diff options
| author | Michael Biebl <biebl@debian.org> | 2020-08-19 10:13:49 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2020-08-19 10:13:49 +0200 |
| commit | e7b44ef4c80907346ec7492a09c45277459924fc (patch) | |
| tree | b1388af193ca205f73336eca47e81815e43a61ca /src | |
| parent | 136d191f1c96dbae1489fed7c2565f5e1b1f8d40 (diff) | |
New upstream version 1.26.2 upstream/1.26.2
Diffstat (limited to 'src')
35 files changed, 850 insertions, 408 deletions
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 2fedc753..71332ba3 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -8,6 +8,7 @@ #include "nm-device-bond.h" #include <stdlib.h> +#include <net/if.h> #include "NetworkManagerUtils.h" #include "nm-device-private.h" @@ -182,7 +183,6 @@ master_update_slave_connection (NMDevice *self, static void set_arp_targets (NMDevice *device, - NMBondMode mode, const char *cur_arp_ip_target, const char *new_arp_ip_target) { @@ -261,15 +261,73 @@ set_bond_attr_or_default (NMDevice *device, _set_bond_attr (device, opt, value); } +static void +set_bond_attr_active_slave (NMDevice *device, NMSettingBond *s_bond) +{ + NMDeviceBond *self = NM_DEVICE_BOND (device); + const NMPlatformLink *plink; + const char *value; + const char *error_reason; + int ifindex; + + value = nm_setting_bond_get_option_or_default (s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE); + if (!value) + return; + + if (!nm_str_is_empty (value)) { + ifindex = nm_device_get_ifindex (device); + plink = nm_platform_link_get_by_ifname (nm_device_get_platform (device), value); + if (!plink) + error_reason = "does not exist"; + else if (plink->master != ifindex) + error_reason = "is not yet enslaved"; + else if (!NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP)) + error_reason = "is not up"; + else + error_reason = NULL; + + if (error_reason) { + _LOGT (LOGD_BOND, "bond option 'active_slave' not set as device \"%s\" %s", value, error_reason); + return; + } + } + + _set_bond_attr (device, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, value); +} + +static void +set_bond_attrs_or_default (NMDevice *device, NMSettingBond *s_bond, const char *const *attr_v) +{ + nm_assert (NM_IS_DEVICE (device)); + nm_assert (s_bond); + nm_assert (attr_v); + + for ( ; *attr_v ; ++attr_v) + set_bond_attr_or_default (device, s_bond, *attr_v); +} + +static void +set_bond_arp_ip_targets (NMDevice *device, NMSettingBond *s_bond) +{ + int ifindex = nm_device_get_ifindex (device); + gs_free char *cur_arp_ip_target = NULL; + + /* ARP targets: clear and initialize the list */ + cur_arp_ip_target = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), + ifindex, + NM_SETTING_BOND_OPTION_ARP_IP_TARGET); + set_arp_targets (device, + cur_arp_ip_target, + nm_setting_bond_get_option_or_default (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)); +} + static gboolean apply_bonding_config (NMDeviceBond *self) { NMDevice *device = NM_DEVICE (self); - int ifindex = nm_device_get_ifindex (device); NMSettingBond *s_bond; NMBondMode mode; const char *mode_str; - gs_free char *cur_arp_ip_target = NULL; s_bond = nm_device_get_applied_setting (device, NM_TYPE_SETTING_BOND); g_return_val_if_fail (s_bond, FALSE); @@ -283,40 +341,34 @@ apply_bonding_config (NMDeviceBond *self) */ set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_MODE); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_MIIMON); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_UPDELAY); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ARP_VALIDATE); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_PRIMARY); - - /* ARP targets: clear and initialize the list */ - cur_arp_ip_target = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), - ifindex, - NM_SETTING_BOND_OPTION_ARP_IP_TARGET); - set_arp_targets (device, - mode, - cur_arp_ip_target, - nm_setting_bond_get_option_or_default (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)); - - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_AD_SELECT); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_FAIL_OVER_MAC); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_LACP_RATE); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_MIN_LINKS); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY); - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP); + set_bond_arp_ip_targets (device, s_bond); + set_bond_attr_active_slave (device, s_bond); + + set_bond_attrs_or_default (device, + s_bond, + NM_MAKE_STRV (NM_SETTING_BOND_OPTION_MIIMON, + NM_SETTING_BOND_OPTION_UPDELAY, + NM_SETTING_BOND_OPTION_DOWNDELAY, + NM_SETTING_BOND_OPTION_ARP_INTERVAL, + NM_SETTING_BOND_OPTION_ARP_VALIDATE, + NM_SETTING_BOND_OPTION_PRIMARY, + NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM, + NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, + NM_SETTING_BOND_OPTION_AD_SELECT, + NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY, + NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE, + NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS, + NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, + NM_SETTING_BOND_OPTION_LACP_RATE, + NM_SETTING_BOND_OPTION_LP_INTERVAL, + NM_SETTING_BOND_OPTION_MIN_LINKS, + NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, + NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, + NM_SETTING_BOND_OPTION_RESEND_IGMP, + NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, + NM_SETTING_BOND_OPTION_USE_CARRIER, + NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, + NM_SETTING_BOND_OPTION_NUM_GRAT_ARP)); return TRUE; } @@ -378,7 +430,7 @@ enslave_slave (NMDevice *device, if (nm_streq0 (active, nm_device_get_iface (slave))) { nm_platform_sysctl_master_set_option (nm_device_get_platform (device), nm_device_get_ifindex (device), - "active_slave", + NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, active); _LOGD (LOGD_BOND, "setting slave %s as active one for master %s", active, nm_device_get_iface (device)); @@ -481,31 +533,41 @@ create_and_realize (NMDevice *device, static gboolean check_changed_options (NMSettingBond *s_a, NMSettingBond *s_b, GError **error) { - guint i, num; - const char *name = NULL, *value_a = NULL, *value_b = NULL; + const char **option_list; - /* Check that options in @s_a have compatible changes in @s_b */ + option_list = nm_setting_bond_get_valid_options (NULL); - num = nm_setting_bond_get_num_options (s_a); - for (i = 0; i < num; i++) { - nm_setting_bond_get_option (s_a, i, &name, &value_a); + for (; *option_list; ++option_list) { + const char *name = *option_list; /* We support changes to these */ if (NM_IN_STRSET (name, - NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, - NM_SETTING_BOND_OPTION_PRIMARY)) { - continue; - } - - /* Missing in @s_b, but has a default value in @s_a */ - value_b = nm_setting_bond_get_option_by_name (s_b, name); - if ( !value_b - && nm_streq0 (value_a, nm_setting_bond_get_option_default (s_a, name))) { + NM_SETTING_BOND_OPTION_PRIMARY, + NM_SETTING_BOND_OPTION_MIIMON, + NM_SETTING_BOND_OPTION_UPDELAY, + NM_SETTING_BOND_OPTION_DOWNDELAY, + NM_SETTING_BOND_OPTION_ARP_INTERVAL, + NM_SETTING_BOND_OPTION_ARP_VALIDATE, + NM_SETTING_BOND_OPTION_PRIMARY, + NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM, + NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, + NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE, + NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS, + NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, + NM_SETTING_BOND_OPTION_LP_INTERVAL, + NM_SETTING_BOND_OPTION_MIN_LINKS, + NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, + NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, + NM_SETTING_BOND_OPTION_RESEND_IGMP, + NM_SETTING_BOND_OPTION_USE_CARRIER, + NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, + NM_SETTING_BOND_OPTION_NUM_GRAT_ARP)) { continue; } /* Reject any other changes */ - if (!nm_streq0 (value_a, value_b)) { + if (!nm_streq0 (nm_setting_bond_get_option_normalized (s_a, name), + nm_setting_bond_get_option_normalized (s_b, name))) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, @@ -527,7 +589,6 @@ can_reapply_change (NMDevice *device, GError **error) { NMDeviceClass *device_class; - NMSettingBond *s_bond_old, *s_bond_new; /* Only handle bond setting here, delegate other settings to parent class */ if (nm_streq (setting_name, NM_SETTING_BOND_SETTING_NAME)) { @@ -537,15 +598,7 @@ can_reapply_change (NMDevice *device, NM_SETTING_BOND_OPTIONS)) return FALSE; - s_bond_old = NM_SETTING_BOND (s_old); - s_bond_new = NM_SETTING_BOND (s_new); - - if ( !check_changed_options (s_bond_old, s_bond_new, error) - || !check_changed_options (s_bond_new, s_bond_old, error)) { - return FALSE; - } - - return TRUE; + return check_changed_options (NM_SETTING_BOND (s_old), NM_SETTING_BOND (s_new), error); } device_class = NM_DEVICE_CLASS (nm_device_bond_parent_class); @@ -561,8 +614,8 @@ static void reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_new) { NMDeviceBond *self = NM_DEVICE_BOND (device); - const char *value; NMSettingBond *s_bond; + const char *value; NMBondMode mode; NM_DEVICE_CLASS (nm_device_bond_parent_class)->reapply_connection (device, @@ -577,10 +630,34 @@ reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_n mode = _nm_setting_bond_mode_from_string (value); g_return_if_fail (mode != NM_BOND_MODE_UNKNOWN); - /* Primary */ - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_PRIMARY); - /* Active slave */ - set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE); + /* Below we set only the bond options that kernel allows to modify + * while keeping the bond interface up */ + + set_bond_attr_active_slave (device, s_bond); + set_bond_arp_ip_targets (device, s_bond); + + set_bond_attrs_or_default (device, + s_bond, + NM_MAKE_STRV (NM_SETTING_BOND_OPTION_PRIMARY, + NM_SETTING_BOND_OPTION_MIIMON, + NM_SETTING_BOND_OPTION_UPDELAY, + NM_SETTING_BOND_OPTION_DOWNDELAY, + NM_SETTING_BOND_OPTION_ARP_INTERVAL, + NM_SETTING_BOND_OPTION_ARP_VALIDATE, + NM_SETTING_BOND_OPTION_PRIMARY, + NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM, + NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, + NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE, + NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS, + NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, + NM_SETTING_BOND_OPTION_LP_INTERVAL, + NM_SETTING_BOND_OPTION_MIN_LINKS, + NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, + NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, + NM_SETTING_BOND_OPTION_RESEND_IGMP, + NM_SETTING_BOND_OPTION_USE_CARRIER, + NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, + NM_SETTING_BOND_OPTION_NUM_GRAT_ARP)); } /*****************************************************************************/ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index de09e480..eb0d4d52 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -68,6 +68,7 @@ #include "nm-device-generic.h" #include "nm-device-vlan.h" +#include "nm-device-vrf.h" #include "nm-device-wireguard.h" #include "nm-device-logging.h" @@ -8097,15 +8098,21 @@ ip_config_merge_and_apply (NMDevice *self, } if (commit) { + gboolean is_vrf; + + is_vrf = priv->master && nm_device_get_device_type (priv->master) == NM_DEVICE_TYPE_VRF; + if (IS_IPv4) { nm_ip4_config_add_dependent_routes (NM_IP4_CONFIG (composite), nm_device_get_route_table (self, addr_family), nm_device_get_route_metric (self, addr_family), + is_vrf, &ip4_dev_route_blacklist); } else { nm_ip6_config_add_dependent_routes (NM_IP6_CONFIG (composite), nm_device_get_route_table (self, addr_family), - nm_device_get_route_metric (self, addr_family)); + nm_device_get_route_metric (self, addr_family), + is_vrf); } } @@ -9534,7 +9541,6 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingIPConfig *s_ip6; gs_unref_bytes GBytes *hwaddr = NULL; - gs_unref_bytes GBytes *bcast_hwaddr = NULL; gs_unref_bytes GBytes *duid = NULL; gboolean enforce_duid = FALSE; const NMPlatformLink *pllink; @@ -9564,20 +9570,16 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) } pllink = nm_platform_link_get (nm_device_get_platform (self), nm_device_get_ip_ifindex (self)); - if (pllink) { + if (pllink) hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address); - bcast_hwaddr = nmp_link_address_get_as_bytes (&pllink->l_broadcast); - } iaid = dhcp_get_iaid (self, AF_INET6, connection, &iaid_explicit); - duid = dhcp6_get_duid (self, connection, hwaddr, &enforce_duid); + priv->dhcp_data_6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (), nm_device_get_multi_index (self), nm_device_get_ip_iface (self), nm_device_get_ip_ifindex (self), - hwaddr, - bcast_hwaddr, &ll_addr->address, nm_connection_get_uuid (connection), nm_device_get_route_table (self, AF_INET6), @@ -10261,14 +10263,25 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) if (!nm_device_sysctl_ip_conf_set (self, AF_INET6, "mtu", nm_sprintf_buf (sbuf, "%u", (unsigned) ip6_mtu))) { int errsv = errno; + NMLogLevel level = LOGL_WARN; + const char *msg = NULL; - _NMLOG (anticipated_failure && errsv == EINVAL ? LOGL_DEBUG : LOGL_WARN, - LOGD_DEVICE, - "mtu: failure to set IPv6 MTU%s", - anticipated_failure && errsv == EINVAL - ? ": Is the underlying MTU value successfully set?" - : ""); success = FALSE; + + if (anticipated_failure && errsv == EINVAL) { + level = LOGL_DEBUG; + msg = "Is the underlying MTU value successfully set?"; + } else if (!g_file_test ("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) { + level = LOGL_DEBUG; + msg = "IPv6 is disabled"; + success = TRUE; + } + + _NMLOG (level, + LOGD_DEVICE, + "mtu: failure to set IPv6 MTU%s%s", + msg ? ": " : "", + msg ?: ""); } priv->carrier_wait_until_ms = nm_utils_get_monotonic_timestamp_msec () + CARRIER_WAIT_TIME_AFTER_MTU_MS; } diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 217c4bdd..7ba30342 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -371,6 +371,7 @@ teamd_ready (NMDeviceTeam *self) success = teamd_read_config (self); if (!success) { + teamd_cleanup (self, TRUE); nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); return; } diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 2d97f9b1..2a342886 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -1937,6 +1937,13 @@ supplicant_iface_bss_changed_cb (NMSupplicantInterface *iface, } else { gs_unref_object NMWifiAP *ap = NULL; + if (!bss_info->bssid_valid) { + /* We failed to initialize the info about the AP. This can + * happen due to an error in the D-Bus communication. In this case + * we ignore the info. */ + return; + } + ap = nm_wifi_ap_new_from_properties (bss_info); /* Let the manager try to fill in the SSID from seen-bssids lists */ diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index 7565bfc8..fc99a30a 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -240,21 +240,27 @@ client_start (NMDhcpManager *self, g_return_val_if_fail (!dhcp_client_id || g_bytes_get_size (dhcp_client_id) >= 2, NULL); g_return_val_if_fail (!error || !*error, NULL); - if (!hwaddr || !bcast_hwaddr) { - nm_utils_error_set (error, - NM_UTILS_ERROR_UNKNOWN, - "missing %s address", - hwaddr ? "broadcast" : "MAC"); - return NULL; - } + if (addr_family == AF_INET) { + if (!hwaddr || !bcast_hwaddr) { + nm_utils_error_set (error, + NM_UTILS_ERROR_UNKNOWN, + "missing %s address", + hwaddr ? "broadcast" : "MAC"); + return NULL; + } - hwaddr_len = g_bytes_get_size (hwaddr); - if ( hwaddr_len == 0 - || hwaddr_len > NM_UTILS_HWADDR_LEN_MAX) { - nm_utils_error_set (error, - NM_UTILS_ERROR_UNKNOWN, - "invalid MAC address"); - g_return_val_if_reached (NULL) ; + hwaddr_len = g_bytes_get_size (hwaddr); + if ( hwaddr_len == 0 + || hwaddr_len > NM_UTILS_HWADDR_LEN_MAX) { + nm_utils_error_set (error, + NM_UTILS_ERROR_UNKNOWN, + "invalid MAC address"); + g_return_val_if_reached (NULL) ; + } + nm_assert (g_bytes_get_size (hwaddr) == g_bytes_get_size (bcast_hwaddr)); + } else { + hwaddr = NULL; + bcast_hwaddr = NULL; } if (hostname) { @@ -268,8 +274,6 @@ client_start (NMDhcpManager *self, } } - nm_assert (g_bytes_get_size (hwaddr) == g_bytes_get_size (bcast_hwaddr)); - priv = NM_DHCP_MANAGER_GET_PRIVATE (self); /* Kill any old client instance */ @@ -457,8 +461,6 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, - GBytes *bcast_hwaddr, const struct in6_addr *ll_addr, const char *uuid, guint32 route_table, @@ -493,8 +495,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, multi_idx, iface, ifindex, - hwaddr, - bcast_hwaddr, + NULL, + NULL, uuid, route_table, route_metric, diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h index 88435282..e8e65ef3 100644 --- a/src/dhcp/nm-dhcp-manager.h +++ b/src/dhcp/nm-dhcp-manager.h @@ -54,8 +54,6 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, struct _NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, - GBytes *bcast_hwaddr, const struct in6_addr *ll_addr, const char *uuid, guint32 route_table, diff --git a/src/dhcp/nm-dhcp-options.c b/src/dhcp/nm-dhcp-options.c index b10635fc..d902c77c 100644 --- a/src/dhcp/nm-dhcp-options.c +++ b/src/dhcp/nm-dhcp-options.c @@ -183,6 +183,7 @@ const NMDhcpOption _nm_dhcp_option_dhcp6_options[] = { REQ (NM_DHCP_OPTION_DHCP6_DNS_SERVERS, "dhcp6_name_servers", TRUE ), REQ (NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, "dhcp6_domain_search", TRUE ), REQ (NM_DHCP_OPTION_DHCP6_SNTP_SERVERS, "dhcp6_sntp_servers", TRUE ), + REQ (NM_DHCP_OPTION_DHCP6_FQDN, "fqdn_fqdn", FALSE ), REQ (NM_DHCP_OPTION_DHCP6_MUD_URL, "dhcp6_mud_url", FALSE ), /* Internal values */ diff --git a/src/dhcp/nm-dhcp-options.h b/src/dhcp/nm-dhcp-options.h index 7c012170..bc3df5ac 100644 --- a/src/dhcp/nm-dhcp-options.h +++ b/src/dhcp/nm-dhcp-options.h @@ -160,7 +160,9 @@ typedef enum { NM_DHCP_OPTION_DHCP6_DNS_SERVERS = 23, NM_DHCP_OPTION_DHCP6_DOMAIN_LIST = 24, NM_DHCP_OPTION_DHCP6_SNTP_SERVERS = 31, + NM_DHCP_OPTION_DHCP6_FQDN = 39, NM_DHCP_OPTION_DHCP6_MUD_URL = 112, + /* Internal values */ NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS = 1026, NM_DHCP_OPTION_DHCP6_NM_PREFIXLEN = 1027, diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index f65937d8..737faad9 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -107,7 +107,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, guint32 rebinding; gs_free nm_sd_dhcp_option *private_options = NULL; - g_return_val_if_fail (lease != NULL, NULL); + nm_assert (lease != NULL); if (sd_dhcp_lease_get_address (lease, &a_address) < 0) { nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get address from lease"); @@ -481,9 +481,9 @@ bound4_handle (NMDhcpSystemd *self, gboolean extended) { NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self)); - sd_dhcp_lease *lease; gs_unref_object NMIP4Config *ip4_config = NULL; gs_unref_hashtable GHashTable *options = NULL; + sd_dhcp_lease *lease = NULL; GError *error = NULL; if ( sd_dhcp_client_get_lease (priv->client4, &lease) < 0 @@ -740,10 +740,11 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx, uint32_t lft_pref, lft_valid; char addr_str[NM_UTILS_INET_ADDRSTRLEN]; char **domains; + const char *s; nm_auto_free_gstring GString *str = NULL; int num, i; - g_return_val_if_fail (lease, NULL); + nm_assert (lease); ip6_config = nm_ip6_config_new (multi_idx, ifindex); @@ -808,6 +809,13 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx, str->str); } + if (sd_dhcp6_lease_get_fqdn (lease, &s) >= 0) { + nm_dhcp_option_add_option (options, + _nm_dhcp_option_dhcp6_options, + NM_DHCP_OPTION_DHCP6_FQDN, + s); + } + NM_SET_OUT (out_options, g_steal_pointer (&options)); return g_steal_pointer (&ip6_config); } @@ -822,7 +830,7 @@ bound6_handle (NMDhcpSystemd *self) gs_unref_hashtable GHashTable *options = NULL; gs_free_error GError *error = NULL; NMPlatformIP6Address prefix = { 0 }; - sd_dhcp6_lease *lease; + sd_dhcp6_lease *lease = NULL; if ( sd_dhcp6_client_get_lease (priv->client6, &lease) < 0 || !lease) { @@ -903,16 +911,12 @@ ip6_start (NMDhcpClient *client, NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); nm_auto (sd_dhcp6_client_unrefp) sd_dhcp6_client *sd_client = NULL; - GBytes *hwaddr; const char *hostname; const char *mud_url; int r, i; const guint8 *duid_arr; gsize duid_len; GBytes *duid; - const uint8_t *hwaddr_arr; - gsize hwaddr_len; - int arp_type; g_return_val_if_fail (!priv->client4, FALSE); g_return_val_if_fail (!priv->client6, FALSE); @@ -957,22 +961,6 @@ ip6_start (NMDhcpClient *client, return FALSE; } - hwaddr = nm_dhcp_client_get_hw_addr (client); - if ( !hwaddr - || !(hwaddr_arr = g_bytes_get_data (hwaddr, &hwaddr_len)) - || (arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len)) < 0) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address"); - return FALSE; - } - r = sd_dhcp6_client_set_mac (sd_client, - hwaddr_arr, - hwaddr_len, - (guint16) arp_type); - if (r < 0) { - nm_utils_error_set_errno (error, r, "failed to set MAC address: %s"); - return FALSE; - } - r = sd_dhcp6_client_set_ifindex (sd_client, nm_dhcp_client_get_ifindex (client)); if (r < 0) { diff --git a/src/initrd/nm-initrd-generator.h b/src/initrd/nm-initrd-generator.h index 97199921..8e17f045 100644 --- a/src/initrd/nm-initrd-generator.h +++ b/src/initrd/nm-initrd-generator.h @@ -9,6 +9,8 @@ #include "nm-connection.h" #include "nm-utils.h" +#define NMI_WAIT_DEVICE_TIMEOUT_MS 60000 + static inline gboolean guess_ip_address_family (const char *str) { diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c index 17f9e1df..be39ef89 100644 --- a/src/initrd/nmi-cmdline-reader.c +++ b/src/initrd/nmi-cmdline-reader.c @@ -584,7 +584,6 @@ reader_parse_master (Reader *reader, { NMConnection *connection; NMSettingConnection *s_con; - NMSettingBond *s_bond; gs_free char *master_to_free = NULL; const char *master; char *slaves; @@ -603,8 +602,15 @@ reader_parse_master (Reader *reader, s_con = nm_connection_get_setting_connection (connection); master = nm_setting_connection_get_uuid (s_con); - if (nm_streq (type_name, NM_SETTING_BOND_SETTING_NAME)) { - s_bond = (NMSettingBond *)nm_connection_get_setting_by_name (connection, type_name); + if (nm_streq (type_name, NM_SETTING_BRIDGE_SETTING_NAME)) { + NMSettingBridge *s_bridge = nm_connection_get_setting_bridge (connection); + + /* Avoid the forwarding delay */ + g_object_set (s_bridge, + NM_SETTING_BRIDGE_STP, FALSE, + NULL); + } else if (nm_streq (type_name, NM_SETTING_BOND_SETTING_NAME)) { + NMSettingBond *s_bond = nm_connection_get_setting_bond (connection); opts = get_word (&argument, ':'); while (opts && *opts) { @@ -867,6 +873,27 @@ reader_add_nameservers (Reader *reader, GPtrArray *nameservers) } } +static void +connection_set_needed (NMConnection *connection) +{ + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection (connection); + if (!nm_streq0 (nm_setting_connection_get_connection_type (s_con), + NM_SETTING_WIRED_SETTING_NAME)) + return; + + g_object_set (s_con, + NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, (int) NMI_WAIT_DEVICE_TIMEOUT_MS, + NULL); +} + +static void +connection_set_needed_cb (gpointer key, gpointer value, gpointer user_data) +{ + connection_set_needed (value); +} + GHashTable * nmi_cmdline_reader_parse (const char *sysfs_dir, const char *const*argv, char **hostname) { @@ -1001,11 +1028,16 @@ nmi_cmdline_reader_parse (const char *sysfs_dir, const char *const*argv, char ** connection = reader_get_connection (reader, bootdev, NULL, TRUE); reader->bootdev_connection = connection; + connection_set_needed (connection); } - if (neednet && g_hash_table_size (reader->hash) == 0) { - /* Make sure there's some connection. */ - reader_get_default_connection (reader); + if (neednet) { + if (g_hash_table_size (reader->hash) == 0) { + /* Make sure there's some connection. */ + reader_get_default_connection (reader); + } + + g_hash_table_foreach (reader->hash, connection_set_needed_cb, NULL); } if (routes) diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c index 04594c48..7787cf5e 100644 --- a/src/initrd/tests/test-cmdline-reader.c +++ b/src/initrd/tests/test-cmdline-reader.c @@ -49,6 +49,7 @@ test_auto (void) g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Wired Connection"); g_assert_cmpint (nm_setting_connection_get_timestamp (s_con), ==, 0); g_assert_cmpint (nm_setting_connection_get_multi_connect (s_con), ==, NM_CONNECTION_MULTI_CONNECT_MULTIPLE); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout (s_con), ==, -1); g_assert (nm_setting_connection_get_autoconnect (s_con)); @@ -190,6 +191,7 @@ test_if_ip4_manual (void) "ip=203.0.113.2::203.0.113.1:26:" "hostname1.example.com:eth4"); NMConnection *connection; + NMSettingConnection *s_con; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; NMIPAddress *ip_addr; @@ -205,6 +207,10 @@ test_if_ip4_manual (void) nmtst_assert_connection_verifies_without_normalization (connection); g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth3"); + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout (s_con), ==, -1); + s_ip4 = nm_connection_get_setting_ip4_config (connection); g_assert (s_ip4); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); @@ -294,6 +300,7 @@ test_multiple_merge (void) const char *const*ARGV = NM_MAKE_STRV ("ip=192.0.2.2:::::eth0", "ip=[2001:db8::2]:::::eth0"); NMConnection *connection; + NMSettingConnection *s_con; NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; @@ -310,6 +317,10 @@ test_multiple_merge (void) nmtst_assert_connection_verifies_without_normalization (connection); g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout (s_con), ==, -1); + s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired); @@ -341,6 +352,7 @@ test_multiple_bootdev (void) "ip=eth4:dhcp", "bootdev=eth4"); NMConnection *connection; + NMSettingConnection *s_con; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; gs_free char *hostname = NULL; @@ -352,12 +364,18 @@ test_multiple_bootdev (void) connection = g_hash_table_lookup (connections, "eth3"); g_assert (connection); + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout (s_con), ==, -1); s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); connection = g_hash_table_lookup (connections, "eth4"); g_assert (connection); + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout (s_con), ==, NMI_WAIT_DEVICE_TIMEOUT_MS); s_ip4 = nm_connection_get_setting_ip4_config (connection); g_assert (s_ip4); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); @@ -388,6 +406,7 @@ test_bootdev (void) g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "ens3"); g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "ens3"); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout(s_con), ==, NMI_WAIT_DEVICE_TIMEOUT_MS); connection = g_hash_table_lookup (connections, "vlan2"); g_assert (connection); @@ -774,6 +793,7 @@ test_bridge (void) s_bridge = nm_connection_get_setting_bridge (connection); g_assert (s_bridge); + g_assert_cmpint (nm_setting_bridge_get_stp (s_bridge), ==, FALSE); connection = g_hash_table_lookup (connections, "eth0"); g_assert (connection); @@ -1255,6 +1275,56 @@ test_bootif_ip (void) } static void +test_neednet (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + const char *const*ARGV = NM_MAKE_STRV ("rd.neednet", + "ip=eno1:dhcp", + "ip=172.25.1.100::172.25.1.1:24::eno2", + "bridge=br0:eno3"); + NMConnection *connection; + NMSettingConnection *s_con; + gs_free char *hostname = NULL; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV, &hostname); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 4); + g_assert_cmpstr (hostname, ==, NULL); + + connection = g_hash_table_lookup (connections, "eno1"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "eno1"); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout (s_con), ==, NMI_WAIT_DEVICE_TIMEOUT_MS); + + connection = g_hash_table_lookup (connections, "eno2"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "eno2"); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout (s_con), ==, NMI_WAIT_DEVICE_TIMEOUT_MS); + + connection = g_hash_table_lookup (connections, "eno3"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "eno3"); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout (s_con), ==, NMI_WAIT_DEVICE_TIMEOUT_MS); + + connection = g_hash_table_lookup (connections, "br0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "br0"); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout (s_con), ==, -1); +} + +static void test_bootif_no_ip (void) { gs_unref_hashtable GHashTable *connections = NULL; @@ -1450,6 +1520,7 @@ int main (int argc, char **argv) g_test_add_func ("/initrd/cmdline/bootif/no_ip", test_bootif_no_ip); g_test_add_func ("/initrd/cmdline/bootif/hwtype", test_bootif_hwtype); g_test_add_func ("/initrd/cmdline/bootif/off", test_bootif_off); + g_test_add_func ("/initrd/cmdline/neednet", test_neednet); return g_test_run (); } diff --git a/src/meson.build b/src/meson.build index 8ff9bd11..07bb1a52 100644 --- a/src/meson.build +++ b/src/meson.build @@ -264,8 +264,8 @@ symbol_map_name = 'NetworkManager.ver' # add dependencies with link_whole, only supported in meson >= 0.46. # Create an executable with full symbols that we use in place of the # library to enumerate the symbols. -network_manager_sym = executable( - 'nm-full-symbols', +network_manager_all_sym = executable( + 'NetworkManager-all-sym', 'main.c', dependencies: nm_deps, c_args: daemon_c_flags, @@ -277,7 +277,7 @@ network_manager_sym = executable( ver_script = custom_target( symbol_map_name, output: symbol_map_name, - depends: [network_manager_sym, core_plugins], + depends: [network_manager_all_sym, core_plugins], command: [create_exports_networkmanager, '--called-from-build', source_root], ) diff --git a/src/ndisc/tests/test-ndisc-fake.c b/src/ndisc/tests/test-ndisc-fake.c index b65511e0..254110e4 100644 --- a/src/ndisc/tests/test-ndisc-fake.c +++ b/src/ndisc/tests/test-ndisc-fake.c @@ -61,8 +61,8 @@ match_gateway (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts _a = &_rdata->addresses[_idx]; \ \ nmtst_assert_ip6_address (&_a->address, (addr)); \ - g_assert_cmpint (_a->timestamp, >=, _ts); \ g_assert_cmpint (_a->timestamp, <=, _ts + 1); \ + g_assert_cmpint ((int) _a->timestamp, >=, (int) _ts - 1); \ g_assert_cmpint (_a->timestamp + _a->lifetime, ==, _ts + (lt)); \ g_assert_cmpint (_a->timestamp + _a->preferred, ==, _ts + (pref)); \ } G_STMT_END diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 08037ebe..151fb4d9 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -810,14 +810,14 @@ master_state_cb (NMActiveConnection *master, gpointer user_data) { NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); NMActiveConnectionState master_state = nm_active_connection_get_state (master); - NMDevice *master_device = nm_active_connection_get_device (master); check_master_ready (self); if ( master_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATING - && (!master_device || !nm_device_is_real (master_device))) { - /* Master failed without ever creating or realizing its device */ + && !priv->master_ready) { + /* Master disconnected before the slave was added */ if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed) NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self); } diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 4169a36e..ea3aed47 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -1361,6 +1361,8 @@ nm_config_data_get_device_config (const NMConfigData *self, const MatchSectionInfo *connection_info; char *value = NULL; + NM_SET_OUT (has_match, FALSE); + g_return_val_if_fail (self, NULL); g_return_val_if_fail (property && *property, NULL); diff --git a/src/nm-hostname-manager.c b/src/nm-hostname-manager.c index f44e169e..86beffdf 100644 --- a/src/nm-hostname-manager.c +++ b/src/nm-hostname-manager.c @@ -11,6 +11,7 @@ #if HAVE_SELINUX #include <selinux/selinux.h> +#include <selinux/label.h> #endif #include "nm-libnm-core-intern/nm-common-macros.h" @@ -345,8 +346,8 @@ nm_hostname_manager_write_hostname (NMHostnameManager *self, const char *hostnam gs_unref_variant GVariant *var = NULL; struct stat file_stat; #if HAVE_SELINUX - security_context_t se_ctx_prev = NULL, se_ctx = NULL; - mode_t st_mode = 0; + gboolean fcon_was_set = FALSE; + char *fcon_prev = NULL; #endif g_return_val_if_fail (NM_IS_HOSTNAME_MANAGER (self), FALSE); @@ -376,16 +377,6 @@ nm_hostname_manager_write_hostname (NMHostnameManager *self, const char *hostnam && (link_path = nm_utils_read_link_absolute (file, NULL))) file = link_path; -#if HAVE_SELINUX - /* Get default context for hostname file and set it for fscreate */ - if (stat (file, &file_stat) == 0) - st_mode = file_stat.st_mode; - matchpathcon (file, st_mode, &se_ctx); - matchpathcon_fini (); - getfscreatecon (&se_ctx_prev); - setfscreatecon (se_ctx); -#endif - #if defined (HOSTNAME_PERSIST_GENTOO) hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n" "hostname=\"%s\"\n", hostname); @@ -393,13 +384,39 @@ nm_hostname_manager_write_hostname (NMHostnameManager *self, const char *hostnam hostname_eol = g_strdup_printf ("%s\n", hostname); #endif +#if HAVE_SELINUX + /* Get default context for hostname file and set it for fscreate */ + { + struct selabel_handle *handle; + + handle = selabel_open (SELABEL_CTX_FILE, NULL, 0); + if (handle) { + mode_t st_mode = 0; + char *fcon = NULL; + + if (stat (file, &file_stat) == 0) + st_mode = file_stat.st_mode; + + if ( (selabel_lookup (handle, &fcon, file, st_mode) == 0) + && (getfscreatecon (&fcon_prev) == 0)) { + setfscreatecon (fcon); + fcon_was_set = TRUE; + } + + selabel_close (handle); + freecon (fcon); + } + } +#endif + ret = g_file_set_contents (file, hostname_eol, -1, &error); #if HAVE_SELINUX /* Restore previous context and cleanup */ - setfscreatecon (se_ctx_prev); - freecon (se_ctx); - freecon (se_ctx_prev); + if (fcon_was_set) + setfscreatecon (fcon_prev); + if (fcon_prev) + freecon (fcon_prev); #endif g_free (hostname_eol); diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 6320e722..c7d65d2a 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -41,11 +41,13 @@ static struct { GMainLoop *main_loop; int ifindex; + gboolean is_vrf_device; guint dad_failed_id; CList dad_failed_lst_head; } gl/*obal*/ = { .ifindex = -1, + .is_vrf_device = FALSE, }; static struct { @@ -120,6 +122,7 @@ dhcp4_state_changed (NMDhcpClient *client, nm_ip4_config_add_dependent_routes (existing, RT_TABLE_MAIN, global_opt.priority_v4, + gl.is_vrf_device, &ip4_dev_route_blacklist); if (!nm_ip4_config_commit (existing, NM_PLATFORM_GET, @@ -236,7 +239,8 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT, 0); nm_ip6_config_add_dependent_routes (existing, RT_TABLE_MAIN, - global_opt.priority_v6); + global_opt.priority_v6, + gl.is_vrf_device); if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET, NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, @@ -480,6 +484,11 @@ main (int argc, char *argv[]) if (pllink) { hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address); bcast_hwaddr = nmp_link_address_get_as_bytes (&pllink->l_broadcast); + + if (pllink->master > 0) { + gl.is_vrf_device + = nm_platform_link_get_type (NM_PLATFORM_GET, pllink->master) == NM_LINK_TYPE_VRF; + } } if (global_opt.iid_str) { diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 490296c8..23c0d3f9 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -384,7 +384,7 @@ nm_ip4_config_lookup_routes (const NMIP4Config *self) void nm_ip_config_iter_ip4_route_init (NMDedupMultiIter *ipconf_iter, const NMIP4Config *self) { - g_return_if_fail (NM_IS_IP4_CONFIG (self)); + nm_assert (NM_IS_IP4_CONFIG (self)); nm_dedup_multi_iter_init (ipconf_iter, nm_ip4_config_lookup_routes (self)); } @@ -672,9 +672,11 @@ nm_ip4_config_update_routes_metric (NMIP4Config *self, gint64 metric) } static void -_add_local_route_from_addr4 (NMIP4Config *self, - const NMPlatformIP4Address *addr, - int ifindex) +_add_local_route_from_addr4 (NMIP4Config * self, + const NMPlatformIP4Address *addr, + int ifindex, + guint32 route_table, + gboolean is_vrf) { nm_auto_nmpobj NMPObject *r = NULL; NMPlatformIP4Route *route; @@ -686,18 +688,19 @@ _add_local_route_from_addr4 (NMIP4Config *self, route->network = addr->address; route->plen = 32; route->pref_src = addr->address; - route->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); route->type_coerced = nm_platform_route_type_coerce (RTN_LOCAL); route->scope_inv = nm_platform_route_scope_inv (RT_SCOPE_HOST); + route->table_coerced = nm_platform_route_table_coerce (is_vrf ? route_table : RT_TABLE_LOCAL); _add_route (self, r, NULL, NULL); } void nm_ip4_config_add_dependent_routes (NMIP4Config *self, - guint32 route_table, - guint32 route_metric, - GPtrArray **out_ip4_dev_route_blacklist) + guint32 route_table, + guint32 route_metric, + gboolean is_vrf, + GPtrArray ** out_ip4_dev_route_blacklist) { GPtrArray *ip4_dev_route_blacklist = NULL; const NMPlatformIP4Address *my_addr; @@ -729,7 +732,7 @@ nm_ip4_config_add_dependent_routes (NMIP4Config *self, if (my_addr->external) continue; - _add_local_route_from_addr4 (self, my_addr, ifindex); + _add_local_route_from_addr4 (self, my_addr, ifindex, route_table, is_vrf); if (_ipv4_is_zeronet (network)) { /* Kernel doesn't add device-routes for destinations that @@ -3224,6 +3227,9 @@ out_addresses_cached: nm_assert (_route_valid (route)); + if (route->type_coerced != nm_platform_route_type_coerce (RTN_UNICAST)) + continue; + g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&route_builder, "{sv}", "dest", diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index d4694d93..ea061749 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -83,7 +83,8 @@ nm_ip_config_best_default_route_is (const NMPObject *obj) * Note that this only considers the main routing table. */ return r && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r) - && nm_platform_route_table_is_main (r->table_coerced); + && nm_platform_route_table_is_main (r->table_coerced) + && r->type_coerced == nm_platform_route_type_coerce (1 /*RTN_UNICAST*/); } const NMPObject *_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp); @@ -157,9 +158,10 @@ NMDedupMultiIndex *nm_ip4_config_get_multi_idx (const NMIP4Config *self); NMIP4Config *nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex); void nm_ip4_config_add_dependent_routes (NMIP4Config *self, - guint32 route_table, - guint32 route_metric, - GPtrArray **out_ip4_dev_route_blacklist); + guint32 route_table, + guint32 route_metric, + gboolean is_vrf, + GPtrArray ** out_ip4_dev_route_blacklist); gboolean nm_ip4_config_commit (const NMIP4Config *self, NMPlatform *platform, diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 4911ec1d..deb30e77 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -475,27 +475,32 @@ _add_multicast_route6 (NMIP6Config *self, int ifindex) } static void -_add_local_route_from_addr6 (NMIP6Config *self, const NMPlatformIP6Address *addr, int ifindex) +_add_local_route_from_addr6 (NMIP6Config * self, + const NMPlatformIP6Address *addr, + int ifindex, + guint32 route_table, + gboolean is_vrf) { nm_auto_nmpobj NMPObject *r = NULL; - NMPlatformIP6Route *route; + NMPlatformIP6Route * route; r = nmp_object_new (NMP_OBJECT_TYPE_IP6_ROUTE, NULL); route = NMP_OBJECT_CAST_IP6_ROUTE (r); route->ifindex = ifindex; route->network = addr->address; route->plen = 128; - route->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); route->type_coerced = nm_platform_route_type_coerce (RTN_LOCAL); route->metric = 0; + route->table_coerced = nm_platform_route_table_coerce (is_vrf ? route_table : RT_TABLE_LOCAL); _add_route (self, r, NULL, NULL); } void nm_ip6_config_add_dependent_routes (NMIP6Config *self, - guint32 route_table, - guint32 route_metric) + guint32 route_table, + guint32 route_metric, + gboolean is_vrf) { const NMPlatformIP6Address *my_addr; const NMPlatformIP6Route *my_route; @@ -524,7 +529,7 @@ nm_ip6_config_add_dependent_routes (NMIP6Config *self, continue; /* Pre-generate local route added by kernel */ - _add_local_route_from_addr6 (self, my_addr, ifindex); + _add_local_route_from_addr6 (self, my_addr, ifindex, route_table, is_vrf); if (NM_FLAGS_HAS (my_addr->n_ifa_flags, IFA_F_NOPREFIXROUTE)) continue; @@ -2677,6 +2682,9 @@ out_addresses_cached: nm_assert (_route_valid (route)); + if (route->type_coerced != nm_platform_route_type_coerce (RTN_UNICAST)) + continue; + g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&route_builder, "{sv}", "dest", diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 36e8518a..b6f461b2 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -93,8 +93,9 @@ NMIP6Config *nm_ip6_config_capture (struct _NMDedupMultiIndex *multi_idx, NMPlat NMSettingIP6ConfigPrivacy use_temporary); void nm_ip6_config_add_dependent_routes (NMIP6Config *self, - guint32 route_table, - guint32 route_metric); + guint32 route_table, + guint32 route_metric, + gboolean is_vrf); gboolean nm_ip6_config_commit (const NMIP6Config *self, NMPlatform *platform, diff --git a/src/nm-manager.c b/src/nm-manager.c index 92112532..778e3b94 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1561,13 +1561,6 @@ check_if_startup_complete (NMManager *self) if (!priv->devices_inited) return; - reason = nm_settings_get_startup_complete_blocked_reason (priv->settings); - if (reason) { - _LOGD (LOGD_CORE, "startup complete is waiting for connection (%s)", - reason); - return; - } - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { reason = nm_device_has_pending_action_reason (device); if (reason) { @@ -1578,6 +1571,31 @@ check_if_startup_complete (NMManager *self) } } + /* All NMDevice must be ready. But also NMSettings tracks profiles that wait for + * ready devices via "connection.wait-device-timeout". + * + * Note that we only re-check nm_settings_get_startup_complete_blocked_reason() when + * all of the devices become ready (again). + * + * For example, assume we have device "eth1" and "profile-eth2" which waits for "eth2". + * If "eth1" is ready (no pending action), we only need to re-evaluate "profile-eth2" + * if we have another device ("eth2"), that becomes non-ready (had pending actions) + * and again become ready. We don't need to check "profile-eth2" until "eth2" becomes + * non-ready. + * That is why nm_settings_get_startup_complete_blocked_reason() only has any significance + * if all devices are ready too. It allows us to cut down the number of checks whether + * NMSettings is ready. That's because we don't need to re-evaluate on minor changes of + * a device, only when all devices become managed and ready. */ + + g_signal_handlers_block_by_func (priv->settings, settings_startup_complete_changed, self); + reason = nm_settings_get_startup_complete_blocked_reason (priv->settings, TRUE); + g_signal_handlers_unblock_by_func (priv->settings, settings_startup_complete_changed, self); + if (reason) { + _LOGD (LOGD_CORE, "startup complete is waiting for connection (%s)", + reason); + return; + } + _LOGI (LOGD_CORE, "startup complete"); priv->startup = FALSE; @@ -6048,8 +6066,9 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) } else { _LOGD (LOGD_SUSPEND, "sleep: %s...", waking_from_suspend ? "waking up" : "re-enabling"); + sleep_devices_clear (self); + if (waking_from_suspend) { - sleep_devices_clear (self); c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { if (nm_device_is_software (device)) continue; @@ -7454,7 +7473,7 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_manager_parent_class)->constructed (object); - priv->settings = nm_settings_new (); + priv->settings = nm_settings_new (self); nm_dbus_object_export (NM_DBUS_OBJECT (priv->settings)); diff --git a/src/nm-policy.c b/src/nm-policy.c index 62ead242..04cbace6 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -764,7 +764,7 @@ update_system_hostname (NMPolicy *self, const char *msg) /* Grab a hostname out of the device's DHCP6 config */ dhcp_config = nm_device_get_dhcp_config (get_default_device (self, AF_INET6), AF_INET6); if (dhcp_config) { - dhcp_hostname = nm_dhcp_config_get_option (dhcp_config, "host_name"); + dhcp_hostname = nm_dhcp_config_get_option (dhcp_config, "fqdn_fqdn"); if (dhcp_hostname && dhcp_hostname[0]) { p = nm_str_skip_leading_spaces (dhcp_hostname); if (p[0]) { @@ -1787,7 +1787,7 @@ device_state_changed (NMDevice *device, if ( sett_conn && old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_ACTIVATED) { - gboolean block_no_secrets = FALSE; + gboolean blocked = FALSE; int tries; guint64 con_v; @@ -1807,15 +1807,32 @@ device_state_changed (NMDevice *device, */ con_v = nm_settings_connection_get_last_secret_agent_version_id (sett_conn); if ( con_v == 0 - || con_v == nm_agent_manager_get_agent_version_id (priv->agent_mgr)) - block_no_secrets = TRUE; + || con_v == nm_agent_manager_get_agent_version_id (priv->agent_mgr)) { + _LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to no secrets", + nm_settings_connection_get_id (sett_conn)); + nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, + TRUE); + blocked = TRUE; + } + } else if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED) { + /* A connection that fails due to dependency-failed is not + * able to reconnect until the master connection activates + * again; when this happens, the master clears the blocked + * reason for all its slaves in activate_slave_connections() + * and tries to reconnect them. For this to work, the slave + * should be marked as blocked when it fails with + * dependency-failed. + */ + _LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to failed dependency", + nm_settings_connection_get_id (sett_conn)); + nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, + TRUE); + blocked = TRUE; } - if (block_no_secrets) { - _LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to no secrets", - nm_settings_connection_get_id (sett_conn)); - nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, TRUE); - } else { + if (!blocked) { tries = nm_settings_connection_autoconnect_retries_get (sett_conn); if (tries > 0) { _LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; %d tries left", diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index fbcc2b31..2f33dc04 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -8196,7 +8196,10 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex) if (!wifi_data) return FALSE; - return nm_wifi_utils_get_wake_on_wlan (wifi_data) != NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE; + return !NM_IN_SET (nm_wifi_utils_get_wake_on_wlan (wifi_data), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE, + NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE); + } else return FALSE; } diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 0a1e7b47..4573d5f7 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -60,6 +60,7 @@ #include "plugins/keyfile/nms-keyfile-storage.h" #include "nm-agent-manager.h" #include "nm-config.h" +#include "nm-manager.h" #include "nm-audit-manager.h" #include "NetworkManagerUtils.h" #include "nm-dispatcher.h" @@ -324,6 +325,7 @@ _sett_conn_entry_find_shadowed_storage (SettConnEntry *sett_conn_entry, /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE (NMSettings, + PROP_MANAGER, PROP_UNMANAGED_SPECS, PROP_HOSTNAME, PROP_CAN_MODIFY, @@ -348,6 +350,8 @@ typedef struct { NMPlatform *platform; + NMManager *manager; + NMHostnameManager *hostname_manager; NMSessionMonitor *session_monitor; @@ -372,9 +376,9 @@ typedef struct { GSList *unmanaged_specs; GSList *unrecognized_specs; + gint64 startup_complete_start_timestamp_msec; GHashTable *startup_complete_idx; - NMSettingsConnection *startup_complete_blocked_by; - gulong startup_complete_platform_change_id; + CList startup_complete_scd_lst_head; guint startup_complete_timeout_id; guint connections_len; @@ -423,7 +427,7 @@ static void default_wired_clear_tag (NMSettings *self, static void _clear_connections_cached_list (NMSettingsPrivate *priv); static void _startup_complete_check (NMSettings *self, - gint64 now_us); + gint64 now_msec); /*****************************************************************************/ @@ -461,34 +465,53 @@ _emit_connection_flags_changed (NMSettings *self, typedef struct { NMSettingsConnection *sett_conn; - gint64 start_at; - gint64 timeout; + CList scd_lst; + gint64 timeout_msec; } StartupCompleteData; static void _startup_complete_data_destroy (StartupCompleteData *scd) { + c_list_unlink_stale (&scd->scd_lst); g_object_unref (scd->sett_conn); - g_slice_free (StartupCompleteData, scd); + nm_g_slice_free (scd); } static gboolean -_startup_complete_check_is_ready (NMPlatform *platform, - NMSettingsConnection *sett_conn) +_startup_complete_check_is_ready (NMSettings *self, + NMSettingsConnection *sett_conn, + gboolean ignore_pending_actions) { - const NMPlatformLink *plink; - const char *ifname; + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + NMConnection *conn; + const CList *tmp_lst; + NMDevice *device; - /* FIXME: instead of just looking for the interface name, it would be better - * to wait for a device that is compatible with the profile. */ + if (!priv->manager) + return TRUE; - ifname = nm_connection_get_interface_name (nm_settings_connection_get_connection (sett_conn)); + conn = nm_settings_connection_get_connection (sett_conn); + + nm_manager_for_each_device (priv->manager, device, tmp_lst) { + + if (!nm_device_is_real (device)) + continue; + + if ( nm_device_get_state (device) < NM_DEVICE_STATE_UNAVAILABLE + || ( !ignore_pending_actions + && nm_device_has_pending_action (device))) { + /* while a device is not yet available and still has a pending + * action itself, it's not a suitable candidate. */ + continue; + } + + if (!nm_device_check_connection_compatible (device, conn, NULL)) + continue; - if (!ifname) return TRUE; + } - plink = nm_platform_link_get_by_ifname (platform, ifname); - return plink && plink->initialized; + return FALSE; } static gboolean @@ -503,116 +526,97 @@ _startup_complete_timeout_cb (gpointer user_data) } static void -_startup_complete_platform_change_cb (NMPlatform *platform, - int obj_type_i, - int ifindex, - const NMPlatformLink *link, - int change_type_i, - NMSettings *self) -{ - const NMPlatformSignalChangeType change_type = change_type_i; - NMSettingsPrivate *priv; - const char *ifname; - - if (change_type == NM_PLATFORM_SIGNAL_REMOVED) - return; - - if (!link->initialized) - return; - - priv = NM_SETTINGS_GET_PRIVATE (self); - - ifname = nm_connection_get_interface_name (nm_settings_connection_get_connection (priv->startup_complete_blocked_by)); - if ( ifname - && !nm_streq (ifname, link->name)) - return; - - nm_assert (priv->startup_complete_timeout_id > 0); - - nm_clear_g_source (&priv->startup_complete_timeout_id); - priv->startup_complete_timeout_id = g_idle_add (_startup_complete_timeout_cb, self); -} - -static void _startup_complete_check (NMSettings *self, - gint64 now_us) + gint64 now_msec) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - gint64 next_expiry; + StartupCompleteData *scd_not_ready; + StartupCompleteData *scd_safe; StartupCompleteData *scd; - NMSettingsConnection *next_sett_conn = NULL; - GHashTableIter iter; + gint64 elapsed_msec; + CList ready_lst; + + if (priv->startup_complete_start_timestamp_msec == 0) { + /* we are already done for good or didn't start yet. */ + return; + } if (!priv->started) { - /* before we are started, we don't setup the timers... */ + /* before we are started there is no need to evaluate our list because + * we are anyway blocking startup-complete. */ return; } - if (!priv->startup_complete_idx) + if (c_list_is_empty (&priv->startup_complete_scd_lst_head)) goto ready; - if (!now_us) - now_us = nm_utils_get_monotonic_timestamp_usec (); + nm_utils_get_monotonic_timestamp_msec_cached (&now_msec); - next_expiry = 0; + elapsed_msec = now_msec - priv->startup_complete_start_timestamp_msec; - g_hash_table_iter_init (&iter, priv->startup_complete_idx); - while (g_hash_table_iter_next (&iter, (gpointer *) &scd, NULL)) { - gint64 expiry; - - if (scd->start_at == 0) { - /* once ready, the decision is remembered and there is nothing - * left to check. */ - continue; - } + /* We search the entire list whether they all timed-out or found a compatible device. + * We do that by appending elements that are ready to the end of the list, so that + * we hopefully keep testing the elements that are ready already (and can shortcut + * the test in common cases). + * + * Note that all profiles that we wait for need to have their dependencies satisfied + * at the same time. For example, consider connection A is waiting for device A' which is ready. + * Connection B waits for device B', which isn't ready. Once B'/B becomes ready, A/A' must + * still be ready. Otherwise, we would wait for A/A' to become ready again. */ + scd_not_ready = NULL; + c_list_init (&ready_lst); + c_list_for_each_entry_safe (scd, scd_safe, &priv->startup_complete_scd_lst_head, scd_lst) { - expiry = scd->start_at + scd->timeout; - if (expiry <= now_us) { - scd->start_at = 0; - continue; - } + if (scd->timeout_msec <= elapsed_msec) + goto next_with_ready; - if (_startup_complete_check_is_ready (priv->platform, scd->sett_conn)) { - scd->start_at = 0; - continue; - } + if (_startup_complete_check_is_ready (self, scd->sett_conn, FALSE)) + goto next_with_ready; - next_expiry = expiry; - next_sett_conn = scd->sett_conn; - /* we found one timeout for which to wait. that's good enough. */ + scd_not_ready = scd; break; + +next_with_ready: + /* this element is ready. We move it to a temporary list, so that we + * can reorder the list (to next time evaluate the non-ready element first). */ + nm_c_list_move_tail (&ready_lst, &scd->scd_lst); } + c_list_splice (&priv->startup_complete_scd_lst_head, &ready_lst); nm_clear_g_source (&priv->startup_complete_timeout_id); - nm_g_object_ref_set (&priv->startup_complete_blocked_by, next_sett_conn); - if (next_expiry > 0) { - nm_assert (priv->startup_complete_blocked_by); - if (priv->startup_complete_platform_change_id == 0) { - priv->startup_complete_platform_change_id = g_signal_connect (priv->platform, - NM_PLATFORM_SIGNAL_LINK_CHANGED, - G_CALLBACK (_startup_complete_platform_change_cb), - self); - } - priv->startup_complete_timeout_id = g_timeout_add (NM_MIN (3600u*1000u, (next_expiry - now_us) / 1000u), + + if (scd_not_ready) { + gint64 timeout_msec; + + timeout_msec = priv->startup_complete_start_timestamp_msec + scd_not_ready->timeout_msec - nm_utils_get_monotonic_timestamp_msec (); + priv->startup_complete_timeout_id = g_timeout_add (NM_CLAMP (0, timeout_msec, 60000), _startup_complete_timeout_cb, self); - _LOGT ("startup-complete: wait for device \"%s\" due to connection %s (%s)", - nm_connection_get_interface_name (nm_settings_connection_get_connection (priv->startup_complete_blocked_by)), - nm_settings_connection_get_uuid (priv->startup_complete_blocked_by), - nm_settings_connection_get_id (priv->startup_complete_blocked_by)); + _LOGT ("startup-complete: wait for suitable device for connection \"%s\" (%s) which has \"connection.wait-device-timeout\" set", + nm_settings_connection_get_id (scd_not_ready->sett_conn), + nm_settings_connection_get_uuid (scd_not_ready->sett_conn)); return; } - nm_clear_pointer (&priv->startup_complete_idx, g_hash_table_destroy); - nm_clear_g_signal_handler (priv->platform, &priv->startup_complete_platform_change_id); + if (_LOGW_ENABLED ()) { + c_list_for_each_entry (scd, &priv->startup_complete_scd_lst_head, scd_lst) { + if (!_startup_complete_check_is_ready (self, scd->sett_conn, TRUE)) { + _LOGW ("startup-complete: profile \"%s\" (%s) was waiting for non-existing device (with timeout \"connection.wait-device-timeout=%"G_GINT64_FORMAT"\")", + nm_settings_connection_get_id (scd->sett_conn), + nm_settings_connection_get_uuid (scd->sett_conn), + scd->timeout_msec); + } + } + } ready: - _LOGT ("startup-complete: ready, no profiles to wait for"); + nm_clear_pointer (&priv->startup_complete_idx, g_hash_table_destroy); + nm_assert (c_list_is_empty (&priv->startup_complete_scd_lst_head)); nm_assert (priv->started); - nm_assert (!priv->startup_complete_blocked_by); + _LOGT ("startup-complete: ready, no more profiles to wait for"); + priv->startup_complete_start_timestamp_msec = 0; nm_assert (!priv->startup_complete_idx); nm_assert (priv->startup_complete_timeout_id == 0); - nm_assert (priv->startup_complete_platform_change_id == 0); _notify (self, PROP_STARTUP_COMPLETE); } @@ -622,75 +626,95 @@ _startup_complete_notify_connection (NMSettings *self, gboolean forget) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - gint64 timeout; - gint64 now_us = 0; - - nm_assert ( !priv->started - || priv->startup_complete_idx); - - timeout = 0; - if (!forget) { - NMSettingConnection *s_con; - gint32 v; - - s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (sett_conn)); - v = nm_setting_connection_get_wait_device_timeout (s_con); - if (v > 0) { - nm_assert (nm_setting_connection_get_interface_name (s_con)); - timeout = ((gint64) v) * 1000; - } + StartupCompleteData *scd; + gint64 timeout_msec; + gint64 now_msec = 0; + NMSettingConnection *s_con; + gint32 v; + + nm_assert (priv->startup_complete_start_timestamp_msec != 0); + + if (forget) { + if (!priv->startup_complete_idx) + return; + if (!g_hash_table_remove (priv->startup_complete_idx, &sett_conn)) + return; + goto check; } - if (timeout == 0) { - if ( !priv->startup_complete_idx - || !g_hash_table_remove (priv->startup_complete_idx, &sett_conn)) + s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (sett_conn)); + v = nm_setting_connection_get_wait_device_timeout (s_con); + if (v > 0) + timeout_msec = v; + else + timeout_msec = 0; + + if (!priv->startup_complete_idx) { + nm_assert (!priv->started); + + if (timeout_msec == 0) + return; + + priv->startup_complete_idx = g_hash_table_new_full (nm_pdirect_hash, + nm_pdirect_equal, + NULL, + (GDestroyNotify) _startup_complete_data_destroy); + scd = NULL; + } else + scd = g_hash_table_lookup (priv->startup_complete_idx, &sett_conn); + + if (!scd) { + if (timeout_msec == 0) return; + scd = g_slice_new (StartupCompleteData); + *scd = (StartupCompleteData) { + .sett_conn = g_object_ref (sett_conn), + .timeout_msec = timeout_msec, + }; + g_hash_table_add (priv->startup_complete_idx, scd); + c_list_link_tail (&priv->startup_complete_scd_lst_head, &scd->scd_lst); } else { - StartupCompleteData *scd; - - if (!priv->startup_complete_idx) { - nm_assert (!priv->started); - priv->startup_complete_idx = g_hash_table_new_full (nm_pdirect_hash, - nm_pdirect_equal, - NULL, - (GDestroyNotify) _startup_complete_data_destroy); - scd = NULL; - } else - scd = g_hash_table_lookup (priv->startup_complete_idx, &sett_conn); - if (!scd) { - now_us = nm_utils_get_monotonic_timestamp_usec (); - scd = g_slice_new (StartupCompleteData); - *scd = (StartupCompleteData) { - .sett_conn = g_object_ref (sett_conn), - .start_at = now_us, - .timeout = timeout, - }; - g_hash_table_add (priv->startup_complete_idx, scd); - } else { - if (scd->start_at == 0) { - /* the entry already is ready and no longer relevant. Ignore it. */ - return; - } - scd->timeout = timeout; - } + scd->timeout_msec = timeout_msec; + nm_c_list_move_front (&priv->startup_complete_scd_lst_head, &scd->scd_lst); } - _startup_complete_check (self, now_us); +check: + _startup_complete_check (self, now_msec); } const char * -nm_settings_get_startup_complete_blocked_reason (NMSettings *self) +nm_settings_get_startup_complete_blocked_reason (NMSettings *self, + gboolean force_reload) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - const char *uuid = NULL; + StartupCompleteData *scd; + const char *uuid; - if (priv->started) { - if (!priv->startup_complete_idx) - return NULL; - if (priv->startup_complete_blocked_by) - uuid = nm_settings_connection_get_uuid (priv->startup_complete_blocked_by); - } - return uuid ?: "unknown"; + if (priv->startup_complete_start_timestamp_msec == 0) + goto out_done; + + if (force_reload) + _startup_complete_check (self, 0); + + if (c_list_is_empty (&priv->startup_complete_scd_lst_head)) + goto out_done; + + scd = c_list_first_entry (&priv->startup_complete_scd_lst_head, StartupCompleteData, scd_lst); + + nm_assert (scd); + nm_assert (NM_IS_SETTINGS_CONNECTION (scd->sett_conn)); + nm_assert (scd == nm_g_hash_table_lookup (priv->startup_complete_idx, &scd->sett_conn)); + + uuid = nm_settings_connection_get_uuid (scd->sett_conn); + if (uuid) + return uuid; + + g_return_val_if_reached ("settings-starting"); + +out_done: + if (!priv->started) + return "settings-starting"; + return NULL; } /*****************************************************************************/ @@ -1138,8 +1162,7 @@ _connection_changed_update (NMSettings *self, _emit_connection_updated (self, sett_conn, update_reason); } - if ( !priv->started - || priv->startup_complete_idx) { + if (priv->startup_complete_start_timestamp_msec != 0) { if (nm_settings_has_connection (self, sett_conn)) _startup_complete_notify_connection (self, sett_conn, FALSE); } @@ -1213,8 +1236,7 @@ _connection_changed_delete (NMSettings *self, nm_key_file_db_remove_key (priv->kf_db_timestamps, uuid); nm_key_file_db_remove_key (priv->kf_db_seen_bssids, uuid); - if ( !priv->started - || priv->startup_complete_idx) + if (priv->startup_complete_start_timestamp_msec != 0) _startup_complete_notify_connection (self, sett_conn, TRUE); } @@ -3711,6 +3733,8 @@ nm_settings_start (NMSettings *self, GError **error) nm_assert (!priv->started); + priv->startup_complete_start_timestamp_msec = nm_utils_get_monotonic_timestamp_msec (); + priv->hostname_manager = g_object_ref (nm_hostname_manager_get ()); priv->kf_db_timestamps = nm_key_file_db_new (NMSTATEDIR "/timestamps", @@ -3797,7 +3821,27 @@ get_property (GObject *object, guint prop_id, g_value_take_boxed (value, nm_utils_strv_make_deep_copied (strv)); break; case PROP_STARTUP_COMPLETE: - g_value_set_boolean (value, !nm_settings_get_startup_complete_blocked_reason (self)); + g_value_set_boolean (value, !nm_settings_get_startup_complete_blocked_reason (self, FALSE)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettings *self = NM_SETTINGS (object); + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + + switch (prop_id) { + case PROP_MANAGER: + /* construct-only */ + priv->manager = g_value_get_pointer (value); + nm_assert (NM_IS_MANAGER (priv->manager)); + g_object_add_weak_pointer (G_OBJECT (priv->manager), (gpointer *) &priv->manager); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -3814,6 +3858,7 @@ nm_settings_init (NMSettings *self) c_list_init (&priv->auth_lst_head); c_list_init (&priv->connections_lst_head); + c_list_init (&priv->startup_complete_scd_lst_head); c_list_init (&priv->sce_dirty_lst_head); priv->sce_idx = g_hash_table_new_full (nm_pstr_hash, nm_pstr_equal, @@ -3833,9 +3878,13 @@ nm_settings_init (NMSettings *self) } NMSettings * -nm_settings_new (void) +nm_settings_new (NMManager *manager) { - return g_object_new (NM_TYPE_SETTINGS, NULL); + nm_assert (NM_IS_MANAGER (manager)); + + return g_object_new (NM_TYPE_SETTINGS, + NM_SETTINGS_MANAGER, manager, + NULL); } static void @@ -3849,9 +3898,8 @@ dispose (GObject *object) nm_assert (g_hash_table_size (priv->sce_idx) == 0); nm_clear_g_source (&priv->startup_complete_timeout_id); - nm_clear_g_signal_handler (priv->platform, &priv->startup_complete_platform_change_id); nm_clear_pointer (&priv->startup_complete_idx, g_hash_table_destroy); - g_clear_object (&priv->startup_complete_blocked_by); + nm_assert (c_list_is_empty (&priv->startup_complete_scd_lst_head)); while ((iter = c_list_first (&priv->auth_lst_head))) nm_auth_chain_destroy (nm_auth_chain_parent_lst_entry (iter)); @@ -3915,6 +3963,11 @@ finalize (GObject *object) g_clear_object (&priv->config); g_clear_object (&priv->platform); + + if (priv->manager) { + g_object_remove_weak_pointer (G_OBJECT (priv->manager), (gpointer *) &priv->manager); + priv->manager = NULL; + } } static const GDBusSignalInfo signal_info_new_connection = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( @@ -4051,9 +4104,16 @@ nm_settings_class_init (NMSettingsClass *class) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_settings); object_class->get_property = get_property; + object_class->set_property = set_property; object_class->dispose = dispose; object_class->finalize = finalize; + obj_properties[PROP_MANAGER] = + g_param_spec_pointer (NM_SETTINGS_MANAGER, "", "", + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_UNMANAGED_SPECS] = g_param_spec_boxed (NM_SETTINGS_UNMANAGED_SPECS, "", "", G_TYPE_STRV, diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index aa7e36e0..35c62ff7 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -26,6 +26,7 @@ #define NM_SETTINGS_CAN_MODIFY "can-modify" #define NM_SETTINGS_CONNECTIONS "connections" #define NM_SETTINGS_STARTUP_COMPLETE "startup-complete" +#define NM_SETTINGS_MANAGER "manager" #define NM_SETTINGS_SIGNAL_CONNECTION_ADDED "connection-added" #define NM_SETTINGS_SIGNAL_CONNECTION_UPDATED "connection-updated" @@ -53,7 +54,7 @@ GType nm_settings_get_type (void); NMSettings *nm_settings_get (void); #define NM_SETTINGS_GET (nm_settings_get ()) -NMSettings *nm_settings_new (void); +NMSettings *nm_settings_new (NMManager *manager); gboolean nm_settings_start (NMSettings *self, GError **error); @@ -122,7 +123,8 @@ void nm_settings_device_added (NMSettings *self, NMDevice *device); void nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quitting); -const char *nm_settings_get_startup_complete_blocked_reason (NMSettings *self); +const char *nm_settings_get_startup_complete_blocked_reason (NMSettings *self, + gboolean force_reload); void nm_settings_kf_db_write (NMSettings *settings); diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.c b/src/settings/plugins/keyfile/nms-keyfile-reader.c index 577709d8..0e9ad5fa 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-reader.c +++ b/src/settings/plugins/keyfile/nms-keyfile-reader.c @@ -171,6 +171,7 @@ nms_keyfile_reader_from_file (const char *full_filename, NM_SET_OUT (out_is_nm_generated, NM_TERNARY_DEFAULT); NM_SET_OUT (out_is_volatile, NM_TERNARY_DEFAULT); NM_SET_OUT (out_is_external, NM_TERNARY_DEFAULT); + NM_SET_OUT (out_shadowed_owned, NM_TERNARY_DEFAULT); if (!nms_keyfile_utils_check_file_permissions (NMS_KEYFILE_FILETYPE_KEYFILE, full_filename, diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h index b0d1216e..068dcade 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h @@ -109,8 +109,9 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, struct in6_addr **addrs, size_t count, size_t *allocated); -int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, - char ***str_arr); +int dhcp6_option_parse_domainname_list(const uint8_t *optval, uint16_t optlen, + char ***str_arr); +int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str); int dhcp6_network_bind_udp_socket(int index, struct in6_addr *address); int dhcp6_network_send_udp_socket(int s, struct in6_addr *address, diff --git a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h index e004f48b..df6c95e0 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h @@ -35,6 +35,7 @@ struct sd_dhcp6_lease { size_t ntp_allocated; char **ntp_fqdn; size_t ntp_fqdn_count; + char *fqdn; }; int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire); @@ -57,5 +58,6 @@ int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval, int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen); int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) ; +int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen); int dhcp6_lease_new(sd_dhcp6_lease **ret); diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index d596752b..a6dad934 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -644,59 +644,103 @@ int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, return count; } -int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char ***str_arr) { - size_t pos = 0, idx = 0; - _cleanup_strv_free_ char **names = NULL; +static int parse_domain(const uint8_t **data, uint16_t *len, char **out_domain) { + _cleanup_free_ char *ret = NULL; + size_t n = 0, allocated = 0; + const uint8_t *optval = *data; + uint16_t optlen = *len; + bool first = true; int r; - assert_return(optlen > 1, -ENODATA); - assert_return(optval[optlen - 1] == '\0', -EINVAL); - - while (pos < optlen) { - _cleanup_free_ char *ret = NULL; - size_t n = 0, allocated = 0; - bool first = true; + if (optlen <= 1) + return -ENODATA; - for (;;) { - const char *label; - uint8_t c; + for (;;) { + const char *label; + uint8_t c; - c = optval[pos++]; + if (optlen == 0) + break; - if (c == 0) - /* End of name */ - break; - if (c > 63) - return -EBADMSG; + c = *optval; + optval++; + optlen--; - /* Literal label */ - label = (const char *)&optval[pos]; - pos += c; - if (pos >= optlen) - return -EMSGSIZE; + if (c == 0) + /* End label */ + break; + if (c > 63) + return -EBADMSG; + if (c > optlen) + return -EMSGSIZE; - if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) - return -ENOMEM; + /* Literal label */ + label = (const char *)optval; + optval += c; + optlen -= c; - if (first) - first = false; - else - ret[n++] = '.'; + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) + return -ENOMEM; - r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); - if (r < 0) - return r; + if (first) + first = false; + else + ret[n++] = '.'; - n += r; - } + r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; - if (n == 0) - continue; + n += r; + } + if (n) { if (!GREEDY_REALLOC(ret, allocated, n + 1)) return -ENOMEM; - ret[n] = 0; + } + + *out_domain = TAKE_PTR(ret); + *data = optval; + *len = optlen; + + return n; +} + +int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str) { + _cleanup_free_ char *domain = NULL; + int r; + + r = parse_domain(&optval, &optlen, &domain); + if (r < 0) + return r; + if (r == 0) + return -ENODATA; + if (optlen != 0) + return -EINVAL; + + *str = TAKE_PTR(domain); + return 0; +} + +int dhcp6_option_parse_domainname_list(const uint8_t *optval, uint16_t optlen, char ***str_arr) { + size_t idx = 0; + _cleanup_strv_free_ char **names = NULL; + int r; + + if (optlen <= 1) + return -ENODATA; + if (optval[optlen - 1] != '\0') + return -EINVAL; + + while (optlen > 0) { + _cleanup_free_ char *ret = NULL; + + r = parse_domain(&optval, &optlen, &ret); + if (r < 0) + return r; + if (r == 0) + continue; r = strv_extend(&names, ret); if (r < 0) diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index d653b257..b80e4e54 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -1288,6 +1288,13 @@ static int client_parse_message( break; + case SD_DHCP6_OPTION_FQDN: + r = dhcp6_lease_set_fqdn(lease, optval, optlen); + if (r < 0) + return r; + + break; + case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME: if (optlen != 4) return -EINVAL; diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c index b6dc0279..5f5a7fe6 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -238,7 +238,7 @@ int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval, if (!optlen) return 0; - r = dhcp6_option_parse_domainname(optval, optlen, &domains); + r = dhcp6_option_parse_domainname_list(optval, optlen, &domains); if (r < 0) return 0; @@ -296,8 +296,8 @@ int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { break; case DHCP6_NTP_SUBOPTION_SRV_FQDN: - r = dhcp6_option_parse_domainname(subval, sublen, - &servers); + r = dhcp6_option_parse_domainname_list(subval, sublen, + &servers); if (r < 0) return 0; @@ -367,6 +367,38 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) { return -ENOENT; } +int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, + size_t optlen) { + int r; + char *fqdn; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + if (optlen < 2) + return -ENODATA; + + /* Ignore the flags field, it doesn't carry any useful + information for clients. */ + r = dhcp6_option_parse_domainname(optval + 1, optlen - 1, &fqdn); + if (r < 0) + return r; + + return free_and_replace(lease->fqdn, fqdn); +} + +int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **fqdn) { + assert_return(lease, -EINVAL); + assert_return(fqdn, -EINVAL); + + if (lease->fqdn) { + *fqdn = lease->fqdn; + return 0; + } + + return -ENOENT; +} + static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) { assert(lease); @@ -375,6 +407,7 @@ static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) { dhcp6_lease_free_ia(&lease->pd); free(lease->dns); + free(lease->fqdn); lease->domains = strv_free(lease->domains); diff --git a/src/systemd/src/systemd/sd-dhcp6-lease.h b/src/systemd/src/systemd/sd-dhcp6-lease.h index 4301c6db..240df74a 100644 --- a/src/systemd/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/src/systemd/sd-dhcp6-lease.h @@ -43,6 +43,7 @@ int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **addrs) int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains); int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **addrs); int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn); +int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **fqdn); sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease); sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease); diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 6d995dc4..ff6b8e00 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -1447,6 +1447,20 @@ get_route_table (NMVpnConnection *self, return route_table ?: (fallback_main ? RT_TABLE_MAIN : 0); } +static gboolean +_is_device_vrf (NMVpnConnection *self) +{ + NMDevice *parent; + NMDevice *master; + + parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); + if (!parent) + return FALSE; + + master = nm_device_get_master (parent); + return master && nm_device_get_link_type (master) == NM_LINK_TYPE_VRF; +} + static void nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) { @@ -1646,6 +1660,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) nm_ip4_config_add_dependent_routes (config, route_table, nm_vpn_connection_get_ip4_route_metric (self), + _is_device_vrf (self), &priv->ip4_dev_route_blacklist); if (priv->ip4_config) { @@ -1840,9 +1855,7 @@ next: nm_ip6_config_add_route (config, &r, NULL); } - nm_ip6_config_add_dependent_routes (config, - route_table, - route_metric); + nm_ip6_config_add_dependent_routes (config, route_table, route_metric, _is_device_vrf (self)); if (priv->ip6_config) { nm_ip6_config_replace (priv->ip6_config, config, NULL); |