From 681dfc70ef98f6ed0c05bcb0fbff00e3fc0799ea Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Mon, 26 Aug 2024 16:10:34 +0200 Subject: New upstream version 1.48.10 --- src/core/devices/nm-device-bridge.c | 180 +++++++++++++++++++---- src/core/devices/nm-device-bridge.h | 2 + src/core/devices/nm-device.c | 2 + src/core/devices/nm-lldp-listener.c | 15 +- src/core/nm-policy.c | 275 ++++++++++++++++++++++++++++++------ 5 files changed, 395 insertions(+), 79 deletions(-) (limited to 'src/core') diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c index b256056d..7a496d96 100644 --- a/src/core/devices/nm-device-bridge.c +++ b/src/core/devices/nm-device-bridge.c @@ -13,6 +13,7 @@ #include "NetworkManagerUtils.h" #include "nm-device-private.h" #include "libnm-platform/nm-platform.h" +#include "libnm-platform/nm-platform-utils.h" #include "nm-device-factory.h" #include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-core-intern/nm-core-internal.h" @@ -419,20 +420,18 @@ static const Option controller_options[] = { 0, }}; -static const NMPlatformBridgeVlan ** -setting_vlans_to_platform(GPtrArray *array) +static NMPlatformBridgeVlan * +setting_vlans_to_platform(GPtrArray *array, guint *out_len) { - NMPlatformBridgeVlan **arr; - NMPlatformBridgeVlan *p_data; - guint i; + NMPlatformBridgeVlan *arr; + guint i; - if (!array || !array->len) + if (!array || !array->len) { + *out_len = 0; return NULL; + } - G_STATIC_ASSERT_EXPR(_nm_alignof(NMPlatformBridgeVlan *) >= _nm_alignof(NMPlatformBridgeVlan)); - arr = g_malloc((sizeof(NMPlatformBridgeVlan *) * (array->len + 1)) - + (sizeof(NMPlatformBridgeVlan) * (array->len))); - p_data = (NMPlatformBridgeVlan *) &arr[array->len + 1]; + arr = g_new(NMPlatformBridgeVlan, array->len); for (i = 0; i < array->len; i++) { NMBridgeVlan *vlan = array->pdata[i]; @@ -440,16 +439,16 @@ setting_vlans_to_platform(GPtrArray *array) nm_bridge_vlan_get_vid_range(vlan, &vid_start, &vid_end); - p_data[i] = (NMPlatformBridgeVlan){ + arr[i] = (NMPlatformBridgeVlan){ .vid_start = vid_start, .vid_end = vid_end, .pvid = nm_bridge_vlan_is_pvid(vlan), .untagged = nm_bridge_vlan_is_untagged(vlan), }; - arr[i] = &p_data[i]; } - arr[i] = NULL; - return (const NMPlatformBridgeVlan **) arr; + + *out_len = array->len; + return arr; } static void @@ -639,15 +638,16 @@ is_bridge_pvid_changed(NMDevice *device, NMSettingBridge *s_bridge) static gboolean bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge, gboolean is_reapply) { - NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); - gconstpointer hwaddr; - size_t length; - gboolean enabled; - guint16 pvid; - NMPlatform *plat; - int ifindex; - gs_unref_ptrarray GPtrArray *vlans = NULL; - gs_free const NMPlatformBridgeVlan **plat_vlans = NULL; + NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); + gconstpointer hwaddr; + size_t length; + gboolean enabled; + guint16 pvid; + NMPlatform *plat; + int ifindex; + gs_unref_ptrarray GPtrArray *vlans = NULL; + gs_free NMPlatformBridgeVlan *plat_vlans = NULL; + guint num_vlans; if (self->vlan_configured) return TRUE; @@ -664,7 +664,7 @@ bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge, gboolean is .vlan_filtering_val = FALSE, .vlan_default_pvid_has = TRUE, .vlan_default_pvid_val = 1})); - nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, NULL); + nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, NULL, 0); return TRUE; } @@ -696,7 +696,7 @@ bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge, gboolean is .vlan_default_pvid_val = 0})); /* Clear all existing VLANs */ - if (!nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, NULL)) + if (!nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, NULL, 0)) return FALSE; /* Now set the default PVID. After this point the kernel creates @@ -714,8 +714,9 @@ bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge, gboolean is /* Create VLANs only after setting the default PVID, so that * any PVID VLAN overrides the bridge's default PVID. */ g_object_get(s_bridge, NM_SETTING_BRIDGE_VLANS, &vlans, NULL); - plat_vlans = setting_vlans_to_platform(vlans); - if (plat_vlans && !nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, plat_vlans)) + plat_vlans = setting_vlans_to_platform(vlans, &num_vlans); + if (plat_vlans + && !nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, plat_vlans, num_vlans)) return FALSE; nm_platform_link_set_bridge_info(plat, @@ -728,6 +729,121 @@ bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge, gboolean is return TRUE; } +static NMPlatformBridgeVlan * +merge_bridge_vlan_default_pvid(NMPlatformBridgeVlan *vlans, guint *num_vlans, guint default_pvid) +{ + NMPlatformBridgeVlan *vlan; + gboolean has_pvid = FALSE; + guint i; + + for (i = 0; i < *num_vlans; i++) { + if (vlans[i].pvid) { + has_pvid = TRUE; + break; + } + } + + /* search if the list of VLANs already contains the default PVID */ + vlan = NULL; + for (i = 0; i < *num_vlans; i++) { + if (default_pvid >= vlans[i].vid_start && default_pvid <= vlans[i].vid_end) { + vlan = &vlans[i]; + break; + } + } + + if (!vlan) { + /* VLAN id not found, append the default PVID at the end. + * Set the PVID flag only if the port didn't have one. */ + vlans = g_realloc_n(vlans, *num_vlans + 1, sizeof(NMPlatformBridgeVlan)); + (*num_vlans)++; + vlans[*num_vlans - 1] = (NMPlatformBridgeVlan){ + .vid_start = default_pvid, + .vid_end = default_pvid, + .untagged = TRUE, + .pvid = !has_pvid, + }; + } + + return vlans; +} + +void +nm_device_reapply_bridge_port_vlans(NMDevice *device) +{ + NMDevice *self = device; /* for logging */ + NMSettingBridgePort *s_bridge_port; + NMDevice *controller; + NMSettingBridge *s_bridge; + gs_unref_ptrarray GPtrArray *tmp_vlans = NULL; + gs_free NMPlatformBridgeVlan *setting_vlans = NULL; + gs_free NMPlatformBridgeVlan *plat_vlans = NULL; + guint num_setting_vlans = 0; + guint num_plat_vlans = 0; + NMPlatform *plat; + int ifindex; + gboolean do_reapply; + + s_bridge_port = nm_device_get_applied_setting(device, NM_TYPE_SETTING_BRIDGE_PORT); + if (!s_bridge_port) + return; + + controller = nm_device_get_controller(device); + if (!controller) + return; + + s_bridge = nm_device_get_applied_setting(controller, NM_TYPE_SETTING_BRIDGE); + if (!s_bridge) + return; + + if (nm_setting_bridge_get_vlan_filtering(s_bridge)) { + g_object_get(s_bridge_port, NM_SETTING_BRIDGE_PORT_VLANS, &tmp_vlans, NULL); + setting_vlans = setting_vlans_to_platform(tmp_vlans, &num_setting_vlans); + + /* During a regular activation, we first set the default_pvid on the bridge + * (which creates the PVID VLAN on the port) and then add the VLANs on the port. + * This ensures that the PVID VLAN is inherited from the bridge, but it's + * overridden if the port specifies one. + * During a reapply on the port, we are not going to touch the bridge and + * so we need to merge manually the PVID from the bridge with the port VLANs. */ + setting_vlans = + merge_bridge_vlan_default_pvid(setting_vlans, + &num_setting_vlans, + nm_setting_bridge_get_vlan_default_pvid(s_bridge)); + } + + plat = nm_device_get_platform(device); + ifindex = nm_device_get_ifindex(device); + + if (!nm_platform_link_get_bridge_vlans(plat, ifindex, &plat_vlans, &num_plat_vlans)) { + _LOGD(LOGD_DEVICE, "reapply-bridge-port-vlans: can't get current VLANs from platform"); + do_reapply = TRUE; + } else { + nmp_utils_bridge_vlan_normalize(setting_vlans, &num_setting_vlans); + nmp_utils_bridge_vlan_normalize(plat_vlans, &num_plat_vlans); + if (!nmp_utils_bridge_normalized_vlans_equal(setting_vlans, + num_setting_vlans, + plat_vlans, + num_plat_vlans)) { + _LOGD(LOGD_DEVICE, "reapply-bridge-port-vlans: VLANs in platform need reapply"); + do_reapply = TRUE; + } else { + _LOGD(LOGD_DEVICE, "reapply-bridge-port-vlans: VLANs in platform didn't change"); + do_reapply = FALSE; + } + } + + if (do_reapply) { + nm_platform_link_set_bridge_vlans(plat, ifindex, TRUE, NULL, 0); + if (num_setting_vlans > 0) + nm_platform_link_set_bridge_vlans(plat, + ifindex, + TRUE, + setting_vlans, + num_setting_vlans); + } +} + static void _platform_lnk_bridge_init_from_setting(NMSettingBridge *s_bridge, NMPlatformLnkBridge *props) { @@ -937,13 +1053,14 @@ attach_port(NMDevice *device, bridge_set_vlan_options(device, s_bridge, FALSE); if (nm_setting_bridge_get_vlan_filtering(s_bridge)) { - gs_free const NMPlatformBridgeVlan **plat_vlans = NULL; - gs_unref_ptrarray GPtrArray *vlans = NULL; + gs_free NMPlatformBridgeVlan *plat_vlans = NULL; + gs_unref_ptrarray GPtrArray *vlans = NULL; + guint num_vlans; if (s_port) g_object_get(s_port, NM_SETTING_BRIDGE_PORT_VLANS, &vlans, NULL); - plat_vlans = setting_vlans_to_platform(vlans); + plat_vlans = setting_vlans_to_platform(vlans, &num_vlans); /* Since the link was just enportd, there are no existing VLANs * (except for the default one) and so there's no need to flush. */ @@ -952,7 +1069,8 @@ attach_port(NMDevice *device, && !nm_platform_link_set_bridge_vlans(nm_device_get_platform(port), nm_device_get_ifindex(port), TRUE, - plat_vlans)) + plat_vlans, + num_vlans)) return FALSE; } diff --git a/src/core/devices/nm-device-bridge.h b/src/core/devices/nm-device-bridge.h index 6d9f1614..f9be7580 100644 --- a/src/core/devices/nm-device-bridge.h +++ b/src/core/devices/nm-device-bridge.h @@ -27,4 +27,6 @@ extern const NMBtVTableNetworkServer *nm_bt_vtable_network_server; void _nm_device_bridge_notify_unregister_bt_nap(NMDevice *device, const char *reason); +void nm_device_reapply_bridge_port_vlans(NMDevice *device); + #endif /* __NETWORKMANAGER_DEVICE_BRIDGE_H__ */ diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 725241d5..799aca04 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -13881,6 +13881,8 @@ check_and_reapply_connection(NMDevice *self, if (priv->state >= NM_DEVICE_STATE_ACTIVATED) nm_device_update_metered(self); + nm_device_reapply_bridge_port_vlans(self); + sett_conn = nm_device_get_settings_connection(self); if (sett_conn) { nm_settings_connection_autoconnect_blocked_reason_set( diff --git a/src/core/devices/nm-lldp-listener.c b/src/core/devices/nm-lldp-listener.c index ac7e97f0..59c8f54c 100644 --- a/src/core/devices/nm-lldp-listener.c +++ b/src/core/devices/nm-lldp-listener.c @@ -704,9 +704,16 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) /*****************************************************************************/ +static void +nmtst_lldp_event_handler(NMLldpRX *lldp, NMLldpRXEvent event, NMLldpNeighbor *n, void *user_data) +{ + g_assert_not_reached(); +} + GVariant * nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len) { + nm_auto(nm_lldp_rx_unrefp) NMLldpRX *lldp_rx = NULL; nm_auto(nm_lldp_neighbor_unrefp) NMLldpNeighbor *neighbor_nm = NULL; nm_auto(lldp_neighbor_freep) LldpNeighbor *neigh = NULL; GVariant *variant; @@ -714,7 +721,13 @@ nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len) g_assert(raw_data); g_assert(raw_len > 0); - neighbor_nm = nm_lldp_neighbor_new_from_raw(raw_data, raw_len); + lldp_rx = nm_lldp_rx_new(&((NMLldpRXConfig){ + .ifindex = 1, + .neighbors_max = MAX_NEIGHBORS, + .callback = nmtst_lldp_event_handler, + })); + + neighbor_nm = nm_lldp_neighbor_new_from_raw(lldp_rx, raw_data, raw_len); g_assert(neighbor_nm); neigh = lldp_neighbor_new(neighbor_nm); diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index 694f5905..93b52526 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -17,6 +17,7 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device.h" +#include "devices/nm-device-factory.h" #include "dns/nm-dns-manager.h" #include "nm-act-request.h" #include "nm-auth-utils.h" @@ -47,6 +48,10 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMPolicy, PROP_ACTIVATING_IP4_AC, PROP_ACTIVATING_IP6_AC, ); +#define HOSTNAME_RETRY_INTERVAL_MIN 30U +#define HOSTNAME_RETRY_INTERVAL_MAX (60U * 60 * 12) /* 12 hours */ +#define HOSTNAME_RETRY_INTERVAL_MULTIPLIER 8U + typedef struct { NMManager *manager; NMNetns *netns; @@ -78,14 +83,21 @@ typedef struct { char *orig_hostname; /* hostname at NM start time */ char *cur_hostname; /* hostname we want to assign */ char *cur_hostname_full; /* similar to @last_hostname, but before shortening */ - char * - last_hostname; /* last hostname NM set (to detect if someone else changed it in the meanwhile) */ + char *last_hostname; /* last hostname NM set (to detect if someone else + * changed it in the meanwhile) */ + struct { + GSource *source; + guint interval_sec; + gboolean do_restart; /* when something changes, set this to TRUE so that the next retry + * will restart from the lowest timeout. */ + } hostname_retry; bool changing_hostname : 1; /* hostname set operation in progress */ bool dhcp_hostname : 1; /* current hostname was set from dhcp */ bool updating_dns : 1; GArray *ip6_prefix_delegations; /* pool of ip6 prefixes delegated to all devices */ + } NMPolicyPrivate; struct _NMPolicy { @@ -134,9 +146,10 @@ _PRIV_TO_SELF(NMPolicyPrivate *priv) /*****************************************************************************/ -static void update_system_hostname(NMPolicy *self, const char *msg); -static void nm_policy_device_recheck_auto_activate_all_schedule(NMPolicy *self); +static void update_system_hostname(NMPolicy *self, const char *msg, gboolean reset_retry_interval); +static void nm_policy_device_recheck_auto_activate_all_schedule(NMPolicy *self); static NMDevice *get_default_device(NMPolicy *self, int addr_family); +static gboolean hostname_retry_cb(gpointer user_data); /*****************************************************************************/ @@ -557,7 +570,56 @@ _get_hostname(NMPolicy *self) } static void -_set_hostname(NMPolicy *self, const char *new_hostname, const char *msg) +hostname_retry_schedule(NMPolicy *self) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); + + if (priv->hostname_retry.source && !priv->hostname_retry.do_restart) + return; + + nm_clear_g_source_inst(&priv->hostname_retry.source); + + if (priv->hostname_retry.do_restart) + priv->hostname_retry.interval_sec = 0; + + priv->hostname_retry.interval_sec *= HOSTNAME_RETRY_INTERVAL_MULTIPLIER; + priv->hostname_retry.interval_sec = NM_CLAMP(priv->hostname_retry.interval_sec, + HOSTNAME_RETRY_INTERVAL_MIN, + HOSTNAME_RETRY_INTERVAL_MAX); + + _LOGT(LOGD_DNS, + "hostname-retry: schedule in %u seconds%s", + priv->hostname_retry.interval_sec, + priv->hostname_retry.do_restart ? " (restarted)" : ""); + priv->hostname_retry.source = + nm_g_timeout_add_seconds_source(priv->hostname_retry.interval_sec, hostname_retry_cb, self); + + priv->hostname_retry.do_restart = FALSE; +} + +static gboolean +hostname_retry_cb(gpointer user_data) +{ + NMPolicy *self = NM_POLICY(user_data); + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); + const CList *tmp_lst; + NMDevice *device; + + _LOGT(LOGD_DNS, "hostname-retry: timeout"); + + nm_clear_g_source_inst(&priv->hostname_retry.source); + + /* Clear any cached DNS results before retrying */ + nm_manager_for_each_device (priv->manager, device, tmp_lst) { + nm_device_clear_dns_lookup_data(device, "hostname retry timeout"); + } + update_system_hostname(self, "hostname retry timeout", FALSE); + + return G_SOURCE_CONTINUE; +} + +static void +_set_hostname(NMPolicy *self, const char *new_hostname, const char *msg, gboolean do_retry) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); gs_free char *old_hostname = NULL; @@ -611,6 +673,15 @@ _set_hostname(NMPolicy *self, const char *new_hostname, const char *msg) priv->updating_dns = FALSE; } + if (!do_retry) { + _LOGT(LOGD_DNS, "hostname-retry: clear"); + nm_clear_g_source_inst(&priv->hostname_retry.source); + priv->hostname_retry.interval_sec = 0; + priv->hostname_retry.do_restart = FALSE; + } else if (!priv->hostname_retry.source) { + hostname_retry_schedule(self); + } + /* Finally, set kernel hostname */ nm_assert(!priv->cur_hostname || priv->cur_hostname[0]); name = priv->cur_hostname ?: FALLBACK_HOSTNAME4; @@ -796,7 +867,7 @@ device_dns_lookup_done(NMDevice *device, gpointer user_data) g_signal_handlers_disconnect_by_func(device, device_dns_lookup_done, self); - update_system_hostname(self, "lookup finished"); + update_system_hostname(self, "lookup finished", FALSE); } static void @@ -809,12 +880,28 @@ device_carrier_changed(NMDevice *device, GParamSpec *pspec, gpointer user_data) if (nm_device_has_carrier(device)) { g_signal_handlers_disconnect_by_func(device, device_carrier_changed, priv); msg = g_strdup_printf("device '%s' got carrier", nm_device_get_iface(device)); - update_system_hostname(self, msg); + update_system_hostname(self, msg, TRUE); } } +/* + * This function evaluates different sources (static configuration, DHCP, DNS, ...) + * to set the system hostname. + * + * When the function needs to perform a blocking action like a DNS resolution, it + * subscribes to a signal for the completion event, registering a callback that + * invokes this function again. In the new invocation, any previous DNS result is + * cached and doesn't need a new resolution. + * + * In case no hostname is found when after sources have been evaluated, it schedules + * a timer to retry later with an interval that is increased at each attempt. When + * this function is called after something changed (for example, carrier went up, a + * new address was added), @reset_retry_interval should be set to TRUE so that the + * next retry will use the smallest interval. In this way, it can quickly adapt to + * temporary misconfigurations at boot or when the network environment changes. + */ static void -update_system_hostname(NMPolicy *self, const char *msg) +update_system_hostname(NMPolicy *self, const char *msg, gboolean reset_retry_interval) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); const char *configured_hostname; @@ -829,6 +916,9 @@ update_system_hostname(NMPolicy *self, const char *msg) g_return_if_fail(self != NULL); + if (reset_retry_interval) + priv->hostname_retry.do_restart = TRUE; + if (priv->hostname_mode == NM_POLICY_HOSTNAME_MODE_NONE) { _LOGT(LOGD_DNS, "set-hostname: hostname is unmanaged"); return; @@ -871,7 +961,7 @@ update_system_hostname(NMPolicy *self, const char *msg) /* Try a persistent hostname first */ configured_hostname = nm_hostname_manager_get_static_hostname(priv->hostname_manager); if (configured_hostname && nm_utils_is_specific_hostname(configured_hostname)) { - _set_hostname(self, configured_hostname, "from system configuration"); + _set_hostname(self, configured_hostname, "from system configuration", FALSE); priv->dhcp_hostname = FALSE; return; } @@ -908,7 +998,10 @@ update_system_hostname(NMPolicy *self, const char *msg) if (dhcp_hostname && dhcp_hostname[0]) { p = nm_str_skip_leading_spaces(dhcp_hostname); if (p[0]) { - _set_hostname(self, p, info->IS_IPv4 ? "from DHCPv4" : "from DHCPv6"); + _set_hostname(self, + p, + info->IS_IPv4 ? "from DHCPv4" : "from DHCPv6", + FALSE); priv->dhcp_hostname = TRUE; return; } @@ -936,7 +1029,7 @@ update_system_hostname(NMPolicy *self, const char *msg) priv); } if (result) { - _set_hostname(self, result, "from address lookup"); + _set_hostname(self, result, "from address lookup", FALSE); return; } if (wait) { @@ -951,8 +1044,10 @@ update_system_hostname(NMPolicy *self, const char *msg) } /* If an hostname was set outside NetworkManager keep it */ - if (external_hostname) + if (external_hostname) { + hostname_retry_schedule(self); return; + } if (priv->hostname_mode == NM_POLICY_HOSTNAME_MODE_DHCP) { /* In dhcp hostname-mode, the hostname is updated only if it comes from @@ -961,7 +1056,7 @@ update_system_hostname(NMPolicy *self, const char *msg) * so reset the hostname to the previous value */ if (priv->dhcp_hostname) { - _set_hostname(self, priv->orig_hostname, "reset dhcp hostname"); + _set_hostname(self, priv->orig_hostname, "reset dhcp hostname", TRUE); priv->dhcp_hostname = FALSE; } return; @@ -973,11 +1068,11 @@ update_system_hostname(NMPolicy *self, const char *msg) * set externally to NM */ if (priv->orig_hostname) { - _set_hostname(self, priv->orig_hostname, "from system startup"); + _set_hostname(self, priv->orig_hostname, "from system startup", TRUE); return; } - _set_hostname(self, NULL, "no hostname found"); + _set_hostname(self, NULL, "no hostname found", TRUE); } static void @@ -1254,7 +1349,7 @@ update_routing_and_dns(NMPolicy *self, gboolean force_update, NMDevice *changed_ update_ip6_routing(self, force_update); /* Update the system hostname */ - update_system_hostname(self, "routing and dns"); + update_system_hostname(self, "routing and dns", FALSE); nm_dns_manager_end_updates(priv->dns_manager, __func__); } @@ -1571,7 +1666,7 @@ _static_hostname_changed_cb(NMHostnameManager *hostname_manager, NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF(priv); - update_system_hostname(self, "hostname changed"); + update_system_hostname(self, "hostname changed", FALSE); } void @@ -1773,6 +1868,74 @@ _connection_autoconnect_retries_set(NMPolicy *self, } } +static void +unblock_autoconnect_for_children(NMPolicy *self, + const char *parent_device, + const char *parent_uuid_settings, + const char *parent_uuid_applied, + const char *parent_mac_addr, + gboolean reset_devcon_autoconnect) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); + NMSettingsConnection *const *connections; + gboolean changed; + guint i; + + _LOGT(LOGD_CORE, + "block-autoconnect: unblocking child profiles for parent ifname=%s%s%s, uuid=%s%s%s" + "%s%s%s", + NM_PRINT_FMT_QUOTE_STRING(parent_device), + NM_PRINT_FMT_QUOTE_STRING(parent_uuid_settings), + NM_PRINT_FMT_QUOTED(parent_uuid_applied, + ", applied-uuid=\"", + parent_uuid_applied, + "\"", + "")); + + changed = FALSE; + connections = nm_settings_get_connections(priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *sett_conn = connections[i]; + NMConnection *connection; + NMDeviceFactory *factory; + const char *parent_name = NULL; + + connection = nm_settings_connection_get_connection(sett_conn); + factory = nm_device_factory_manager_find_factory_for_connection(connection); + if (factory) + parent_name = nm_device_factory_get_connection_parent(factory, connection); + + if (!parent_name) + continue; + + if (!NM_IN_STRSET(parent_name, + parent_device, + parent_uuid_applied, + parent_uuid_settings, + parent_mac_addr)) + continue; + + if (reset_devcon_autoconnect) { + if (nm_manager_devcon_autoconnect_retries_reset(priv->manager, NULL, sett_conn)) + changed = TRUE; + } + + /* unblock the devices associated with that connection */ + if (nm_manager_devcon_autoconnect_blocked_reason_set( + priv->manager, + NULL, + sett_conn, + NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_FAILED, + FALSE)) { + if (!nm_settings_connection_autoconnect_is_blocked(sett_conn)) + changed = TRUE; + } + } + + if (changed) + nm_policy_device_recheck_auto_activate_all_schedule(self); +} + static void unblock_autoconnect_for_ports(NMPolicy *self, const char *controller_device, @@ -1856,16 +2019,21 @@ unblock_autoconnect_for_ports_for_sett_conn(NMPolicy *self, NMSettingsConnection } static void -activate_slave_connections(NMPolicy *self, NMDevice *device) -{ - const char *master_device; - const char *master_uuid_settings = NULL; - const char *master_uuid_applied = NULL; +activate_port_or_children_connections(NMPolicy *self, + NMDevice *device, + gboolean activate_children_connections_only) +{ + const char *controller_device; + const char *controller_uuid_settings = NULL; + const char *controller_uuid_applied = NULL; + const char *parent_mac_addr = NULL; NMActRequest *req; gboolean internal_activation = FALSE; - master_device = nm_device_get_iface(device); - nm_assert(master_device); + controller_device = nm_device_get_iface(device); + nm_assert(controller_device); + + parent_mac_addr = nm_device_get_permanent_hw_address(device); req = nm_device_get_act_request(device); if (req) { @@ -1875,25 +2043,33 @@ activate_slave_connections(NMPolicy *self, NMDevice *device) sett_conn = nm_active_connection_get_settings_connection(NM_ACTIVE_CONNECTION(req)); if (sett_conn) - master_uuid_settings = nm_settings_connection_get_uuid(sett_conn); + controller_uuid_settings = nm_settings_connection_get_uuid(sett_conn); connection = nm_active_connection_get_applied_connection(NM_ACTIVE_CONNECTION(req)); if (connection) - master_uuid_applied = nm_connection_get_uuid(connection); + controller_uuid_applied = nm_connection_get_uuid(connection); - if (nm_streq0(master_uuid_settings, master_uuid_applied)) - master_uuid_applied = NULL; + if (nm_streq0(controller_uuid_settings, controller_uuid_applied)) + controller_uuid_applied = NULL; subject = nm_active_connection_get_subject(NM_ACTIVE_CONNECTION(req)); internal_activation = subject && (nm_auth_subject_get_subject_type(subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL); } - unblock_autoconnect_for_ports(self, - master_device, - master_uuid_settings, - master_uuid_applied, - !internal_activation); + if (!activate_children_connections_only) { + unblock_autoconnect_for_ports(self, + controller_device, + controller_uuid_settings, + controller_uuid_applied, + !internal_activation); + } + unblock_autoconnect_for_children(self, + controller_device, + controller_uuid_settings, + controller_uuid_applied, + parent_mac_addr, + !internal_activation); } static gboolean @@ -2061,13 +2237,12 @@ device_state_changed(NMDevice *device, } break; case 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. + /* A connection that fails due to dependency-failed is not able to + * reconnect until the connection it depends on activates again; + * when this happens, the controller or parent clears the blocked + * reason for all its dependent devices in activate_port_or_children_connections() + * and tries to reconnect them. For this to work, the port should + * be marked as blocked when it fails with dependency-failed. */ _LOGD(LOGD_DEVICE, "block-autoconnect: connection[%p] (%s) now blocked from autoconnect due to " @@ -2111,6 +2286,11 @@ device_state_changed(NMDevice *device, } break; case NM_DEVICE_STATE_ACTIVATED: + if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_OVS_INTERFACE) { + /* When parent is ovs-interface, the kernel link is only created in stage3, we have to + * delay unblocking the children and schedule them for activation until parent is activated */ + activate_port_or_children_connections(self, device, TRUE); + } if (sett_conn) { /* Reset auto retries back to default since connection was successful */ nm_manager_devcon_autoconnect_retries_reset(priv->manager, device, sett_conn); @@ -2133,7 +2313,7 @@ device_state_changed(NMDevice *device, update_ip_dns(self, AF_INET6, device); update_ip4_routing(self, TRUE); update_ip6_routing(self, TRUE); - update_system_hostname(self, "routing and dns"); + update_system_hostname(self, "routing and dns", TRUE); nm_dns_manager_end_updates(priv->dns_manager, __func__); break; @@ -2195,9 +2375,9 @@ device_state_changed(NMDevice *device, break; case NM_DEVICE_STATE_PREPARE: - /* Reset auto-connect retries of all slaves and schedule them for + /* Reset auto-connect retries of all ports or children and schedule them for * activation. */ - activate_slave_connections(self, device); + activate_port_or_children_connections(self, device, FALSE); /* Now that the device state is progressing, we don't care * anymore for the AC state. */ @@ -2281,7 +2461,7 @@ device_l3cd_changed(NMDevice *device, update_ip6_routing(self, TRUE); /* FIXME: since we already monitor platform addresses changes, * this is probably no longer necessary? */ - update_system_hostname(self, "ip conf"); + update_system_hostname(self, "ip conf", FALSE); } else { nm_dns_manager_set_ip_config(priv->dns_manager, AF_UNSPEC, @@ -2303,7 +2483,7 @@ device_platform_address_changed(NMDevice *device, gpointer user_data) state = nm_device_get_state(device); if (state > NM_DEVICE_STATE_DISCONNECTED && state < NM_DEVICE_STATE_DEACTIVATING) { - update_system_hostname(self, "address changed"); + update_system_hostname(self, "address changed", TRUE); } } @@ -2642,7 +2822,7 @@ dns_config_changed(NMDnsManager *dns_manager, gpointer user_data) nm_device_clear_dns_lookup_data(device, "DNS configuration changed"); } - update_system_hostname(self, "DNS configuration changed"); + update_system_hostname(self, "DNS configuration changed", FALSE); } nm_dispatcher_call_dns_change(); @@ -2913,7 +3093,7 @@ constructed(GObject *object) G_OBJECT_CLASS(nm_policy_parent_class)->constructed(object); _LOGD(LOGD_DNS, "hostname-mode: %s", _hostname_mode_to_string(priv->hostname_mode)); - update_system_hostname(self, "initial hostname"); + update_system_hostname(self, "initial hostname", FALSE); } NMPolicy * @@ -2971,6 +3151,7 @@ dispose(GObject *object) nm_clear_g_source_inst(&priv->reset_connections_retries_idle_source); nm_clear_g_source_inst(&priv->device_recheck_auto_activate_all_idle_source); + nm_clear_g_source_inst(&priv->hostname_retry.source); nm_clear_g_free(&priv->orig_hostname); nm_clear_g_free(&priv->cur_hostname); -- cgit 1.3.0-6-gf8a5