diff options
| author | Michael Biebl <biebl@debian.org> | 2023-03-09 20:01:53 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2023-03-09 20:01:53 +0100 |
| commit | cffb548b401e2cd3fad166aa92e0f634bbb1d4d6 (patch) | |
| tree | 6d803d8f7d0d92a1c5e5705974fff8975472af95 /src/core/devices/nm-device.c | |
| parent | 647d6b95d5475e0a1bf3d6f299d1cb8c9041a7a4 (diff) | |
| parent | 12e1ee797bbf0b10d1fd5afd4b947484769f2b9f (diff) | |
Merge tag 'debian/1.42.4-1' into debian/bullseye-backports
network-manager Debian release 1.42.4-1
Diffstat (limited to 'src/core/devices/nm-device.c')
| -rw-r--r-- | src/core/devices/nm-device.c | 478 |
1 files changed, 294 insertions, 184 deletions
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index c4f0f9a2..3565c04d 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -18,7 +18,7 @@ #include <netinet/in.h> #include <netinet/if_ether.h> #include <linux/if.h> -#include <linux/if_addr.h> +#include "nm-compat-headers/linux/if_addr.h" #include <linux/rtnetlink.h> #include <linux/if_ether.h> #include <linux/if_infiniband.h> @@ -59,6 +59,7 @@ #include "settings/nm-settings.h" #include "nm-setting-ethtool.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "nm-setting-user.h" #include "nm-auth-utils.h" #include "nm-keep-alive.h" @@ -77,6 +78,7 @@ #include "nm-device-generic.h" #include "nm-device-bridge.h" +#include "nm-device-loopback.h" #include "nm-device-vlan.h" #include "nm-device-vrf.h" #include "nm-device-wireguard.h" @@ -110,6 +112,7 @@ typedef enum { CLEANUP_TYPE_KEEP, CLEANUP_TYPE_REMOVED, CLEANUP_TYPE_DECONFIGURE, + CLEANUP_TYPE_KEEP_REAPPLY, } CleanupType; typedef enum _nm_packed { @@ -309,7 +312,7 @@ typedef struct { typedef enum { RESOLVER_WAIT_ADDRESS = 0, - RESOLVER_IN_PROGRESS, + RESOLVER_STARTED, RESOLVER_DONE, } ResolverState; @@ -848,7 +851,7 @@ static void _dev_ipshared4_spawn_dnsmasq(NMDevice *self); static void _dev_ipshared6_start(NMDevice *self); static void -_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean from_reapply); +_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean preserve_dhcp); static void concheck_update_state(NMDevice *self, int addr_family, @@ -1583,6 +1586,9 @@ _prop_get_ipv4_link_local(NMDevice *self) if (!s_ip4) return NM_SETTING_IP4_LL_DISABLED; + if (NM_IS_DEVICE_LOOPBACK(self)) + return NM_SETTING_IP4_LL_DISABLED; + link_local = nm_setting_ip4_config_get_link_local(s_ip4); if (link_local == NM_SETTING_IP4_LL_DEFAULT) { @@ -1804,6 +1810,7 @@ _prop_get_ipvx_dhcp_iaid(NMDevice *self, const char *iface; const char *fail_reason; gboolean is_explicit = TRUE; + gint64 i64; s_ip = nm_connection_get_setting_ip_config(connection, addr_family); iaid_str = nm_setting_ip_config_get_dhcp_iaid(s_ip); @@ -1862,7 +1869,7 @@ _prop_get_ipvx_dhcp_iaid(NMDevice *self, iaid = unaligned_read_be32(&hwaddr_buf[hwaddr_len - 4]); goto out_good; - } else if (nm_streq(iaid_str, "stable")) { + } else if (nm_streq(iaid_str, NM_IAID_STABLE)) { nm_auto_free_checksum GChecksum *sum = NULL; guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; NMUtilsStableType stable_type; @@ -1885,14 +1892,21 @@ _prop_get_ipvx_dhcp_iaid(NMDevice *self, iaid = unaligned_read_be32(digest); goto out_good; - } else if ((iaid = _nm_utils_ascii_str_to_int64(iaid_str, 10, 0, G_MAXUINT32, -1)) != -1) { - goto out_good; - } else { + } else if (nm_streq(iaid_str, NM_IAID_IFNAME)) { iface = nm_device_get_ip_iface(self); iaid = nm_utils_create_dhcp_iaid(TRUE, (const guint8 *) iface, strlen(iface)); goto out_good; + } else if (_nm_utils_iaid_verify(iaid_str, &i64)) { + if (i64 < 0) { + fail_reason = nm_assert_unreachable_val("bug handling iaid value"); + goto out_fail; + } + nm_assert(i64 <= G_MAXUINT32); + iaid = (guint32) i64; + goto out_good; } + fail_reason = nm_assert_unreachable_val("bug handling iaid code"); out_fail: nm_assert(fail_reason); if (!log_silent) { @@ -1906,11 +1920,13 @@ out_fail: iaid = nm_utils_create_dhcp_iaid(TRUE, (const guint8 *) iface, strlen(iface)); out_good: if (!log_silent) { + char buf[NM_DHCP_IAID_TO_HEXSTR_BUF_LEN]; + _LOGD(LOGD_DEVICE | LOGD_DHCPX(IS_IPv4) | LOGD_IPX(IS_IPv4), - "ipv%c.dhcp-iaid: using %u (0x%08x) IAID (str: '%s', explicit %d)", + "ipv%c.dhcp-iaid: using %u (%s) IAID (str: '%s', explicit %d)", nm_utils_addr_family_to_char(addr_family), iaid, - iaid, + nm_dhcp_iaid_to_hexstr(iaid, buf), iaid_str, is_explicit); } @@ -2736,12 +2752,6 @@ _ethtool_state_set(NMDevice *self) /*****************************************************************************/ -static gboolean -is_loopback(NMDevice *self) -{ - return NM_IS_DEVICE_GENERIC(self) && NM_DEVICE_GET_PRIVATE(self)->ifindex == 1; -} - gboolean nm_device_is_vpn(NMDevice *self) { @@ -3578,7 +3588,7 @@ _dev_ip_state_check_async(NMDevice *self, int addr_family) } static void -_dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean from_reapply) +_dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean keep_reapply) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); int IS_IPv4; @@ -3586,7 +3596,7 @@ _dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean from_reapply) if (addr_family == AF_UNSPEC) { _dev_ip_state_set_state(self, addr_family, - from_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, + keep_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, "ip-state-clear"); return; } @@ -3597,7 +3607,7 @@ _dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean from_reapply) nm_clear_g_source_inst(&priv->ip_data_x[IS_IPv4].req_timeout_source); _dev_ip_state_set_state(self, addr_family, - from_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, + keep_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, "ip-state-clear"); priv->ip_data_x[IS_IPv4].wait_for_carrier = FALSE; priv->ip_data_x[IS_IPv4].wait_for_ports = FALSE; @@ -4129,18 +4139,30 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N /* Check if AC6 addresses completed DAD */ if (NM_FLAGS_ANY(notify_data->platform_change_on_idle.obj_type_flags, nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP6_ADDRESS)) - && priv->ipac6_data.state == NM_DEVICE_IP_STATE_PENDING && priv->ipac6_data.l3cd - && nm_l3cfg_check_ready(l3cfg, - priv->ipac6_data.l3cd, - AF_INET6, - NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, - NULL)) { - if (nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, AF_INET6)) - _dev_l3_cfg_commit(self, FALSE); - - nm_clear_l3cd(&priv->ipac6_data.l3cd); - _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); - _dev_ip_state_check_async(self, AF_INET6); + && priv->ipac6_data.state == NM_DEVICE_IP_STATE_PENDING && priv->ipac6_data.l3cd) { + gs_unref_array GArray *conflicts = NULL; + gboolean ready; + + ready = nm_l3cfg_check_ready(l3cfg, + priv->ipac6_data.l3cd, + AF_INET6, + NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, + &conflicts); + if (conflicts) { + /* nm_ndisc_dad_failed() will emit a new "NDisc:config-received" + * signal; _dev_ipac6_ndisc_config_changed() will be called + * synchronously to update the current state and schedule a commit. */ + nm_ndisc_dad_failed(priv->ipac6_data.ndisc, conflicts, TRUE); + } else if (ready) { + if (nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, AF_INET6)) + _dev_l3_cfg_commit(self, FALSE); + + nm_clear_l3cd(&priv->ipac6_data.l3cd); + _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); + _dev_ip_state_check_async(self, AF_INET6); + } else { + /* wait */ + } } _dev_ipmanual_check_ready(self); @@ -5005,6 +5027,9 @@ nm_device_get_route_metric_default(NMDeviceType device_type) */ switch (device_type) { + case NM_DEVICE_TYPE_LOOPBACK: + return 30; + /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT). * * Note that returning 50 from this function means that this device-type is @@ -5425,7 +5450,7 @@ concheck_is_possible(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (!nm_device_is_real(self) || is_loopback(self)) + if (!nm_device_is_real(self) || NM_IS_DEVICE_LOOPBACK(self)) return FALSE; /* we enable periodic checks for every device state (except UNKNOWN). Especially with @@ -6203,7 +6228,8 @@ nm_device_master_release_slave(NMDevice *self, NMDevicePrivate *priv; NMDevicePrivate *slave_priv; SlaveInfo *info; - gs_unref_object NMDevice *self_free = NULL; + gs_unref_object NMDevice *self_free = NULL; + gs_unref_object NMDevice *slave_free = NULL; g_return_if_fail(NM_DEVICE(self)); g_return_if_fail(NM_DEVICE(slave)); @@ -6246,14 +6272,15 @@ nm_device_master_release_slave(NMDevice *self, /* keep both alive until the end of the function. * Transfers ownership from slave_priv->master. */ - self_free = self; + nm_assert(self == slave_priv->master); + self_free = g_steal_pointer(&slave_priv->master); - c_list_unlink(&info->lst_slave); - slave_priv->master = NULL; + nm_assert(slave == info->slave); + slave_free = g_steal_pointer(&info->slave); + c_list_unlink(&info->lst_slave); g_signal_handler_disconnect(slave, info->watch_id); - g_object_unref(slave); - g_slice_free(SlaveInfo, info); + nm_g_slice_free(info); if (c_list_is_empty(&priv->slaves)) { _active_connection_set_state_flags_full(self, @@ -6577,27 +6604,30 @@ device_recheck_slave_status(NMDevice *self, const NMPlatformLink *plink) NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); } - if (master && NM_DEVICE_GET_CLASS(master)->attach_port) { - nm_device_master_add_slave(master, self, FALSE); + if (master) { + if (NM_DEVICE_GET_CLASS(master)->attach_port) { + nm_device_master_add_slave(master, self, FALSE); + } else { + _LOGD(LOGD_DEVICE, + "enslaved to non-master-type device %s; ignoring", + nm_device_get_iface(master)); + } goto out; } - if (master) { - _LOGD(LOGD_DEVICE, - "enslaved to non-master-type device %s; ignoring", - nm_device_get_iface(master)); - } else { + if (plink->master) { _LOGD(LOGD_DEVICE, "enslaved to unknown device %d (%s%s%s)", plink->master, NM_PRINT_FMT_QUOTED(plink_master, "\"", plink_master->name, "\"", "??")); + if (!priv->ifindex_changed_id) { + priv->ifindex_changed_id = g_signal_connect(nm_device_get_manager(self), + NM_MANAGER_DEVICE_IFINDEX_CHANGED, + G_CALLBACK(device_ifindex_changed_cb), + self); + } } - if (!priv->ifindex_changed_id) { - priv->ifindex_changed_id = g_signal_connect(nm_device_get_manager(self), - NM_MANAGER_DEVICE_IFINDEX_CHANGED, - G_CALLBACK(device_ifindex_changed_cb), - self); - } + return; out: @@ -6609,6 +6639,8 @@ device_ifindex_changed_cb(NMManager *manager, NMDevice *device_changed, NMDevice { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + g_return_if_fail(priv->master_ifindex > 0); + if (priv->master_ifindex != nm_device_get_ifindex(device_changed)) return; @@ -7146,6 +7178,9 @@ nm_device_update_from_platform_link(NMDevice *self, const NMPlatformLink *plink) ifindex_changed = _set_ifindex(self, plink ? plink->ifindex : 0, FALSE); + nm_device_update_hw_address(self); + nm_device_update_permanent_hw_address(self, FALSE); + if (ifindex_changed) NM_DEVICE_GET_CLASS(self)->link_changed(self, plink); @@ -7465,11 +7500,6 @@ realize_start_setup(NMDevice *self, NM_UNMANAGED_EXTERNAL_DOWN, _dev_unmanaged_is_external_down(self, TRUE)); - /* Unmanaged the loopback device with an explicit NM_UNMANAGED_BY_TYPE flag. - * Later we might want to manage 'lo' too. Currently, that doesn't work because - * NetworkManager might down the interface or remove the 127.0.0.1 address. */ - nm_device_set_unmanaged_flags(self, NM_UNMANAGED_BY_TYPE, is_loopback(self)); - nm_device_set_unmanaged_by_user_udev(self); nm_device_set_unmanaged_by_user_conf(self); @@ -7659,8 +7689,7 @@ nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error) nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, TRUE); nm_device_set_unmanaged_flags(self, - NM_UNMANAGED_PARENT | NM_UNMANAGED_BY_TYPE - | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_EXPLICIT + NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_EXPLICIT | NM_UNMANAGED_EXTERNAL_DOWN | NM_UNMANAGED_IS_SLAVE, NM_UNMAN_FLAG_OP_FORGET); @@ -8565,6 +8594,7 @@ nm_device_generate_connection(NMDevice *self, nm_device_get_iface(master), local->message); g_error_free(local); + NM_SET_OUT(out_maybe_later, TRUE); return NULL; } } else { @@ -8585,7 +8615,7 @@ nm_device_generate_connection(NMDevice *self, pllink = nm_platform_link_get(nm_device_get_platform(self), priv->ifindex); if (pllink && pllink->inet6_token.id) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; g_object_set(s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, @@ -8776,6 +8806,14 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e return FALSE; } + if (!nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV) + && nm_connection_get_setting(connection, NM_TYPE_SETTING_SRIOV)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not support SR-IOV"); + return FALSE; + } + conn_iface = nm_manager_get_connection_iface(NM_MANAGER_GET, connection, NULL, NULL, &local); /* We always need a interface name for virtual devices, but for @@ -9359,14 +9397,17 @@ activate_stage1_device_prepare(NMDevice *self) nm_device_state_changed(self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); if (priv->stage1_sriov_state != NM_DEVICE_STAGE_STATE_COMPLETED) { - NMSettingSriov *s_sriov; + NMSettingSriov *s_sriov = NULL; if (nm_device_sys_iface_state_is_external_or_assume(self)) { /* pass */ - } else if (priv->stage1_sriov_state == NM_DEVICE_STAGE_STATE_PENDING) + } else if (priv->stage1_sriov_state == NM_DEVICE_STAGE_STATE_PENDING) { return; - else if (priv->ifindex > 0 && nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV) - && (s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))) { + } else if (priv->ifindex > 0) { + s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV); + } + + if (s_sriov) { nm_auto_freev NMPlatformVF **plat_vfs = NULL; gs_free_error GError *error = NULL; NMSriovVF *vf; @@ -9374,6 +9415,8 @@ activate_stage1_device_prepare(NMDevice *self) guint num; guint i; + nm_assert(nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV)); + autoprobe = nm_setting_sriov_get_autoprobe_drivers(s_sriov); if (autoprobe == NM_TERNARY_DEFAULT) { autoprobe = nm_config_data_get_connection_default_int64( @@ -9612,6 +9655,18 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) user_tag_1, NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG); } + + if (nm_setting_ip_config_get_replace_local_rule(s_ip) == NM_TERNARY_TRUE) { + /* The user specified that the local rule should be replaced. + * In order to do that, we track the local rule with negative + * priority. */ + nmp_global_tracker_track_local_rule( + global_tracker, + addr_family, + -5, + user_tag_1, + NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG); + } } if (klass->get_extra_rules) { @@ -10058,7 +10113,7 @@ _dev_ipmanual_check_ready(NMDevice *self) gboolean has_carrier; NML3CfgCheckReadyFlags flags; gboolean ready; - gboolean acd_used = FALSE; + gs_unref_array GArray *conflicts = NULL; int IS_IPv4; if (priv->ipmanual_data.state_4 != NM_DEVICE_IP_STATE_PENDING @@ -10101,8 +10156,8 @@ _dev_ipmanual_check_ready(NMDevice *self) priv->l3cds[L3_CONFIG_DATA_TYPE_MANUALIP].d, addr_family, flags, - &acd_used); - if (acd_used) { + &conflicts); + if (conflicts) { _dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_FAILED); _dev_ip_state_check_async(self, AF_UNSPEC); } else if (ready) { @@ -10434,6 +10489,7 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) .request_broadcast = request_broadcast, .acd_timeout_msec = _prop_get_ipv4_dad_timeout(self), }, + .previous_lease = priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4)].d, }; priv->ipdhcp_data_4.client = @@ -10484,16 +10540,16 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) G_CALLBACK(_dev_ipdhcpx_notify), self); - /* FIXME(l3cfg:dhcp:previous-lease): take the NML3ConfigData from the previous lease (if any) - * and pass it on to NMDhcpClient. This is a fake lease that we use initially (until - * NMDhcpClient got a real lease). Note that NMDhcpClient needs to check whether the - * lease already expired. */ - + /* Take the NML3ConfigData from the previous lease (if any) that was passed to the NMDhcpClient. + * This may be the old lease only used during the duration of a reapply until we get the + * new lease. */ previous_lease = nm_dhcp_client_get_lease(priv->ipdhcp_data_x[IS_IPv4].client); + if (!priv->ipdhcp_data_x[IS_IPv4].config) { priv->ipdhcp_data_x[IS_IPv4].config = nm_dhcp_config_new(addr_family, previous_lease); _notify(self, PROP_DHCPX_CONFIG(IS_IPv4)); } + if (previous_lease) { nm_dhcp_config_set_lease(priv->ipdhcp_data_x[IS_IPv4].config, previous_lease); _dev_l3_register_l3cds_set_one_full(self, @@ -10747,14 +10803,14 @@ nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device) l3cd_src = priv_src->l3cds[L3_CONFIG_DATA_TYPE_AC_6].d; } if (l3cd_src) { - const char *const *strvarr; - const struct in6_addr *addrs; - guint n; - guint i; + const char *const *strvarr; + const char *const *addrs; + guint n; + guint i; addrs = nm_l3_config_data_get_nameservers(l3cd_src, AF_INET6, &n); for (i = 0; i < n; i++) - nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &addrs[i]); + nm_l3_config_data_add_nameserver(l3cd, AF_INET6, addrs[i]); strvarr = nm_l3_config_data_get_searches(l3cd_src, AF_INET6, &n); for (i = 0; i < n; i++) @@ -10806,7 +10862,8 @@ _dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6 || (!priv->ipll_data_6.v6.ipv6ll && NM_IN_SET(priv->ipll_data_6.v6.llstate, NM_L3_IPV6LL_STATE_NONE, - NM_L3_IPV6LL_STATE_DEFUNCT))); + NM_L3_IPV6LL_STATE_DEFUNCT, + NM_L3_IPV6LL_STATE_READY))); switch (priv->ipll_data_6.v6.llstate) { case NM_L3_IPV6LL_STATE_NONE: @@ -10844,7 +10901,7 @@ _dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6 } if (changed) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; _LOGT_ipll(AF_INET6, "set state %s (was %s, llstate=%s, lladdr=%s)", @@ -10853,7 +10910,7 @@ _dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6 nm_l3_ipv6ll_state_to_string(priv->ipll_data_6.v6.llstate), nm_ip_addr_is_null(AF_INET6, &priv->ipll_data_6.v6.lladdr) ? "(none)" - : _nm_utils_inet6_ntop(&priv->ipll_data_6.v6.lladdr, sbuf)); + : nm_inet6_ntop(&priv->ipll_data_6.v6.lladdr, sbuf)); } if (changed) @@ -10889,6 +10946,11 @@ _dev_ipll6_start(NMDevice *self) if (priv->ipll_data_6.v6.ipv6ll) return; + if (NM_IS_DEVICE_LOOPBACK(self)) { + _dev_ipll6_set_llstate(self, NM_L3_IPV6LL_STATE_READY, NULL); + return; + } + if (!priv->l3cfg) { _LOGD(LOGD_IP6, "linklocal6: no IP link for IPv6"); goto out_fail; @@ -11000,6 +11062,10 @@ nm_device_get_configured_mtu_from_connection(NMDevice *self, if (setting) mtu = nm_setting_wireguard_get_mtu(NM_SETTING_WIREGUARD(setting)); global_property_name = NM_CON_DEFAULT("wireguard.mtu"); + } else if (setting_type == NM_TYPE_SETTING_LOOPBACK) { + if (setting) + mtu = nm_setting_loopback_get_mtu(NM_SETTING_LOOPBACK(setting)); + global_property_name = NM_CON_DEFAULT("loopback.mtu"); } else g_return_val_if_reached(0); @@ -11411,10 +11477,14 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc, const NML3ConfigData *l3cd, NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean ready = TRUE; - NMDedupMultiIter iter; - const NMPObject *obj; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean ready; + + /* The ndisc configuration changes when we receive a new RA or + * when a lifetime expires; but also when DAD fails for a + * SLAAC address and we need to regenerate new stable-privacy + * addresses. In all these cases we update the AC6 configuration, + * schedule a commit and update the AC state. */ _dev_ipac6_grace_period_start(self, 0, TRUE); @@ -11425,22 +11495,11 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc, FALSE); nm_clear_l3cd(&priv->ipac6_data.l3cd); - - /* wait that addresses are committed to platform and - * become non-tentative before declaring AC6 is ready.*/ - nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP6_ADDRESS) { - const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(obj); - const NMPlatformIP6Address *plat_addr; - - plat_addr = nm_platform_ip6_address_get(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - &addr->address); - if (!plat_addr || (plat_addr->n_ifa_flags & IFA_F_TENTATIVE)) { - ready = FALSE; - break; - } - } - + ready = nm_l3cfg_check_ready(priv->l3cfg, + l3cd, + AF_INET6, + NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, + NULL); if (ready) { _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); } else { @@ -12078,13 +12137,34 @@ activate_stage3_ip_config(NMDevice *self) ifindex = nm_device_get_ip_ifindex(self); + ipv4_method = nm_device_get_effective_ip_config_method(self, AF_INET); + if (nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + /* "auto" usually means DHCPv4 or autoconf6, but it doesn't have to be. Subclasses + * can overwrite it. For example, you cannot run DHCPv4 on PPP/WireGuard links. */ + ipv4_method = klass->get_ip_method_auto(self, AF_INET); + } + + ipv6_method = nm_device_get_effective_ip_config_method(self, AF_INET6); + + if (nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { + ipv6_method = klass->get_ip_method_auto(self, AF_INET6); + } + if (priv->ip_data_4.do_reapply) { _LOGD_ip(AF_INET, "reapply..."); - _cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_DECONFIGURE, TRUE); + priv->ip_data_4.do_reapply = FALSE; + _cleanup_ip_pre(self, + AF_INET, + CLEANUP_TYPE_KEEP_REAPPLY, + nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)); } if (priv->ip_data_6.do_reapply) { _LOGD_ip(AF_INET6, "reapply..."); - _cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_DECONFIGURE, TRUE); + priv->ip_data_6.do_reapply = FALSE; + _cleanup_ip_pre(self, + AF_INET6, + CLEANUP_TYPE_KEEP_REAPPLY, + nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)); } /* Add the interface to the specified firewall zone */ @@ -12136,18 +12216,6 @@ activate_stage3_ip_config(NMDevice *self) * let's do it! */ _commit_mtu(self); - ipv4_method = nm_device_get_effective_ip_config_method(self, AF_INET); - if (nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - /* "auto" usually means DHCPv4 or autoconf6, but it doesn't have to be. Subclasses - * can overwrite it. For example, you cannot run DHCPv4 on PPP/WireGuard links. */ - ipv4_method = klass->get_ip_method_auto(self, AF_INET); - } - - ipv6_method = nm_device_get_effective_ip_config_method(self, AF_INET6); - if (nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - ipv6_method = klass->get_ip_method_auto(self, AF_INET6); - } - if (!nm_device_sys_iface_state_is_external(self) && (!klass->ready_for_ip_config || klass->ready_for_ip_config(self, TRUE))) { if (priv->ipmanual_data.state_6 == NM_DEVICE_IP_STATE_NONE @@ -12274,16 +12342,28 @@ _dev_ipshared4_new_l3cd(NMDevice *self, NMConnection *connection, NMPlatformIP4A static gboolean _dev_ipshared4_init(NMDevice *self) { - static const char *const modules[] = {"ip_tables", - "iptable_nat", - "nf_nat_ftp", - "nf_nat_irc", - "nf_nat_sip", - "nf_nat_tftp", - "nf_nat_pptp", - "nf_nat_h323"}; - int errsv; - guint i; + static const char *const modules_iptables[] = {"ip_tables", "iptable_nat"}; + static const char *const modules_nftables[] = + {"nf_nat_ftp", "nf_nat_irc", "nf_nat_sip", "nf_nat_tftp", "nf_nat_pptp", "nf_nat_h323"}; + int errsv; + guint i; + + switch (nm_firewall_utils_get_backend()) { + case NM_FIREWALL_BACKEND_IPTABLES: + for (i = 0; i < G_N_ELEMENTS(modules_iptables); i++) + nmp_utils_modprobe(NULL, FALSE, modules_iptables[i], NULL); + break; + case NM_FIREWALL_BACKEND_NFTABLES: + for (i = 0; i < G_N_ELEMENTS(modules_nftables); i++) + nmp_utils_modprobe(NULL, FALSE, modules_nftables[i], NULL); + break; + case NM_FIREWALL_BACKEND_NONE: + /* do not modify network settings like ip forwarding */ + return TRUE; + default: + nm_assert_not_reached(); + break; + } if (nm_platform_sysctl_get_int32(nm_device_get_platform(self), NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_forward"), @@ -12312,9 +12392,6 @@ _dev_ipshared4_init(NMDevice *self) nm_strerror_native(errsv)); } - for (i = 0; i < G_N_ELEMENTS(modules); i++) - nmp_utils_modprobe(NULL, FALSE, modules[i], NULL); - return TRUE; } @@ -12591,17 +12668,18 @@ delete_on_deactivate_check_and_schedule(NMDevice *self) } static void -_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean from_reapply) +_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean preserve_dhcp) { - const int IS_IPv4 = NM_IS_IPv4(addr_family); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean keep_reapply = (cleanup_type == CLEANUP_TYPE_KEEP_REAPPLY); _dev_ipsharedx_cleanup(self, addr_family); _dev_ipdev_cleanup(self, AF_UNSPEC); _dev_ipdev_cleanup(self, addr_family); - _dev_ipdhcpx_cleanup(self, addr_family, TRUE, FALSE); + _dev_ipdhcpx_cleanup(self, addr_family, !preserve_dhcp || !keep_reapply, FALSE); if (!IS_IPv4) _dev_ipac6_cleanup(self); @@ -12613,8 +12691,8 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gbool nm_clear_g_signal_handler(nm_manager_get_dns_manager(priv->manager), &priv->ip_data.dnsmgr_update_pending_signal_id); - _dev_ip_state_cleanup(self, AF_UNSPEC, from_reapply); - _dev_ip_state_cleanup(self, addr_family, from_reapply); + _dev_ip_state_cleanup(self, AF_UNSPEC, keep_reapply); + _dev_ip_state_cleanup(self, addr_family, keep_reapply); } gboolean @@ -12762,7 +12840,9 @@ can_reapply_change(NMDevice *self, goto out_fail; } - if (nm_streq(setting_name, NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME) + if (NM_IN_STRSET(setting_name, + NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME, + NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME) && NM_DEVICE_GET_CLASS(self)->can_reapply_change_ovs_external_ids) { /* TODO: this means, you cannot reapply changes to the external-ids for * OVS system interfaces. */ @@ -12984,6 +13064,10 @@ check_and_reapply_connection(NMDevice *self, if (priv->state >= NM_DEVICE_STATE_ACTIVATED) nm_device_update_metered(self); + /* Notify dispatcher when re-applied */ + _LOGD(LOGD_DEVICE, "Notifying re-apply complete"); + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_REAPPLY, self, NULL, NULL, NULL, NULL); + return TRUE; } @@ -13889,7 +13973,7 @@ nm_device_start_ip_check(NMDevice *self) NMSettingConnection *s_con; guint timeout = 0; const char *ping_binary = NULL; - char buf[NM_UTILS_INET_ADDRSTRLEN]; + char buf[NM_INET_ADDRSTRLEN]; NMLogDomain log_domain = LOGD_IP4; /* Shouldn't be any active ping here, since IP_CHECK happens after the @@ -13920,14 +14004,14 @@ nm_device_start_ip_check(NMDevice *self) } else if (priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY) { gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET); if (gw) { - _nm_utils_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway, buf); + nm_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway, buf); ping_binary = nm_utils_find_helper("ping", "/usr/bin/ping", NULL); log_domain = LOGD_IP4; } } else if (priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY) { gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET6); if (gw) { - _nm_utils_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway, buf); + nm_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway, buf); ping_binary = nm_utils_find_helper("ping6", "/usr/bin/ping6", NULL); log_domain = LOGD_IP6; } @@ -14151,8 +14235,6 @@ NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str, NMUnmanagedFlags, NM_UTILS_FLAGS2STR(NM_UNMANAGED_SLEEPING, "sleeping"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_QUITTING, "quitting"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_PARENT, "parent"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_TYPE, "by-type"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_PLATFORM_INIT, "platform-init"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_EXPLICIT, "user-explicit"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_DEFAULT, "by-default"), @@ -14847,9 +14929,10 @@ _nm_device_check_connection_available(NMDevice *self, } else { if (!nm_device_get_managed(self, TRUE)) { /* device is strictly unmanaged by authoritative unmanaged reasons. */ - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - "device is strictly unmanaged"); + nm_utils_error_set_literal( + error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_STRICTLY_UNMANAGED_DEVICE, + "device is strictly unmanaged"); return FALSE; } if (!NM_FLAGS_HAS(flags, @@ -16138,7 +16221,7 @@ nm_device_queue_state(NMDevice *self, NMDeviceState state, NMDeviceStateReason r /* We should only ever have one delayed state transition at a time */ if (priv->queued_state.id) { - _LOGW(LOGD_DEVICE, + _LOGD(LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", nm_device_state_to_string(priv->queued_state.state), nm_device_state_reason_to_string_a(priv->queued_state.reason), @@ -17036,6 +17119,21 @@ nm_device_auth_retries_try_next(NMDevice *self) return TRUE; } +static const char * +_resolver_state_to_string(ResolverState state) +{ + switch (state) { + case RESOLVER_WAIT_ADDRESS: + return "WAIT-ADDRESS"; + case RESOLVER_STARTED: + return "STARTED"; + case RESOLVER_DONE: + return "DONE"; + } + nm_assert_not_reached(); + return "UNKNOWN"; +} + static void hostname_dns_lookup_callback(GObject *source, GAsyncResult *result, gpointer user_data) { @@ -17055,7 +17153,9 @@ hostname_dns_lookup_callback(GObject *source, GAsyncResult *result, gpointer use if (error) { _LOGD(LOGD_DNS, - "hostname-from-dns: lookup error for %s: %s", + "hostname-from-dns: ipv%c resolver %s: lookup error for %s: %s", + nm_utils_addr_family_to_char(resolver->addr_family), + _resolver_state_to_string(RESOLVER_DONE), (addr_str = g_inet_address_to_string(resolver->address)), error->message); } else { @@ -17065,7 +17165,9 @@ hostname_dns_lookup_callback(GObject *source, GAsyncResult *result, gpointer use valid = nm_utils_validate_hostname(resolver->hostname); _LOGD(LOGD_DNS, - "hostname-from-dns: lookup done for %s, result %s%s%s%s", + "hostname-from-dns: ipv%c resolver %s: lookup successful for %s, result %s%s%s%s", + nm_utils_addr_family_to_char(resolver->addr_family), + _resolver_state_to_string(RESOLVER_DONE), (addr_str = g_inet_address_to_string(resolver->address)), NM_PRINT_FMT_QUOTE_STRING(resolver->hostname), valid ? "" : " (invalid)"); @@ -17091,8 +17193,9 @@ hostname_dns_address_timeout(gpointer user_data) nm_assert(!resolver->cancellable); _LOGT(LOGD_DNS, - "hostname-from-dns: timed out while waiting IPv%c address", - nm_utils_addr_family_to_char(resolver->addr_family)); + "hostname-from-dns: ipv%c state %s: timed out while waiting for address", + nm_utils_addr_family_to_char(resolver->addr_family), + _resolver_state_to_string(RESOLVER_DONE)); resolver->timeout_id = 0; resolver->state = RESOLVER_DONE; @@ -17101,30 +17204,22 @@ hostname_dns_address_timeout(gpointer user_data) return G_SOURCE_REMOVE; } -static const char * -_resolver_state_to_string(ResolverState state) +void +nm_device_clear_dns_lookup_data(NMDevice *self, const char *reason) { - switch (state) { - case RESOLVER_WAIT_ADDRESS: - return "wait-address"; - case RESOLVER_IN_PROGRESS: - return "in-progress"; - case RESOLVER_DONE: - return "done"; - default: - nm_assert_not_reached(); - return "unknown"; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + if (priv->hostname_resolver_4 || priv->hostname_resolver_6) { + _LOGT(LOGD_DNS, "hostname-from-dns: resetting (%s)", reason); + nm_clear_pointer(&priv->hostname_resolver_4, _hostname_resolver_free); + nm_clear_pointer(&priv->hostname_resolver_6, _hostname_resolver_free); } } -void -nm_device_clear_dns_lookup_data(NMDevice *self) +gboolean +nm_device_get_allow_autoconnect_on_external(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - guint i; - - for (i = 0; i < 2; i++) - nm_clear_pointer(&priv->hostname_resolver_x[i], _hostname_resolver_free); + return NM_DEVICE_GET_CLASS(self)->allow_autoconnect_on_external; } static GInetAddress * @@ -17151,27 +17246,36 @@ get_address_for_hostname_dns_lookup(NMDevice *self, int addr_family) if (head_entry) { c_list_for_each_entry (iter, &head_entry->lst_entries_head, lst_entries) { - const NMPlatformIPAddress *addr = NMP_OBJECT_CAST_IP_ADDRESS(iter->obj); + const NMPlatformIPXAddress *addr = NMP_OBJECT_CAST_IPX_ADDRESS(iter->obj); if (IS_IPv4) { - return g_inet_address_new_from_bytes(addr->address_ptr, G_SOCKET_FAMILY_IPV4); + if (nm_ip4_addr_is_loopback(addr->a4.address)) + continue; + return g_inet_address_new_from_bytes(addr->ax.address_ptr, G_SOCKET_FAMILY_IPV4); } + if (addr->ax.n_ifa_flags & IFA_F_TENTATIVE) + continue; + /* For IPv6 prefer, in order: * - !link-local, !deprecated * - !link-local, deprecated * - link-local */ - if (!IN6_IS_ADDR_LINKLOCAL(addr->address_ptr)) { - if (!(addr->n_ifa_flags & IFA_F_DEPRECATED)) { - return g_inet_address_new_from_bytes(addr->address_ptr, G_SOCKET_FAMILY_IPV6); + if (IN6_ARE_ADDR_EQUAL(&addr->a6.address, &in6addr_loopback)) + continue; + + if (!IN6_IS_ADDR_LINKLOCAL(addr->ax.address_ptr)) { + if (!(addr->ax.n_ifa_flags & IFA_F_DEPRECATED)) { + return g_inet_address_new_from_bytes(addr->ax.address_ptr, + G_SOCKET_FAMILY_IPV6); } - addr6_nonll = addr->address_ptr; + addr6_nonll = addr->ax.address_ptr; continue; } - addr6_ll = addr->address_ptr; + addr6_ll = addr->ax.address_ptr; } if (addr6_nonll || addr6_ll) @@ -17246,29 +17350,35 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean } else if (new_address != resolver->address) address_changed = TRUE; + if (address_changed) { + /* set new state before logging */ + if (new_address) + resolver->state = RESOLVER_STARTED; + else + resolver->state = RESOLVER_WAIT_ADDRESS; + } + { gs_free char *old_str = NULL; gs_free char *new_str = NULL; - _LOGT(LOGD_DNS, - "hostname-from-dns: ipv%c resolver state %s, old address %s, new address %s", - nm_utils_addr_family_to_char(resolver->addr_family), - _resolver_state_to_string(resolver->state), - resolver->address ? (old_str = g_inet_address_to_string(resolver->address)) - : "(null)", - new_address ? (new_str = g_inet_address_to_string(new_address)) : "(null)"); + if (address_changed) { + _LOGT(LOGD_DNS, + "hostname-from-dns: ipv%c resolver %s, address changed from %s to %s", + nm_utils_addr_family_to_char(resolver->addr_family), + _resolver_state_to_string(resolver->state), + resolver->address ? (old_str = g_inet_address_to_string(resolver->address)) + : "(null)", + new_address ? (new_str = g_inet_address_to_string(new_address)) : "(null)"); + } } - /* In every state, if the address changed, we restart - * the resolution with the new address */ if (address_changed) { nm_clear_g_cancellable(&resolver->cancellable); g_clear_object(&resolver->address); - resolver->state = RESOLVER_WAIT_ADDRESS; } if (address_changed && new_address) { - resolver->state = RESOLVER_IN_PROGRESS; resolver->cancellable = g_cancellable_new(); resolver->address = g_steal_pointer(&new_address); @@ -17286,7 +17396,7 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean resolver->timeout_id = g_timeout_add(30000, hostname_dns_address_timeout, resolver); NM_SET_OUT(out_wait, TRUE); return NULL; - case RESOLVER_IN_PROGRESS: + case RESOLVER_STARTED: NM_SET_OUT(out_wait, TRUE); return NULL; case RESOLVER_DONE: @@ -17578,7 +17688,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps nm_assert(priv->type == NM_DEVICE_TYPE_UNKNOWN); priv->type = g_value_get_uint(value); nm_assert(priv->type > NM_DEVICE_TYPE_UNKNOWN); - nm_assert(priv->type <= NM_DEVICE_TYPE_VRF); + nm_assert(priv->type <= NM_DEVICE_TYPE_LOOPBACK); break; case PROP_LINK_TYPE: /* construct-only */ |