diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 21ba692855..69f4ddb6c9 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -705,6 +705,8 @@ typedef struct _NMDevicePrivate { IPDevStateData ipdev_data_unspec; + gulong sharing_ipv4_changed_id; + struct { /* If we set the addrgenmode6, this records the previously set value. */ guint8 previous_mode_val; @@ -792,7 +794,6 @@ typedef struct _NMDevicePrivate { char *prop_ip_iface; /* IP interface D-Bus property */ GList *ping_operations; GSource *ping_timeout; - bool refresh_forwarding_done : 1; } NMDevicePrivate; G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) @@ -880,6 +881,8 @@ static void _dev_ipshared4_spawn_dnsmasq(NMDevice *self); static void _dev_ipshared6_start(NMDevice *self); +static void _dev_ipforwarding4_start(NMDevice *self, int addr_family); + static void _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean preserve_dhcp); @@ -2166,8 +2169,8 @@ _prop_get_ipvx_dhcp_send_hostname(NMDevice *self, int addr_family) return send_hostname_v2; } -NMSettingIPConfigForwarding -nm_device_get_ipv4_forwarding(NMDevice *self) +static NMSettingIPConfigForwarding +_prop_get_ipv4_forwarding(NMDevice *self) { NMSettingIPConfig *s_ip; NMSettingIPConfigForwarding forwarding; @@ -3814,7 +3817,7 @@ nm_device_assume_state_reset(NMDevice *self) /*****************************************************************************/ -char * +static char * nm_device_sysctl_ip_conf_get(NMDevice *self, int addr_family, const char *property) { const char *ifname; @@ -6681,7 +6684,7 @@ concheck_update_state(NMDevice *self, } } -const char * +static const char * nm_device_get_effective_ip_config_method(NMDevice *self, int addr_family) { NMDeviceClass *klass; @@ -8675,6 +8678,8 @@ nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error) g_object_thaw_notify(G_OBJECT(self)); + nm_device_managed_type_set(self, NM_DEVICE_MANAGED_TYPE_REMOVED); + nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, TRUE); nm_device_set_unmanaged_flags(self, @@ -13199,17 +13204,12 @@ activate_stage3_ip_config_for_addr_family(NMDevice *self, int addr_family) goto out_devip; if (IS_IPv4) { - NMSettingIPConfigForwarding ipv4_forwarding = nm_device_get_ipv4_forwarding(self); - - if (NM_IN_SET(ipv4_forwarding, - NM_SETTING_IP_CONFIG_FORWARDING_NO, - NM_SETTING_IP_CONFIG_FORWARDING_YES)) { - nm_device_sysctl_ip_conf_set(self, AF_INET, "forwarding", ipv4_forwarding ? "1" : "0"); - } priv->ipll_data_4.v4.mode = _prop_get_ipv4_link_local(self); if (priv->ipll_data_4.v4.mode == NM_SETTING_IP4_LL_ENABLED) _dev_ipll4_start(self); + _dev_ipforwarding4_start(self, addr_family); + if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) _dev_ipdhcpx_start(self, AF_INET); else if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { @@ -13529,15 +13529,21 @@ nm_device_activate_schedule_stage3_ip_config(NMDevice *self, gboolean do_sync) static void _dev_ipsharedx_set_state(NMDevice *self, int addr_family, NMDeviceIPState state) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - 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); + NMDeviceIPState old_state = priv->ipshared_data_x[IS_IPv4].state; - if (priv->ipshared_data_x[IS_IPv4].state != state) { + if (old_state != state) { _LOGD_ipshared(addr_family, "set state %s (was %s)", nm_device_ip_state_to_string(state), - nm_device_ip_state_to_string(priv->ipshared_data_x[IS_IPv4].state)); + nm_device_ip_state_to_string(old_state)); priv->ipshared_data_x[IS_IPv4].state = state; + + if (old_state == NM_DEVICE_IP_STATE_READY || state == NM_DEVICE_IP_STATE_READY) + nm_manager_update_shared_connection(NM_MANAGER_GET, + addr_family, + state == NM_DEVICE_IP_STATE_READY); } } @@ -13833,6 +13839,106 @@ _dev_ipshared6_start(NMDevice *self) /*****************************************************************************/ +/** + * Set the device's forwarding to the specified value. If %NM_TERNARY_DEFAULT is specified, + * it's set to the kernel's default, otherwise it's set to the specific value. + */ +static void +_dev_ipforwarding4_set(NMDevice *self, NMTernary val) +{ + gs_free const char *default_forwarding = NULL; + gs_free const char *current_forwarding = NULL; + const char *val_str; + + if (val != NM_TERNARY_DEFAULT) { + val_str = val ? "1" : "0"; + } else { + default_forwarding = nm_platform_sysctl_get( + nm_device_get_platform(self), + NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/conf/default/forwarding")); + + if (!default_forwarding) { + _LOGW(LOGD_DEVICE, + "error setting IPv4 forwarding: can't read default forwarding value: %s", + nm_strerror_native(errno)); + return; /* Non fatal */ + } + + val_str = default_forwarding; + } + + current_forwarding = nm_device_sysctl_ip_conf_get(self, AF_INET, "forwarding"); + if (nm_streq0(current_forwarding, val_str)) + return; + + if (!nm_device_sysctl_ip_conf_set(self, AF_INET, "forwarding", val_str)) + _LOGW(LOGD_DEVICE, + "error setting IPv4 forwarding to '%s': %s", + val_str, + nm_strerror_native(errno)); +} + +static void +_dev_ipforwarding4_auto_cb(NMManager *manager, gboolean sharing_ipv4, gpointer data) +{ + NMDevice *self = NM_DEVICE(data); + + _dev_ipforwarding4_set(self, sharing_ipv4 ? NM_TERNARY_TRUE : NM_TERNARY_DEFAULT); +} + +static void +_dev_ipforwarding4_start(NMDevice *self, int addr_family) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMSettingIPConfigForwarding ipv4_forwarding = _prop_get_ipv4_forwarding(self); + NMTernary new_forwarding = NM_TERNARY_DEFAULT; + + /* IPv6 per-interface forwarding not supported yet */ + if (addr_family != AF_INET) + return; + + if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { + new_forwarding = NM_TERNARY_TRUE; + } else if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_YES) { + new_forwarding = NM_TERNARY_TRUE; + } else if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_NO) { + new_forwarding = NM_TERNARY_FALSE; + } else if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_AUTO) { + if (nm_manager_get_sharing_ipv4(NM_MANAGER_GET)) + new_forwarding = NM_TERNARY_TRUE; + else + new_forwarding = NM_TERNARY_DEFAULT; + + if (!priv->sharing_ipv4_changed_id) + priv->sharing_ipv4_changed_id = g_signal_connect(NM_MANAGER_GET, + NM_MANAGER_SHARING_IPV4_CHANGED, + G_CALLBACK(_dev_ipforwarding4_auto_cb), + self); + } else { + nm_assert_not_reached(); + } + + _dev_ipforwarding4_set(self, new_forwarding); +} + +static void +_dev_ipforwarding_cleanup(NMDevice *self, int addr_family, CleanupType cleanup_type) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + if (!NM_IS_IPv4(addr_family)) + return; + + nm_clear_g_signal_handler(NM_MANAGER_GET, &priv->sharing_ipv4_changed_id); + + if (NM_IN_SET(cleanup_type, CLEANUP_TYPE_DECONFIGURE, CLEANUP_TYPE_KEEP_REAPPLY)) { + /* Deconfigure by restoring kernel's default */ + _dev_ipforwarding4_set(self, NM_TERNARY_DEFAULT); + } +} + +/*****************************************************************************/ + static void act_request_set(NMDevice *self, NMActRequest *act_request) { @@ -13945,6 +14051,8 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gbool NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); gboolean keep_reapply = (cleanup_type == CLEANUP_TYPE_KEEP_REAPPLY); + _dev_ipforwarding_cleanup(self, addr_family, cleanup_type); + _dev_ipsharedx_cleanup(self, addr_family); _dev_ipdev_cleanup(self, AF_UNSPEC); @@ -17013,8 +17121,6 @@ _cleanup_generic_post(NMDevice *self, NMDeviceStateReason reason, CleanupType cl priv->v4_route_table_all_sync_before = FALSE; priv->v6_route_table_all_sync_before = FALSE; - priv->refresh_forwarding_done = FALSE; - priv->mtu_force_set_done = FALSE; priv->needs_ip6_subnet = FALSE; @@ -17060,7 +17166,6 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu NMDevicePrivate *priv; NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self); int ifindex; - gint32 default_forwarding_v4; g_return_if_fail(NM_IS_DEVICE(self)); @@ -17083,17 +17188,6 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", "0"); } - /* Restoring the device's forwarding to the sysctl default is necessary because - * `refresh_forwarding()` only updates forwarding on activated devices. */ - default_forwarding_v4 = nm_platform_sysctl_get_int32( - nm_device_get_platform(self), - NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/conf/default/forwarding"), - 0); - nm_device_sysctl_ip_conf_set(self, - AF_INET, - "forwarding", - default_forwarding_v4 == 1 ? "1" : "0"); - /* Call device type-specific deactivation */ if (klass->deactivate) klass->deactivate(self); @@ -19047,19 +19141,6 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean return nm_assert_unreachable_val(NULL); } -gboolean -nm_device_get_refresh_forwarding_done(NMDevice *self) -{ - return NM_DEVICE_GET_PRIVATE(self)->refresh_forwarding_done; -} - -void -nm_device_set_refresh_forwarding_done(NMDevice *self, gboolean is_refresh_forwarding_done) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->refresh_forwarding_done = is_refresh_forwarding_done; -} - /*****************************************************************************/ static const char * diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index 820951ea6a..8632944a2d 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -853,14 +853,4 @@ void nm_routing_rules_sync(NMConnection *applied_connection, NMDevice *self, NMNetns *netns); -NMSettingIPConfigForwarding nm_device_get_ipv4_forwarding(NMDevice *self); - -const char *nm_device_get_effective_ip_config_method(NMDevice *self, int addr_family); - -char *nm_device_sysctl_ip_conf_get(NMDevice *self, int addr_family, const char *property); - -gboolean nm_device_get_refresh_forwarding_done(NMDevice *self); - -void nm_device_set_refresh_forwarding_done(NMDevice *self, gboolean is_refresh_forwarding_done); - #endif /* __NETWORKMANAGER_DEVICE_H__ */ diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 060e0c2c7c..87dde2c3af 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -136,6 +136,7 @@ enum { ACTIVE_CONNECTION_REMOVED, CONFIGURE_QUIT, DEVICE_IFINDEX_CHANGED, + SHARING_IPV4_CHANGED, LAST_SIGNAL }; @@ -238,6 +239,8 @@ typedef struct { guint8 device_state_prune_ratelimit_count; + guint shared_connections_ip4_count; + bool startup : 1; bool devices_inited : 1; @@ -8829,6 +8832,41 @@ nm_manager_emit_device_ifindex_changed(NMManager *self, NMDevice *device) g_signal_emit(self, signals[DEVICE_IFINDEX_CHANGED], 0, device); } +void +nm_manager_update_shared_connection(NMManager *self, int addr_family, gboolean enabled) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); + gboolean state_changed, state; + + /* Only IPv4 supported for the moment */ + if (addr_family != AF_INET) + return; + + if (enabled) { + g_return_if_fail(priv->shared_connections_ip4_count < G_MAXUINT); + priv->shared_connections_ip4_count++; + state_changed = priv->shared_connections_ip4_count == 1; + } else { + g_return_if_fail(priv->shared_connections_ip4_count > 0); + priv->shared_connections_ip4_count--; + state_changed = priv->shared_connections_ip4_count == 0; + } + + if (state_changed) { + state = priv->shared_connections_ip4_count > 0; + _LOGD(LOGD_SHARING, "sharing-ipv4 state change %d -> %d", !state, state); + g_signal_emit(self, signals[SHARING_IPV4_CHANGED], 0, state); + } +} + +gboolean +nm_manager_get_sharing_ipv4(NMManager *self) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); + + return priv->shared_connections_ip4_count > 0; +} + /*****************************************************************************/ NM_DEFINE_SINGLETON_REGISTER(NMManager); @@ -9932,6 +9970,17 @@ nm_manager_class_init(NMManagerClass *manager_class) G_TYPE_NONE, 1, NM_TYPE_DEVICE); + + signals[SHARING_IPV4_CHANGED] = g_signal_new(NM_MANAGER_SHARING_IPV4_CHANGED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN); } NMConfig * diff --git a/src/core/nm-manager.h b/src/core/nm-manager.h index 3c5213c4f2..e10ca0d110 100644 --- a/src/core/nm-manager.h +++ b/src/core/nm-manager.h @@ -61,6 +61,7 @@ #define NM_MANAGER_CONFIGURE_QUIT "configure-quit" #define NM_MANAGER_INTERNAL_DEVICE_ADDED "internal-device-added" #define NM_MANAGER_INTERNAL_DEVICE_REMOVED "internal-device-removed" +#define NM_MANAGER_SHARING_IPV4_CHANGED "sharing-ipv4-changed" GType nm_manager_get_type(void); @@ -212,6 +213,9 @@ struct _NMDnsManager; struct _NMDnsManager *nm_manager_get_dns_manager(NMManager *self); +void nm_manager_update_shared_connection(NMManager *self, int addr_family, gboolean enabled); +gboolean nm_manager_get_sharing_ipv4(NMManager *self); + /*****************************************************************************/ void nm_manager_notify_delete_settings_connections(NMManager *self, diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index 3893620811..f7be1a9f87 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -18,7 +18,6 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device.h" #include "devices/nm-device-factory.h" -#include "devices/nm-device-private.h" #include "dns/nm-dns-manager.h" #include "nm-act-request.h" #include "nm-auth-utils.h" @@ -98,6 +97,7 @@ typedef struct { bool updating_dns : 1; GArray *ip6_prefix_delegations; /* pool of ip6 prefixes delegated to all devices */ + } NMPolicyPrivate; struct _NMPolicy { @@ -2083,65 +2083,6 @@ unblock_autoconnect_for_ports_for_sett_conn(NMPolicy *self, NMSettingsConnection unblock_autoconnect_for_ports(self, controller_device, controller_uuid_settings, NULL); } -static void -refresh_forwarding(NMPolicy *self, NMDevice *device, gboolean is_activated_shared_device) -{ - NMActiveConnection *ac; - NMDevice *tmp_device; - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); - const CList *tmp_lst; - gboolean any_shared_active = false; - gint32 default_forwarding_v4; - const char *new_value = NULL; - - /* FIXME: This implementation is still inefficient because refresh_forwarding() - * is called every time a device goes up or down, requiring a full scan of all - * active connections to determine if any shared connection is active. */ - nm_manager_for_each_active_connection (priv->manager, ac, tmp_lst) { - NMSettingIPConfig *s_ip; - NMDevice *to_device = nm_active_connection_get_device(ac); - - if (to_device) { - s_ip = nm_device_get_applied_setting(to_device, NM_TYPE_SETTING_IP4_CONFIG); - if (s_ip) { - if (nm_streq0(nm_device_get_effective_ip_config_method(to_device, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { - any_shared_active = true; - break; - } - } - } - } - - default_forwarding_v4 = nm_platform_sysctl_get_int32( - NM_PLATFORM_GET, - NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/conf/default/forwarding"), - 0); - - new_value = any_shared_active ? "1" : (default_forwarding_v4 ? "1" : "0"); - - nm_manager_for_each_device (priv->manager, tmp_device, tmp_lst) { - NMDeviceState state; - NMSettingIPConfigForwarding ipv4_forwarding; - - state = nm_device_get_state(tmp_device); - if (state != NM_DEVICE_STATE_ACTIVATED) - continue; - - ipv4_forwarding = nm_device_get_ipv4_forwarding(tmp_device); - - if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_AUTO - || (device == tmp_device && is_activated_shared_device)) { - gs_free char *sysctl_value = NULL; - - sysctl_value = nm_device_sysctl_ip_conf_get(tmp_device, AF_INET, "forwarding"); - - if (!nm_streq0(sysctl_value, new_value)) - nm_device_sysctl_ip_conf_set(tmp_device, AF_INET, "forwarding", new_value); - } - } -} - static void activate_port_or_children_connections(NMPolicy *self, NMDevice *device, @@ -2286,9 +2227,8 @@ device_state_changed(NMDevice *device, NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF(priv); NMActiveConnection *ac; - NMSettingsConnection *sett_conn = nm_device_get_settings_connection(device); - NMSettingConnection *s_con = NULL; - gboolean is_activated_shared_device = FALSE; + NMSettingsConnection *sett_conn = nm_device_get_settings_connection(device); + NMSettingConnection *s_con = NULL; switch (nm_device_state_reason_check(reason)) { case NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED: @@ -2404,10 +2344,6 @@ device_state_changed(NMDevice *device, } } } - if (!nm_device_get_refresh_forwarding_done(device)) { - refresh_forwarding(self, device, FALSE); - nm_device_set_refresh_forwarding_done(device, TRUE); - } break; case NM_DEVICE_STATE_ACTIVATED: if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_OVS_INTERFACE) { @@ -2443,20 +2379,11 @@ device_state_changed(NMDevice *device, update_system_hostname(self, "routing and dns", TRUE); nm_dns_manager_end_updates(priv->dns_manager, __func__); - is_activated_shared_device = - nm_streq0(nm_device_get_effective_ip_config_method(device, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_SHARED); - refresh_forwarding(self, device, is_activated_shared_device); - nm_device_set_refresh_forwarding_done(device, FALSE); break; case NM_DEVICE_STATE_UNMANAGED: case NM_DEVICE_STATE_UNAVAILABLE: if (old_state > NM_DEVICE_STATE_DISCONNECTED) update_routing_and_dns(self, FALSE, device); - if (!nm_device_get_refresh_forwarding_done(device)) { - refresh_forwarding(self, device, FALSE); - nm_device_set_refresh_forwarding_done(device, TRUE); - } break; case NM_DEVICE_STATE_DEACTIVATING: if (sett_conn) { @@ -2492,10 +2419,6 @@ device_state_changed(NMDevice *device, } } ip6_remove_device_prefix_delegations(self, device); - if (!nm_device_get_refresh_forwarding_done(device)) { - refresh_forwarding(self, device, FALSE); - nm_device_set_refresh_forwarding_done(device, TRUE); - } break; case NM_DEVICE_STATE_DISCONNECTED: g_signal_handlers_disconnect_by_func(device, device_dns_lookup_done, self); @@ -2512,10 +2435,6 @@ device_state_changed(NMDevice *device, /* Device is now available for auto-activation */ nm_policy_device_recheck_auto_activate_schedule(self, device); - if (!nm_device_get_refresh_forwarding_done(device)) { - refresh_forwarding(self, device, FALSE); - nm_device_set_refresh_forwarding_done(device, TRUE); - } break; case NM_DEVICE_STATE_PREPARE: @@ -2531,10 +2450,6 @@ device_state_changed(NMDevice *device, g_object_weak_unref(G_OBJECT(ac), pending_ac_gone, self); g_object_unref(self); } - if (!nm_device_get_refresh_forwarding_done(device)) { - refresh_forwarding(self, device, FALSE); - nm_device_set_refresh_forwarding_done(device, TRUE); - } break; case NM_DEVICE_STATE_IP_CONFIG: /* We must have secrets if we got here. */ @@ -2545,10 +2460,6 @@ device_state_changed(NMDevice *device, sett_conn, NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_FAILED, FALSE); - if (!nm_device_get_refresh_forwarding_done(device)) { - refresh_forwarding(self, device, FALSE); - nm_device_set_refresh_forwarding_done(device, TRUE); - } break; case NM_DEVICE_STATE_SECONDARIES: if (sett_conn)