diff -Nru nplan-0.32~16.04.4/debian/changelog nplan-0.32~16.04.5/debian/changelog --- nplan-0.32~16.04.4/debian/changelog 2018-03-02 22:02:03.000000000 +0000 +++ nplan-0.32~16.04.5/debian/changelog 2018-05-08 14:36:24.000000000 +0000 @@ -1,3 +1,22 @@ +nplan (0.32~16.04.5) xenial; urgency=medium + + * bond/bridge: Support suffixes for time-based values so things like + "mii-monitor-interval" can support milliseconds. (LP: #1745597) + * Do not attempt to rebind driver 'qeth'. (LP: #1756322) + * Allow setting ClientIdentifier=mac for networkd-renderered devices + (LP: #1738998) + * IPv6: accept-ra should default to being unset, so that the kernel default + can be used. (LP: #1732002) + * doc/netplan.md: Clarify the behavior for time-based values for bonds + and bridges. (LP: #1756587) + * critical: provide a way to set "CriticalConnection=true" on a networkd + connection, especially for remote-fs scenarios. (LP: #1769682) + * networkd: don't wipe out /run/netplan on generate: we do want to keep any + YAML configurations in that directory, we just need to remove generated + wpasupplicant configs. (LP: #1764869) + + -- Mathieu Trudel-Lapierre Tue, 08 May 2018 10:36:24 -0400 + nplan (0.32~16.04.4) xenial; urgency=medium [ Oliver Grawert ] diff -Nru nplan-0.32~16.04.4/doc/netplan.md nplan-0.32~16.04.5/doc/netplan.md --- nplan-0.32~16.04.4/doc/netplan.md 2018-03-02 20:41:47.000000000 +0000 +++ nplan-0.32~16.04.5/doc/netplan.md 2018-05-08 14:33:45.000000000 +0000 @@ -161,10 +161,23 @@ : Enable DHCP for IPv6. Off by default. +``dhcp-identifier`` (scalar) + +: When set to 'mac'; pass that setting over to systemd-networkd to use the + device's MAC address as a unique identifier rather than a RFC4361-compliant + Client ID. This has no effect when NetworkManager is used as a renderer. + +``critical`` (bool) + +: (networkd backend only) Designate the connection as "critical to the + system", meaning that special care will be taken by systemd-networkd to + not release the IP from DHCP when it the daemon is restarted. + ``accept-ra`` (bool) : Accept Router Advertisement that would have the kernel configure IPv6 by itself. - On by default. + When enabled, accept Router Advertisements. When disabled, do not respond to + Router Advertisements. If unset use the host kernel default setting. ``addresses`` (sequence of scalars) @@ -275,14 +288,15 @@ ``parameters`` (mapping) -: Customization parameters for special bridging options. Using the - NetworkManager renderer, parameter values for time intervals should be - expressed in milliseconds; for the systemd renderer, they should be in - seconds unless otherwise specified. +: Customization parameters for special bridging options. Unless otherwise + specified, parameter values for time intervals should be expressed in + milliseconds, but can also be expressed in seconds using a time suffix + (such as "s" for seconds, "ms" for milliseconds). ``ageing-time`` (scalar) - : Set the period of time to keep a MAC address in the forwarding - database after a packet is received. + : Set the period of time (in seconds) to keep a MAC address in the forwarding + database after a packet is received. This maps to the AgeingTimeSec= + property when the networkd renderer is used. ``priority`` (scalar) : Set the priority value for the bridge. This value should be a @@ -296,20 +310,21 @@ designated port and root port selection algorithms. ``forward-delay`` (scalar) - : Specify the period of time the bridge will remain in Listening and - Learning states before getting to the Forwarding state. This value - should be set in seconds for the systemd backend, and in milliseconds - for the NetworkManager backend. + : Specify the period of time (in seconds) the bridge will remain in Listening and + Learning states before getting to the Forwarding state. This field + maps to the ForwardDelaySec= property for the networkd renderer. ``hello-time`` (scalar) - : Specify the interval between two hello packets being sent out from + : Specify the interval (in seconds) between two hello packets being sent out from the root and designated bridges. Hello packets communicate - information about the network topology. + information about the network topology. When the networkd renderer + is used, this maps to the HelloTimeSec= property. ``max-age`` (scalar) - : Set the maximum age of a hello packet. If the last hello packet is + : Set the maximum age (in seconds) of a hello packet. If the last hello packet is older than that value, the bridge will attempt to become the root - bridge. + bridge. This maps to the MaxAgeSec= property when the networkd + renderer is used. ``path-cost`` (scalar) : Set the cost of a path on the bridge. Faster interfaces should have @@ -341,10 +356,10 @@ ``parameters`` (mapping) -: Customization parameters for special bonding options. Using the - NetworkManager renderer, parameter values for intervals should be - expressed in milliseconds; for the systemd renderer, they should be in - seconds unless otherwise specified. +: Customization parameters for special bonding options. Unless otherwise + specified, parameter values for time intervals should be expressed in + milliseconds, but can also be expressed in seconds using a time suffix + (such as "s" for seconds, "ms" for milliseconds). ``mode`` (scalar) : Set the bonding mode used for the interfaces. The default is @@ -360,7 +375,8 @@ ``mii-monitor-interval`` (scalar) : Specifies the interval for MII monitoring (verifying if an interface of the bond has carrier). The default is ``0``; which disables MII - monitoring. + monitoring. This is equivalent to the MIIMonitorSec= field for the + networkd backend. ``min-links`` (scalar) : The minimum number of links up in a bond to consider the bond @@ -386,6 +402,7 @@ ``arp-interval`` (scalar) : Set the interval value for how frequently ARP link monitoring should happen. The default value is ``0``, which disables ARP monitoring. + For the networkd backend, this maps to the ARPIntervalSec= property. ``arp-ip-targets`` (sequence of scalars) : IPs of other hosts on the link which should be sent ARP requests in @@ -408,11 +425,13 @@ ``up-delay`` (scalar) : Specify the delay before enabling a link once the link is physically - up. The default value is ``0``. + up. The default value is ``0``. This maps to the UpDelaySec= property + for the networkd renderer. ``down-delay`` (scalar) : Specify the delay before disabling a link once the link has been - lost. The default value is ``0``. + lost. The default value is ``0``. This maps to the DownDelaySec= + property for the networkd renderer. ``fail-over-mac-policy`` (scalar) : Set whether to set all slaves to the same MAC address when adding @@ -451,10 +470,11 @@ are sent at 200ms intervals. ``learn-packet-interval`` (scalar) - : Specify the interval between sending learning packets to each slave. - The value range is between ``1`` and ``0x7fffffff``. The default - value is ``1``. This option only affects ``balance-tlb`` and - ``balance-alb`` modes. + : Specify the interval (seconds) between sending learning packets to + each slave. The value range is between ``1`` and ``0x7fffffff``. + The default value is ``1``. This option only affects ``balance-tlb`` + and ``balance-alb`` modes. Using the networkd renderer, this field + maps to the LearnPacketIntervalSec= property. ``primary`` (scalar) : Specify a device to be used as a primary slave, or preferred device diff -Nru nplan-0.32~16.04.4/src/netplan nplan-0.32~16.04.5/src/netplan --- nplan-0.32~16.04.4/src/netplan 2018-03-02 20:41:50.000000000 +0000 +++ nplan-0.32~16.04.5/src/netplan 2018-05-08 14:36:19.000000000 +0000 @@ -157,6 +157,11 @@ if 'ath6kl_sdio' in driver_name: logging.debug('replug %s: ath6kl_sdio driver does not support rebinding, ignoring', device) return False + # workaround for qeth: driver does not recognize unbind command + # https://bugs.launchpad.net/ubuntu/+source/netplan.io/+bug/1756322 + if driver_name == 'qeth': + logging.debug('replug %s: qeth driver do not support rebinding, ignoring (LP: #1756322)', device) + return False logging.debug('replug %s: unbinding %s from %s', device, devname, driver) with open(os.path.join(driver, 'unbind'), 'w') as f: f.write(devname) diff -Nru nplan-0.32~16.04.4/src/networkd.c nplan-0.32~16.04.5/src/networkd.c --- nplan-0.32~16.04.4/src/networkd.c 2018-03-02 20:42:55.000000000 +0000 +++ nplan-0.32~16.04.5/src/networkd.c 2018-05-08 14:34:51.000000000 +0000 @@ -65,15 +65,15 @@ params = g_string_sized_new(200); if (def->bridge_params.ageing_time) - g_string_append_printf(params, "AgeingTimeSec=%u\n", def->bridge_params.ageing_time); + g_string_append_printf(params, "AgeingTimeSec=%s\n", def->bridge_params.ageing_time); if (def->bridge_params.priority) g_string_append_printf(params, "Priority=%u\n", def->bridge_params.priority); if (def->bridge_params.forward_delay) - g_string_append_printf(params, "ForwardDelaySec=%u\n", def->bridge_params.forward_delay); + g_string_append_printf(params, "ForwardDelaySec=%s\n", def->bridge_params.forward_delay); if (def->bridge_params.hello_time) - g_string_append_printf(params, "HelloTimeSec=%u\n", def->bridge_params.hello_time); + g_string_append_printf(params, "HelloTimeSec=%s\n", def->bridge_params.hello_time); if (def->bridge_params.max_age) - g_string_append_printf(params, "MaxAgeSec=%u\n", def->bridge_params.max_age); + g_string_append_printf(params, "MaxAgeSec=%s\n", def->bridge_params.max_age); g_string_append_printf(params, "STP=%s\n", def->bridge_params.stp ? "true" : "false"); g_string_append_printf(s, "\n[Bridge]\n%s", params->str); @@ -113,6 +113,19 @@ g_string_free_to_file(s, rootdir, path, ".link"); } + +static gboolean +interval_has_suffix(const char* param) { + gchar* endptr; + + g_ascii_strtoull(param, &endptr, 10); + if (*endptr == '\0') + return FALSE; + + return TRUE; +} + + static void write_bond_parameters(net_definition* def, GString* s) { @@ -124,8 +137,13 @@ g_string_append_printf(params, "\nMode=%s", def->bond_params.mode); if (def->bond_params.lacp_rate) g_string_append_printf(params, "\nLACPTransmitRate=%s", def->bond_params.lacp_rate); - if (def->bond_params.monitor_interval) - g_string_append_printf(params, "\nMIIMonitorSec=%d", def->bond_params.monitor_interval); + if (def->bond_params.monitor_interval) { + g_string_append(params, "\nMIIMonitorSec="); + if (interval_has_suffix(def->bond_params.monitor_interval)) + g_string_append(params, def->bond_params.monitor_interval); + else + g_string_append_printf(params, "%sms", def->bond_params.monitor_interval); + } if (def->bond_params.min_links) g_string_append_printf(params, "\nMinLinks=%d", def->bond_params.min_links); if (def->bond_params.transmit_hash_policy) @@ -134,8 +152,13 @@ g_string_append_printf(params, "\nAdSelect=%s", def->bond_params.selection_logic); if (def->bond_params.all_slaves_active) g_string_append_printf(params, "\nAllSlavesActive=%d", def->bond_params.all_slaves_active); - if (def->bond_params.arp_interval) - g_string_append_printf(params, "\nARPIntervalSec=%d", def->bond_params.arp_interval); + if (def->bond_params.arp_interval) { + g_string_append(params, "\nARPIntervalSec="); + if (interval_has_suffix(def->bond_params.arp_interval)) + g_string_append(params, def->bond_params.arp_interval); + else + g_string_append_printf(params, "%sms", def->bond_params.arp_interval); + } if (def->bond_params.arp_ip_targets && def->bond_params.arp_ip_targets->len > 0) { g_string_append_printf(params, "\nARPIPTargets="); for (unsigned i = 0; i < def->bond_params.arp_ip_targets->len; ++i) { @@ -148,10 +171,20 @@ g_string_append_printf(params, "\nARPValidate=%s", def->bond_params.arp_validate); if (def->bond_params.arp_all_targets) g_string_append_printf(params, "\nARPAllTargets=%s", def->bond_params.arp_all_targets); - if (def->bond_params.up_delay) - g_string_append_printf(params, "\nUpDelaySec=%d", def->bond_params.up_delay); - if (def->bond_params.down_delay) - g_string_append_printf(params, "\nDownDelaySec=%d", def->bond_params.down_delay); + if (def->bond_params.up_delay) { + g_string_append(params, "\nUpDelaySec="); + if (interval_has_suffix(def->bond_params.up_delay)) + g_string_append(params, def->bond_params.up_delay); + else + g_string_append_printf(params, "%sms", def->bond_params.up_delay); + } + if (def->bond_params.down_delay) { + g_string_append(params, "\nDownDelaySec="); + if (interval_has_suffix(def->bond_params.down_delay)) + g_string_append(params, def->bond_params.down_delay); + else + g_string_append_printf(params, "%sms", def->bond_params.down_delay); + } if (def->bond_params.fail_over_mac_policy) g_string_append_printf(params, "\nFailOverMACPolicy=%s", def->bond_params.fail_over_mac_policy); if (def->bond_params.gratuitious_arp) @@ -164,7 +197,7 @@ if (def->bond_params.resend_igmp) g_string_append_printf(params, "\nResendIGMP=%d", def->bond_params.resend_igmp); if (def->bond_params.learn_interval) - g_string_append_printf(params, "\nLearnPacketIntervalSec=%d", def->bond_params.learn_interval); + g_string_append_printf(params, "\nLearnPacketIntervalSec=%s", def->bond_params.learn_interval); if (params->len) g_string_append_printf(s, "\n[Bond]%s\n", params->str); @@ -243,7 +276,9 @@ if (def->ip6_addresses) for (unsigned i = 0; i < def->ip6_addresses->len; ++i) g_string_append_printf(s, "Address=%s\n", g_array_index(def->ip6_addresses, char*, i)); - if (!def->accept_ra) + if (def->accept_ra == ACCEPT_RA_ENABLED) + g_string_append_printf(s, "IPv6AcceptRA=yes\n"); + else if (def->accept_ra == ACCEPT_RA_DISABLED) g_string_append_printf(s, "IPv6AcceptRA=no\n"); if (def->gateway4) g_string_append_printf(s, "Gateway=%s\n", def->gateway4); @@ -262,7 +297,7 @@ g_string_append(s, "\n"); } if (def->bridge) { - g_string_append_printf(s, "Bridge=%s\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n", def->bridge); + g_string_append_printf(s, "Bridge=%s\nLinkLocalAddressing=no\n", def->bridge); if (def->bridge_params.path_cost || def->bridge_params.port_priority) g_string_append_printf(s, "\n[Bridge]\n"); @@ -272,7 +307,7 @@ g_string_append_printf(s, "Priority=%u\n", def->bridge_params.port_priority); } if (def->bond) { - g_string_append_printf(s, "Bond=%s\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n", def->bond); + g_string_append_printf(s, "Bond=%s\nLinkLocalAddressing=no\n", def->bond); if (def->bond_params.primary_slave) g_string_append_printf(s, "PrimarySlave=true\n"); @@ -303,6 +338,10 @@ g_string_append_printf(s, "\n[DHCP]\nUseMTU=true\n"); /* NetworkManager compatible route metrics */ g_string_append_printf(s, "RouteMetric=%i\n", (def->type == ND_WIFI ? 600 : 100)); + if (g_strcmp0(def->dhcp_identifier, "duid") != 0) + g_string_append_printf(s, "ClientIdentifier=%s\n", def->dhcp_identifier); + if (def->critical) + g_string_append_printf(s, "CriticalConnection=true\n"); } g_string_free_to_file(s, rootdir, path, ".network"); @@ -397,7 +436,7 @@ cleanup_networkd_conf(const char* rootdir) { unlink_glob(rootdir, "/run/systemd/network/10-netplan-*"); - unlink_glob(rootdir, "/run/netplan/*"); + unlink_glob(rootdir, "/run/netplan/wpa-*.conf"); unlink_glob(rootdir, "/run/systemd/system/multi-user.target.wants/netplan-wpa@*.service"); } diff -Nru nplan-0.32~16.04.4/src/nm.c nplan-0.32~16.04.5/src/nm.c --- nplan-0.32~16.04.4/src/nm.c 2018-03-02 20:41:47.000000000 +0000 +++ nplan-0.32~16.04.5/src/nm.c 2018-05-08 14:33:45.000000000 +0000 @@ -156,7 +156,7 @@ if (def->bond_params.lacp_rate) g_string_append_printf(params, "\nlacp_rate=%s", def->bond_params.lacp_rate); if (def->bond_params.monitor_interval) - g_string_append_printf(params, "\nmiimon=%d", def->bond_params.monitor_interval); + g_string_append_printf(params, "\nmiimon=%s", def->bond_params.monitor_interval); if (def->bond_params.min_links) g_string_append_printf(params, "\nmin_links=%d", def->bond_params.min_links); if (def->bond_params.transmit_hash_policy) @@ -166,7 +166,7 @@ if (def->bond_params.all_slaves_active) g_string_append_printf(params, "\nall_slaves_active=%d", def->bond_params.all_slaves_active); if (def->bond_params.arp_interval) - g_string_append_printf(params, "\narp_interval=%d", def->bond_params.arp_interval); + g_string_append_printf(params, "\narp_interval=%s", def->bond_params.arp_interval); if (def->bond_params.arp_ip_targets) { g_string_append_printf(params, "\narp_ip_target="); for (unsigned i = 0; i < def->bond_params.arp_ip_targets->len; ++i) { @@ -180,9 +180,9 @@ if (def->bond_params.arp_all_targets) g_string_append_printf(params, "\narp_all_targets=%s", def->bond_params.arp_all_targets); if (def->bond_params.up_delay) - g_string_append_printf(params, "\nupdelay=%d", def->bond_params.up_delay); + g_string_append_printf(params, "\nupdelay=%s", def->bond_params.up_delay); if (def->bond_params.down_delay) - g_string_append_printf(params, "\ndowndelay=%d", def->bond_params.down_delay); + g_string_append_printf(params, "\ndowndelay=%s", def->bond_params.down_delay); if (def->bond_params.fail_over_mac_policy) g_string_append_printf(params, "\nfail_over_mac=%s", def->bond_params.fail_over_mac_policy); if (def->bond_params.gratuitious_arp) @@ -195,7 +195,7 @@ if (def->bond_params.resend_igmp) g_string_append_printf(params, "\nresend_igmp=%d", def->bond_params.resend_igmp); if (def->bond_params.learn_interval) - g_string_append_printf(params, "\nlp_interval=%d", def->bond_params.learn_interval); + g_string_append_printf(params, "\nlp_interval=%s", def->bond_params.learn_interval); if (def->bond_params.primary_slave) g_string_append_printf(params, "\nprimary=%s", def->bond_params.primary_slave); @@ -214,15 +214,15 @@ params = g_string_sized_new(200); if (def->bridge_params.ageing_time) - g_string_append_printf(params, "ageing-time=%u\n", def->bridge_params.ageing_time); + g_string_append_printf(params, "ageing-time=%s\n", def->bridge_params.ageing_time); if (def->bridge_params.priority) g_string_append_printf(params, "priority=%u\n", def->bridge_params.priority); if (def->bridge_params.forward_delay) - g_string_append_printf(params, "forward-delay=%u\n", def->bridge_params.forward_delay); + g_string_append_printf(params, "forward-delay=%s\n", def->bridge_params.forward_delay); if (def->bridge_params.hello_time) - g_string_append_printf(params, "hello-time=%u\n", def->bridge_params.hello_time); + g_string_append_printf(params, "hello-time=%s\n", def->bridge_params.hello_time); if (def->bridge_params.max_age) - g_string_append_printf(params, "max-age=%u\n", def->bridge_params.max_age); + g_string_append_printf(params, "max-age=%s\n", def->bridge_params.max_age); g_string_append_printf(params, "stp=%s\n", def->bridge_params.stp ? "true" : "false"); g_string_append_printf(s, "\n[bridge]\n%s", params->str); diff -Nru nplan-0.32~16.04.4/src/parse.c nplan-0.32~16.04.5/src/parse.c --- nplan-0.32~16.04.4/src/parse.c 2018-03-02 20:41:47.000000000 +0000 +++ nplan-0.32~16.04.5/src/parse.c 2018-05-08 14:33:45.000000000 +0000 @@ -458,6 +458,25 @@ } static gboolean +handle_accept_ra(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) +{ + if (g_ascii_strcasecmp(scalar(node), "true") == 0 || + g_ascii_strcasecmp(scalar(node), "on") == 0 || + g_ascii_strcasecmp(scalar(node), "yes") == 0 || + g_ascii_strcasecmp(scalar(node), "y") == 0) + cur_netdef->accept_ra = ACCEPT_RA_ENABLED; + else if (g_ascii_strcasecmp(scalar(node), "false") == 0 || + g_ascii_strcasecmp(scalar(node), "off") == 0 || + g_ascii_strcasecmp(scalar(node), "no") == 0 || + g_ascii_strcasecmp(scalar(node), "n") == 0) + cur_netdef->accept_ra = ACCEPT_RA_DISABLED; + else + return yaml_error(node, error, "invalid boolean value %s", scalar(node)); + + return TRUE; +} + +static gboolean handle_match(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** error) { cur_netdef->has_match = TRUE; @@ -804,10 +823,10 @@ return TRUE; } const mapping_entry_handler bridge_params_handlers[] = { - {"ageing-time", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bridge_params.ageing_time)}, - {"forward-delay", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bridge_params.forward_delay)}, - {"hello-time", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bridge_params.hello_time)}, - {"max-age", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bridge_params.max_age)}, + {"ageing-time", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bridge_params.ageing_time)}, + {"forward-delay", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bridge_params.forward_delay)}, + {"hello-time", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bridge_params.hello_time)}, + {"max-age", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bridge_params.max_age)}, {"path-cost", YAML_MAPPING_NODE, handle_bridge_path_cost, NULL, netdef_offset(bridge_params.path_cost)}, {"port-priority", YAML_MAPPING_NODE, handle_bridge_port_priority, NULL, netdef_offset(bridge_params.port_priority)}, {"priority", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bridge_params.priority)}, @@ -921,25 +940,25 @@ const mapping_entry_handler bond_params_handlers[] = { {"mode", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.mode)}, {"lacp-rate", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.lacp_rate)}, - {"mii-monitor-interval", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bond_params.monitor_interval)}, + {"mii-monitor-interval", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.monitor_interval)}, {"min-links", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bond_params.min_links)}, {"transmit-hash-policy", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.transmit_hash_policy)}, {"ad-select", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.selection_logic)}, {"all-slaves-active", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(bond_params.all_slaves_active)}, - {"arp-interval", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bond_params.arp_interval)}, + {"arp-interval", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.arp_interval)}, /* TODO: arp_ip_targets */ {"arp-ip-targets", YAML_SEQUENCE_NODE, handle_arp_ip_targets}, {"arp-validate", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.arp_validate)}, {"arp-all-targets", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.arp_all_targets)}, - {"up-delay", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bond_params.up_delay)}, - {"down-delay", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bond_params.down_delay)}, + {"up-delay", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.up_delay)}, + {"down-delay", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.down_delay)}, {"fail-over-mac-policy", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.fail_over_mac_policy)}, {"gratuitious-arp", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bond_params.gratuitious_arp)}, /* TODO: unsolicited_na */ {"packets-per-slave", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bond_params.packets_per_slave)}, {"primary-reselect-policy", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.primary_reselect_policy)}, {"resend-igmp", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bond_params.resend_igmp)}, - {"learn-packet-interval", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bond_params.learn_interval)}, + {"learn-packet-interval", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.learn_interval)}, {"primary", YAML_SCALAR_NODE, handle_bond_primary_slave, NULL, netdef_offset(bond_params.primary_slave)}, {NULL} }; @@ -950,6 +969,20 @@ return process_mapping(doc, node, bond_params_handlers, error); } +static gboolean +handle_dhcp_identifier(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) +{ + if (cur_netdef->dhcp_identifier) + g_free(cur_netdef->dhcp_identifier); + cur_netdef->dhcp_identifier = g_strdup(scalar(node)); + + if (g_ascii_strcasecmp(cur_netdef->dhcp_identifier, "duid") == 0 || + g_ascii_strcasecmp(cur_netdef->dhcp_identifier, "mac") == 0) + return TRUE; + + return yaml_error(node, error, "invalid DHCP client identifier type '%s'", cur_netdef->dhcp_identifier); +} + /**************************************************** * Grammar and handlers for network devices ****************************************************/ @@ -961,10 +994,12 @@ }; const mapping_entry_handler ethernet_def_handlers[] = { + {"accept-ra", YAML_SCALAR_NODE, handle_accept_ra}, {"addresses", YAML_SEQUENCE_NODE, handle_addresses}, + {"critical", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(critical)}, {"dhcp4", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(dhcp4)}, {"dhcp6", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(dhcp6)}, - {"accept-ra", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(accept_ra)}, + {"dhcp-identifier", YAML_SCALAR_NODE, handle_dhcp_identifier}, {"gateway4", YAML_SCALAR_NODE, handle_gateway4}, {"gateway6", YAML_SCALAR_NODE, handle_gateway6}, {"macaddress", YAML_SCALAR_NODE, handle_netdef_mac, NULL, netdef_offset(set_mac)}, @@ -980,11 +1015,13 @@ }; const mapping_entry_handler wifi_def_handlers[] = { + {"accept-ra", YAML_SCALAR_NODE, handle_accept_ra}, {"access-points", YAML_MAPPING_NODE, handle_wifi_access_points}, {"addresses", YAML_SEQUENCE_NODE, handle_addresses}, + {"critical", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(critical)}, {"dhcp4", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(dhcp4)}, {"dhcp6", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(dhcp6)}, - {"accept-ra", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(accept_ra)}, + {"dhcp-identifier", YAML_SCALAR_NODE, handle_dhcp_identifier}, {"gateway4", YAML_SCALAR_NODE, handle_gateway4}, {"gateway6", YAML_SCALAR_NODE, handle_gateway6}, {"macaddress", YAML_SCALAR_NODE, handle_netdef_mac, NULL, netdef_offset(set_mac)}, @@ -1000,10 +1037,12 @@ }; const mapping_entry_handler bridge_def_handlers[] = { + {"accept-ra", YAML_SCALAR_NODE, handle_accept_ra}, {"addresses", YAML_SEQUENCE_NODE, handle_addresses}, + {"critical", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(critical)}, {"dhcp4", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(dhcp4)}, {"dhcp6", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(dhcp6)}, - {"accept-ra", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(accept_ra)}, + {"dhcp-identifier", YAML_SCALAR_NODE, handle_dhcp_identifier}, {"gateway4", YAML_SCALAR_NODE, handle_gateway4}, {"gateway6", YAML_SCALAR_NODE, handle_gateway6}, {"interfaces", YAML_SEQUENCE_NODE, handle_interfaces, NULL, netdef_offset(bridge)}, @@ -1018,10 +1057,12 @@ }; const mapping_entry_handler bond_def_handlers[] = { + {"accept-ra", YAML_SCALAR_NODE, handle_accept_ra}, {"addresses", YAML_SEQUENCE_NODE, handle_addresses}, + {"critical", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(critical)}, {"dhcp4", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(dhcp4)}, {"dhcp6", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(dhcp6)}, - {"accept-ra", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(accept_ra)}, + {"dhcp-identifier", YAML_SCALAR_NODE, handle_dhcp_identifier}, {"gateway4", YAML_SCALAR_NODE, handle_gateway4}, {"gateway6", YAML_SCALAR_NODE, handle_gateway6}, {"interfaces", YAML_SEQUENCE_NODE, handle_interfaces, NULL, netdef_offset(bond)}, @@ -1036,10 +1077,12 @@ }; const mapping_entry_handler vlan_def_handlers[] = { + {"accept-ra", YAML_SCALAR_NODE, handle_accept_ra}, {"addresses", YAML_SEQUENCE_NODE, handle_addresses}, + {"critical", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(critical)}, {"dhcp4", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(dhcp4)}, {"dhcp6", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(dhcp6)}, - {"accept-ra", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(accept_ra)}, + {"dhcp-identifier", YAML_SCALAR_NODE, handle_dhcp_identifier}, {"gateway4", YAML_SCALAR_NODE, handle_gateway4}, {"gateway6", YAML_SCALAR_NODE, handle_gateway6}, {"id", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(vlan_id)}, @@ -1150,7 +1193,7 @@ cur_netdef->backend = backend_cur_type ?: BACKEND_NONE; cur_netdef->id = g_strdup(scalar(key)); cur_netdef->vlan_id = G_MAXUINT; /* 0 is a valid ID */ - cur_netdef->accept_ra = TRUE; /* By default, accept RAs */ + cur_netdef->dhcp_identifier = g_strdup("duid"); /* keep networkd's default */ g_hash_table_insert(netdefs, cur_netdef->id, cur_netdef); } diff -Nru nplan-0.32~16.04.4/src/parse.h nplan-0.32~16.04.5/src/parse.h --- nplan-0.32~16.04.4/src/parse.h 2018-03-02 20:41:47.000000000 +0000 +++ nplan-0.32~16.04.5/src/parse.h 2018-05-08 14:33:45.000000000 +0000 @@ -42,6 +42,12 @@ BACKEND_NM, } netdef_backend; +typedef enum { + ACCEPT_RA_KERNEL, + ACCEPT_RA_ENABLED, + ACCEPT_RA_DISABLED, +} ra_mode; + typedef struct missing_node { char* netdef_id; yaml_node_t* node; @@ -59,11 +65,13 @@ /* status options */ gboolean optional; + gboolean critical; /* addresses */ gboolean dhcp4; gboolean dhcp6; - gboolean accept_ra; + char* dhcp_identifier; + ra_mode accept_ra; GArray* ip4_addresses; GArray* ip6_addresses; char* gateway4; @@ -104,34 +112,34 @@ struct { char* mode; char* lacp_rate; - guint monitor_interval; + char* monitor_interval; guint min_links; char* transmit_hash_policy; char* selection_logic; gboolean all_slaves_active; - guint arp_interval; + char* arp_interval; GArray* arp_ip_targets; char* arp_validate; char* arp_all_targets; - guint up_delay; - guint down_delay; + char* up_delay; + char* down_delay; char* fail_over_mac_policy; guint gratuitious_arp; /* TODO: unsolicited_na */ guint packets_per_slave; char* primary_reselect_policy; guint resend_igmp; - guint learn_interval; + char* learn_interval; char* primary_slave; } bond_params; struct { - guint ageing_time; + char* ageing_time; guint priority; guint port_priority; - guint forward_delay; - guint hello_time; - guint max_age; + char* forward_delay; + char* hello_time; + char* max_age; guint path_cost; gboolean stp; } bridge_params; diff -Nru nplan-0.32~16.04.4/tests/generate.py nplan-0.32~16.04.5/tests/generate.py --- nplan-0.32~16.04.4/tests/generate.py 2018-03-02 20:45:41.000000000 +0000 +++ nplan-0.32~16.04.5/tests/generate.py 2018-05-08 14:33:45.000000000 +0000 @@ -345,7 +345,7 @@ 'bond0.netdev': '[NetDev]\nName=bond0\nMTUBytes=9000\nKind=bond\n', 'bond0.network': '[Match]\nName=bond0\n\n[Network]\nVLAN=bond0.108\n', 'eth1.link': '[Match]\nOriginalName=eth1\n\n[Link]\nWakeOnLan=off\nMTUBytes=1280\n', - 'eth1.network': '[Match]\nName=eth1\n\n[Network]\nBond=bond0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n' + 'eth1.network': '[Match]\nName=eth1\n\n[Network]\nBond=bond0\nLinkLocalAddressing=no\n' }) def test_eth_match_by_driver_rename(self): @@ -579,7 +579,7 @@ ethernets: eth0: dhcp6: true - accept-ra: no''') + accept-ra: n''') self.assert_networkd({'eth0.network': '''[Match] Name=eth0 @@ -592,6 +592,115 @@ RouteMetric=100 '''}) + def test_bridge_dhcp6_no_accept_ra(self): + self.generate('''network: + version: 2 + ethernets: + engreen: + dhcp4: no + dhcp6: no + accept-ra: no + bridges: + br0: + interfaces: [engreen] + dhcp6: true + accept-ra: no''') + self.assert_networkd({'br0.network': '''[Match] +Name=br0 + +[Network] +DHCP=ipv6 +IPv6AcceptRA=no + +[DHCP] +UseMTU=true +RouteMetric=100 +''', + 'br0.netdev': '''[NetDev] +Name=br0 +Kind=bridge +''', + 'engreen.network': '''[Match] +Name=engreen + +[Network] +IPv6AcceptRA=no +Bridge=br0 +LinkLocalAddressing=no +'''}) + + def test_bond_dhcp6_no_accept_ra(self): + self.generate('''network: + version: 2 + ethernets: + engreen: + dhcp6: no + accept-ra: no + bonds: + bond0: + interfaces: [engreen] + dhcp6: true + accept-ra: yes''') + self.assert_networkd({'bond0.network': '''[Match] +Name=bond0 + +[Network] +DHCP=ipv6 +IPv6AcceptRA=yes + +[DHCP] +UseMTU=true +RouteMetric=100 +''', + 'bond0.netdev': '''[NetDev] +Name=bond0 +Kind=bond +''', + 'engreen.network': '''[Match] +Name=engreen + +[Network] +IPv6AcceptRA=no +Bond=bond0 +LinkLocalAddressing=no +'''}) + + def test_eth_dhcp6_accept_ra(self): + self.generate('''network: + version: 2 + ethernets: + eth0: + dhcp6: true + accept-ra: yes''') + self.assert_networkd({'eth0.network': '''[Match] +Name=eth0 + +[Network] +DHCP=ipv6 +IPv6AcceptRA=yes + +[DHCP] +UseMTU=true +RouteMetric=100 +'''}) + + def test_eth_dhcp6_accept_ra_unset(self): + self.generate('''network: + version: 2 + ethernets: + eth0: + dhcp6: true''') + self.assert_networkd({'eth0.network': '''[Match] +Name=eth0 + +[Network] +DHCP=ipv6 + +[DHCP] +UseMTU=true +RouteMetric=100 +'''}) + def test_eth_dhcp4_and_6(self): self.generate('''network: version: 2 @@ -639,6 +748,69 @@ RouteMetric=100 '''}) + def test_dhcp_critical_true(self): + self.generate('''network: + version: 2 + ethernets: + engreen: + dhcp4: yes + critical: yes +''') + + self.assert_networkd({'engreen.network': '''[Match] +Name=engreen + +[Network] +DHCP=ipv4 + +[DHCP] +UseMTU=true +RouteMetric=100 +CriticalConnection=true +'''}) + + def test_dhcp_identifier_mac(self): + self.generate('''network: + version: 2 + ethernets: + engreen: + dhcp4: yes + dhcp-identifier: mac +''') + + self.assert_networkd({'engreen.network': '''[Match] +Name=engreen + +[Network] +DHCP=ipv4 + +[DHCP] +UseMTU=true +RouteMetric=100 +ClientIdentifier=mac +'''}) + + def test_dhcp_identifier_duid(self): + # This option should be silently ignored, since it's the default + self.generate('''network: + version: 2 + ethernets: + engreen: + dhcp4: yes + dhcp-identifier: duid +''') + + self.assert_networkd({'engreen.network': '''[Match] +Name=engreen + +[Network] +DHCP=ipv4 + +[DHCP] +UseMTU=true +RouteMetric=100 +'''}) + def test_route_v4_single(self): self.generate('''network: version: 2 @@ -926,9 +1098,9 @@ self.assert_networkd({'br0.netdev': '[NetDev]\nName=br0\nKind=bridge\n', 'br0.network': ND_DHCP4 % 'br0', 'eno1.network': '[Match]\nName=eno1\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n', + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n', 'switchports.network': '[Match]\nDriver=yayroute\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n'}) def test_eth_bridge_nm_blacklist(self): self.generate('''network: @@ -962,9 +1134,9 @@ self.assert_networkd({'br0.netdev': '[NetDev]\nName=br0\nKind=bridge\n', 'br0.network': ND_DHCP4 % 'br0', 'eno1.network': '[Match]\nName=eno1\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n', + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n', 'switchports.network': '[Match]\nDriver=yayroute\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n'}) def test_bridge_params(self): self.generate('''network: @@ -997,10 +1169,10 @@ 'STP=true\n', 'br0.network': ND_DHCP4 % 'br0', 'eno1.network': '[Match]\nName=eno1\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n\n' + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n\n' '[Bridge]\nCost=70\nPriority=14\n', 'switchports.network': '[Match]\nDriver=yayroute\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n'}) def test_bond_empty(self): self.generate('''network: @@ -1032,9 +1204,9 @@ self.assert_networkd({'bn0.netdev': '[NetDev]\nName=bn0\nKind=bond\n', 'bn0.network': ND_DHCP4 % 'bn0', 'eno1.network': '[Match]\nName=eno1\n\n' - '[Network]\nBond=bn0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n', + '[Network]\nBond=bn0\nLinkLocalAddressing=no\n', 'switchports.network': '[Match]\nDriver=yayroute\n\n' - '[Network]\nBond=bn0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) + '[Network]\nBond=bn0\nLinkLocalAddressing=no\n'}) def test_bond_empty_parameters(self): self.generate('''network: @@ -1053,9 +1225,9 @@ self.assert_networkd({'bn0.netdev': '[NetDev]\nName=bn0\nKind=bond\n', 'bn0.network': ND_DHCP4 % 'bn0', 'eno1.network': '[Match]\nName=eno1\n\n' - '[Network]\nBond=bn0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n', + '[Network]\nBond=bn0\nLinkLocalAddressing=no\n', 'switchports.network': '[Match]\nDriver=yayroute\n\n' - '[Network]\nBond=bn0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) + '[Network]\nBond=bn0\nLinkLocalAddressing=no\n'}) def test_bond_with_parameters(self): self.generate('''network: @@ -1072,12 +1244,12 @@ lacp-rate: 10 mii-monitor-interval: 10 min-links: 10 - up-delay: 10 - down-delay: 10 + up-delay: 20 + down-delay: 30 all-slaves-active: true transmit-hash-policy: none ad-select: none - arp-interval: 10 + arp-interval: 15 arp-validate: all arp-all-targets: all fail-over-mac-policy: none @@ -1096,17 +1268,17 @@ '[Bond]\n' 'Mode=802.1ad\n' 'LACPTransmitRate=10\n' - 'MIIMonitorSec=10\n' + 'MIIMonitorSec=10ms\n' 'MinLinks=10\n' 'TransmitHashPolicy=none\n' 'AdSelect=none\n' 'AllSlavesActive=1\n' - 'ARPIntervalSec=10\n' + 'ARPIntervalSec=15ms\n' 'ARPIPTargets=10.10.10.10,20.20.20.20\n' 'ARPValidate=all\n' 'ARPAllTargets=all\n' - 'UpDelaySec=10\n' - 'DownDelaySec=10\n' + 'UpDelaySec=20ms\n' + 'DownDelaySec=30ms\n' 'FailOverMACPolicy=none\n' 'GratuitiousARP=10\n' 'PacketsPerSlave=10\n' @@ -1115,9 +1287,41 @@ 'LearnPacketIntervalSec=10\n', 'bn0.network': ND_DHCP4 % 'bn0', 'eno1.network': '[Match]\nName=eno1\n\n' - '[Network]\nBond=bn0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n', + '[Network]\nBond=bn0\nLinkLocalAddressing=no\n', + 'switchports.network': '[Match]\nDriver=yayroute\n\n' + '[Network]\nBond=bn0\nLinkLocalAddressing=no\n'}) + + def test_bond_with_parameters_all_suffix(self): + self.generate('''network: + version: 2 + ethernets: + eno1: {} + switchports: + match: + driver: yayroute + bonds: + bn0: + parameters: + mode: 802.1ad + mii-monitor-interval: 10ms + up-delay: 20ms + down-delay: 30s + arp-interval: 15m + interfaces: [eno1, switchports] + dhcp4: true''') + + self.assert_networkd({'bn0.netdev': '[NetDev]\nName=bn0\nKind=bond\n\n' + '[Bond]\n' + 'Mode=802.1ad\n' + 'MIIMonitorSec=10ms\n' + 'ARPIntervalSec=15m\n' + 'UpDelaySec=20ms\n' + 'DownDelaySec=30s\n', + 'bn0.network': ND_DHCP4 % 'bn0', + 'eno1.network': '[Match]\nName=eno1\n\n' + '[Network]\nBond=bn0\nLinkLocalAddressing=no\n', 'switchports.network': '[Match]\nDriver=yayroute\n\n' - '[Network]\nBond=bn0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) + '[Network]\nBond=bn0\nLinkLocalAddressing=no\n'}) def test_bond_primary_slave(self): self.generate('''network: @@ -1140,9 +1344,9 @@ 'Mode=active-backup\n', 'bn0.network': ND_DHCP4 % 'bn0', 'eno1.network': '[Match]\nName=eno1\n\n' - '[Network]\nBond=bn0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\nPrimarySlave=true\n', + '[Network]\nBond=bn0\nLinkLocalAddressing=no\nPrimarySlave=true\n', 'switchports.network': '[Match]\nDriver=yayroute\n\n' - '[Network]\nBond=bn0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) + '[Network]\nBond=bn0\nLinkLocalAddressing=no\n'}) def test_gateway(self): self.generate('''network: @@ -3559,6 +3763,22 @@ primary: eno2 dhcp4: true''', expect_fail=True) + def test_invalid_dhcp_identifier(self): + self.generate('''network: + version: 2 + ethernets: + engreen: + dhcp4: yes + dhcp-identifier: invalid''', expect_fail=True) + + def test_invalid_accept_ra(self): + err = self.generate('''network: + version: 2 + bridges: + br0: + accept-ra: j''', expect_fail=True) + self.assertIn('invalid boolean', err) + class TestForwardDeclaration(TestBase): @@ -3587,15 +3807,15 @@ 'br0.network': ND_DHCP4 % 'br0', 'bond0.netdev': '[NetDev]\nName=bond0\nKind=bond\n', 'bond0.network': '[Match]\nName=bond0\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n', + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n', 'eth0.link': '[Match]\nMACAddress=00:01:02:03:04:05\n\n' '[Link]\nName=eth0\nWakeOnLan=off\n', 'eth0.network': '[Match]\nMACAddress=00:01:02:03:04:05\nName=eth0\n\n' - '[Network]\nBond=bond0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n', + '[Network]\nBond=bond0\nLinkLocalAddressing=no\n', 'eth1.link': '[Match]\nMACAddress=02:01:02:03:04:05\n\n' '[Link]\nName=eth1\nWakeOnLan=off\n', 'eth1.network': '[Match]\nMACAddress=02:01:02:03:04:05\nName=eth1\n\n' - '[Network]\nBond=bond0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) + '[Network]\nBond=bond0\nLinkLocalAddressing=no\n'}) def test_fwdecl_feature_blend(self): self.generate('''network: @@ -3642,22 +3862,22 @@ '[Network]\nVLAN=vlan1\n', 'bond0.netdev': '[NetDev]\nName=bond0\nKind=bond\n', 'bond0.network': '[Match]\nName=bond0\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n\n' + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n\n' '[Bridge]\nCost=8888\n', 'eth2.network': '[Match]\nName=eth2\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n\n' + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n\n' '[Bridge]\nCost=1000\n', 'br1.netdev': '[NetDev]\nName=br1\nKind=bridge\n', 'br1.network': '[Match]\nName=br1\n\n' - '[Network]\nBond=bond0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n', + '[Network]\nBond=bond0\nLinkLocalAddressing=no\n', 'eth0.link': '[Match]\nMACAddress=00:01:02:03:04:05\n\n' '[Link]\nName=eth0\nWakeOnLan=off\n', 'eth0.network': '[Match]\nMACAddress=00:01:02:03:04:05\nName=eth0\n\n' - '[Network]\nBond=bond0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n', + '[Network]\nBond=bond0\nLinkLocalAddressing=no\n', 'eth1.link': '[Match]\nMACAddress=02:01:02:03:04:05\n\n' '[Link]\nName=eth1\nWakeOnLan=off\n', 'eth1.network': '[Match]\nMACAddress=02:01:02:03:04:05\nName=eth1\n\n' - '[Network]\nBridge=br1\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) + '[Network]\nBridge=br1\nLinkLocalAddressing=no\n'}) class TestMerging(TestBase): @@ -3755,9 +3975,9 @@ self.assert_networkd({'br0.netdev': '[NetDev]\nName=br0\nKind=bridge\n', 'br0.network': ND_DHCP4 % 'br0', 'eno1.network': '[Match]\nName=eno1\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n', + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n', 'switchports.network': '[Match]\nDriver=yayroute\n\n' - '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) + '[Network]\nBridge=br0\nLinkLocalAddressing=no\n'}) def test_def_in_run(self): rundir = os.path.join(self.workdir.name, 'run', 'netplan') diff -Nru nplan-0.32~16.04.4/tests/integration.py nplan-0.32~16.04.5/tests/integration.py --- nplan-0.32~16.04.4/tests/integration.py 2018-03-02 21:16:52.000000000 +0000 +++ nplan-0.32~16.04.5/tests/integration.py 2018-05-08 14:36:19.000000000 +0000 @@ -374,8 +374,10 @@ ethernets: %(ec)s: dhcp4: yes + accept-ra: no ethbr: match: {name: %(e2c)s} + accept-ra: no bridges: mybr: interfaces: [ethbr] @@ -455,6 +457,7 @@ ethernets: ethbr: match: {name: %(e2c)s} + accept-ra: no bridges: mybr: interfaces: [ethbr] @@ -488,6 +491,7 @@ ethernets: ethbr: match: {name: %(e2c)s} + accept-ra: no bridges: mybr: interfaces: [ethbr] @@ -520,6 +524,7 @@ ethernets: ethbr: match: {name: %(e2c)s} + accept-ra: no bridges: mybr: interfaces: [ethbr] @@ -552,6 +557,7 @@ ethernets: ethbr: match: {name: %(e2c)s} + accept-ra: no bridges: mybr: interfaces: [ethbr] @@ -584,6 +590,7 @@ ethernets: ethbr: match: {name: %(e2c)s} + accept-ra: no bridges: mybr: interfaces: [ethbr] @@ -616,6 +623,7 @@ ethernets: ethbr: match: {name: %(e2c)s} + accept-ra: no bridges: mybr: interfaces: [ethbr] @@ -648,6 +656,7 @@ ethernets: ethbr: match: {name: %(e2c)s} + accept-ra: no bridges: mybr: interfaces: [ethbr] @@ -681,6 +690,7 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: @@ -702,8 +712,10 @@ f.write('''network: renderer: %(r)s ethernets: - %(ec)s: {} - %(e2c)s: {} + %(ec)s: + accept-ra: no + %(e2c)s: + accept-ra: no bonds: mybond: interfaces: [%(ec)s, %(e2c)s] @@ -733,7 +745,9 @@ ethernets: ethbn: match: {name: %(ec)s} - %(e2c)s: {} + accept-ra: no + %(e2c)s: + accept-ra: no bonds: mybond: interfaces: [ethbn] @@ -760,7 +774,9 @@ ethernets: ethbn: match: {name: %(ec)s} - %(e2c)s: {} + accept-ra: no + %(e2c)s: + accept-ra: no bonds: mybond: parameters: @@ -787,7 +803,9 @@ ethernets: ethbn: match: {name: %(ec)s} - %(e2c)s: {} + accept-ra: no + %(e2c)s: + accept-ra: no bonds: mybond: parameters: @@ -815,6 +833,7 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: @@ -843,6 +862,7 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: @@ -873,6 +893,7 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: @@ -900,6 +921,7 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: @@ -927,6 +949,7 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: @@ -957,8 +980,10 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no ethb2: match: {name: %(e2c)s} + accept-ra: no bonds: mybond: interfaces: [ethbn, ethb2] @@ -1281,13 +1306,16 @@ bonds: bond0: interfaces: [ethbn, ethb2] + accept-ra: no parameters: mode: balance-rr ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no ethb2: match: {name: %(e2c)s} + accept-ra: no ''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client}) self.generate_and_settle() self.assert_iface_up(self.dev_e_client, @@ -1323,6 +1351,7 @@ bridges: br0: interfaces: ['bond0', 'vlan2'] + accept-ra: no parameters: stp: false path-cost: @@ -1331,20 +1360,25 @@ bonds: bond0: interfaces: ['br1'] + accept-ra: no parameters: mode: balance-rr bridges: br1: interfaces: ['ethb2'] + accept-ra: no vlans: vlan2: link: ethbn id: 2 + accept-ra: no ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no ethb2: match: {name: %(e2c)s} + accept-ra: no ''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client}) self.generate_and_settle() self.assert_iface_up('vlan1', ['vlan1@br0']) @@ -1360,6 +1394,7 @@ class TestNetworkd(NetworkTestBase, _CommonTests): backend = 'networkd' + @unittest.skip("networkd in xenial will block waiting for SLAAC") def test_eth_dhcp6_off(self): self.setup_eth('slaac') with open(self.config, 'w') as f: @@ -1400,6 +1435,7 @@ match: name: %(ec)s macaddress: %(ec_mac)s + accept-ra: no bonds: mybond: interfaces: [ethbn] @@ -1426,6 +1462,7 @@ match: name: %(ec)s macaddress: %(ec_mac)s + accept-ra: no bridges: br0: interfaces: [ethbr] @@ -1449,14 +1486,17 @@ ethernets: ethbn: match: {name: %(ec)s} - %(e2c)s: {} + accept-ra: no + %(e2c)s: + accept-ra: no bonds: mybond: interfaces: [ethbn] parameters: mode: active-backup - mii-monitor-interval: 5 - down-delay: 10 + mii-monitor-interval: 5s + down-delay: 10s + accept-ra: no dhcp4: yes''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client}) self.generate_and_settle() self.assert_iface_up(self.dev_e_client, @@ -1478,14 +1518,16 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: interfaces: [ethbn] parameters: mode: active-backup - mii-monitor-interval: 5 - up-delay: 10 + mii-monitor-interval: 50ms + up-delay: 50ms + accept-ra: no dhcp4: yes''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client}) self.generate_and_settle() self.assert_iface_up(self.dev_e_client, @@ -1496,7 +1538,7 @@ with open('/sys/class/net/mybond/bonding/slaves') as f: self.assertEqual(f.read().strip(), self.dev_e_client) with open('/sys/class/net/mybond/bonding/updelay') as f: - self.assertEqual(f.read().strip(), '10000') + self.assertEqual(f.read().strip(), '50') def test_bond_arp_interval(self): self.setup_eth(None) @@ -1508,6 +1550,7 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: @@ -1515,7 +1558,7 @@ parameters: mode: balance-xor arp-ip-targets: [ 192.168.5.1 ] - arp-interval: 50 + arp-interval: 50s dhcp4: yes''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client}) self.generate_and_settle() self.assert_iface_up(self.dev_e_client, @@ -1538,13 +1581,14 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: interfaces: [ethbn] parameters: mode: balance-xor - arp-interval: 50 + arp-interval: 50s arp-ip-targets: [ 192.168.5.1 ] dhcp4: yes''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client}) self.generate_and_settle() @@ -1568,6 +1612,7 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: @@ -1575,7 +1620,7 @@ parameters: mode: balance-xor arp-ip-targets: [192.168.5.1] - arp-interval: 50 + arp-interval: 50s arp-all-targets: all arp-validate: all dhcp4: yes''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client}) @@ -1600,6 +1645,7 @@ ethernets: ethbn: match: {name: %(ec)s} + accept-ra: no %(e2c)s: {} bonds: mybond: @@ -1607,7 +1653,7 @@ parameters: mode: balance-xor arp-ip-targets: [192.168.5.1] - arp-interval: 50 + arp-interval: 50s arp-validate: all dhcp4: yes''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client}) self.generate_and_settle() @@ -1655,6 +1701,7 @@ ethernets: ethbr: match: {name: %(e2c)s} + accept-ra: no bridges: mybr: interfaces: [ethbr] @@ -1763,7 +1810,7 @@ interfaces: [ethbn] parameters: mode: active-backup - mii-monitor-interval: 5 + mii-monitor-interval: 5000 down-delay: 10000 dhcp4: yes''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client}) self.generate_and_settle() @@ -1792,7 +1839,7 @@ interfaces: [ethbn] parameters: mode: active-backup - mii-monitor-interval: 5 + mii-monitor-interval: 5000 up-delay: 10000 dhcp4: yes''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client}) self.generate_and_settle() @@ -1913,7 +1960,7 @@ mybond: parameters: mode: balance-tlb - mii-monitor-interval: 5 + mii-monitor-interval: 5000 learn-packet-interval: 15 interfaces: [ethbn] dhcp4: yes''' % {'r': self.backend, 'ec': self.dev_e_client, 'e2c': self.dev_e2_client})