diff options
author | Thomas Haller <thaller@redhat.com> | 2020-09-15 12:01:52 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-09-15 12:01:52 +0200 |
commit | 88425e569f42043e079c596de029fcd3981ccde6 (patch) | |
tree | b2659f655999a9c8527e0c5bbf800030a2efc691 | |
parent | 991999489a300fb623e0fc4b5b6e465f94c79352 (diff) | |
parent | 3338ea0530bc05b403049df6df8f246cb455b597 (diff) | |
download | NetworkManager-88425e569f42043e079c596de029fcd3981ccde6.tar.gz |
device: merge branch 'th/device-track-shared-ips'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/625
-rw-r--r-- | src/devices/nm-device.c | 50 | ||||
-rw-r--r-- | src/nm-netns.c | 108 | ||||
-rw-r--r-- | src/nm-netns.h | 12 |
3 files changed, 133 insertions, 37 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index c1a2bab12b..f0fe5a0385 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -327,6 +327,8 @@ typedef struct _NMDevicePrivate { const NML3ConfigData *l3cds[_L3_CONFIG_DATA_TYPE_NUM]; + NMNetnsSharedIPHandle *shared_ip_handle; + int parent_ifindex; int auth_retries; @@ -9649,21 +9651,11 @@ nm_device_dhcp4_renew (NMDevice *self, gboolean release) /*****************************************************************************/ -static GHashTable *shared_ips = NULL; - -static void -shared_ip_release (gpointer data) -{ - g_hash_table_remove (shared_ips, data); - if (!g_hash_table_size (shared_ips)) - nm_clear_pointer (&shared_ips, g_hash_table_unref); -} - static NMIP4Config * shared4_new_config (NMDevice *self, NMConnection *connection) { - NMIP4Config *config = NULL; - gboolean is_generated = FALSE; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMIP4Config *config; NMSettingIPConfig *s_ip4; NMPlatformIP4Address address = { .addr_source = NM_IP_CONFIG_SOURCE_SHARED, @@ -9673,42 +9665,24 @@ shared4_new_config (NMDevice *self, NMConnection *connection) g_return_val_if_fail (connection, NULL); s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip4 && nm_setting_ip_config_get_num_addresses (s_ip4)) { + if ( s_ip4 + && nm_setting_ip_config_get_num_addresses (s_ip4) > 0) { /* Use the first user-supplied address */ NMIPAddress *user = nm_setting_ip_config_get_address (s_ip4, 0); in_addr_t a; nm_ip_address_get_address_binary (user, &a); nm_platform_ip4_address_set_addr (&address, a, nm_ip_address_get_prefix (user)); + nm_clear_pointer (&priv->shared_ip_handle, nm_netns_shared_ip_release); } else { - /* Find an unused address in the 10.42.x.x range */ - guint32 start = (guint32) ntohl (0x0a2a0001); /* 10.42.0.1 */ - guint32 count = 0; - - if (G_UNLIKELY (!shared_ips)) - shared_ips = g_hash_table_new (nm_direct_hash, NULL); - else { - while (g_hash_table_lookup (shared_ips, GUINT_TO_POINTER (start + count))) { - count += ntohl (0x100); - if (count > ntohl (0xFE00)) { - _LOGE (LOGD_SHARING, "ran out of shared IP addresses!"); - return FALSE; - } - } - } - nm_platform_ip4_address_set_addr (&address, start + count, 24); - g_hash_table_add (shared_ips, GUINT_TO_POINTER (address.address)); - is_generated = TRUE; + if (!priv->shared_ip_handle) + priv->shared_ip_handle = nm_netns_shared_ip_reserve (nm_device_get_netns (self)); + nm_platform_ip4_address_set_addr (&address, priv->shared_ip_handle->addr, 24); } config = nm_device_ip4_config_new (self); nm_ip4_config_add_address (config, &address); - if (is_generated) { - /* Remove the address lock when the object gets disposed */ - g_object_set_qdata_full (G_OBJECT (config), NM_CACHED_QUARK ("shared-ip"), - GUINT_TO_POINTER (address.address), - shared_ip_release); - } + return config; } @@ -15936,6 +15910,8 @@ _cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type) queued_state_clear (self); + nm_clear_pointer (&priv->shared_ip_handle, nm_netns_shared_ip_release); + _cleanup_ip_pre (self, AF_INET, cleanup_type); _cleanup_ip_pre (self, AF_INET6, cleanup_type); } diff --git a/src/nm-netns.c b/src/nm-netns.c index cf0e5f0b6b..a9596eaf00 100644 --- a/src/nm-netns.c +++ b/src/nm-netns.c @@ -28,6 +28,7 @@ typedef struct { NMPNetns *platform_netns; NMPRulesManager *rules_manager; GHashTable *l3cfgs; + GHashTable *shared_ips; CList l3cfg_signal_pending_lst_head; guint signal_pending_idle_id; } NMNetnsPrivate; @@ -218,6 +219,112 @@ _platform_signal_cb (NMPlatform *platform, /*****************************************************************************/ +NMNetnsSharedIPHandle * +nm_netns_shared_ip_reserve (NMNetns *self) +{ + NMNetnsPrivate *priv; + NMNetnsSharedIPHandle *handle; + const in_addr_t addr_start = ntohl (0x0a2a0001u); /* 10.42.0.1 */ + in_addr_t addr; + char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + + /* Find an unused address in the 10.42.x.x range */ + + g_return_val_if_fail (NM_IS_NETNS (self), NULL); + + priv = NM_NETNS_GET_PRIVATE (self); + + if (!priv->shared_ips) { + addr = addr_start; + priv->shared_ips = g_hash_table_new (nm_puint32_hash, nm_puint32_equals); + g_object_ref (self); + } else { + guint32 count; + + nm_assert (g_hash_table_size (priv->shared_ips) > 0); + + count = 0u; + for (;;) { + addr = addr_start + htonl (count << 8u); + + handle = g_hash_table_lookup (priv->shared_ips, &addr); + if (!handle) + break; + + count++; + + if (count > 0xFFu) { + if (handle->_ref_count == 1) { + _LOGE ("shared-ip4: ran out of shared IP addresses. Reuse %s/24", + _nm_utils_inet4_ntop (handle->addr, sbuf_addr)); + } else { + _LOGD ("shared-ip4: reserved IP address range %s/24 (duplicate)", + _nm_utils_inet4_ntop (handle->addr, sbuf_addr)); + } + handle->_ref_count++; + return handle; + } + } + } + + handle = g_slice_new (NMNetnsSharedIPHandle); + *handle = (NMNetnsSharedIPHandle) { + .addr = addr, + ._ref_count = 1, + ._self = self, + }; + + g_hash_table_add (priv->shared_ips, handle); + + _LOGD ("shared-ip4: reserved IP address range %s/24", + _nm_utils_inet4_ntop (handle->addr, sbuf_addr)); + return handle; +} + +void +nm_netns_shared_ip_release (NMNetnsSharedIPHandle *handle) +{ + NMNetns *self; + NMNetnsPrivate *priv; + char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + + g_return_if_fail (handle); + + self = handle->_self; + + g_return_if_fail (NM_IS_NETNS (self)); + + priv = NM_NETNS_GET_PRIVATE (self); + + nm_assert (handle->_ref_count > 0); + nm_assert (handle == nm_g_hash_table_lookup (priv->shared_ips, handle)); + + if (handle->_ref_count > 1) { + nm_assert (handle->addr == ntohl (0x0A2AFF01u)); /* 10.42.255.1 */ + handle->_ref_count--; + _LOGD ("shared-ip4: release IP address range %s/24 (%d more references held)", + _nm_utils_inet4_ntop (handle->addr, sbuf_addr), + handle->_ref_count); + return; + } + + if (!g_hash_table_remove (priv->shared_ips, handle)) + nm_assert_not_reached (); + + if (g_hash_table_size (priv->shared_ips) == 0) { + nm_clear_pointer (&priv->shared_ips, g_hash_table_unref); + g_object_unref (self); + } + + _LOGD ("shared-ip4: release IP address range %s/24", + _nm_utils_inet4_ntop (handle->addr, sbuf_addr)); + + handle->_self = NULL; + nm_g_slice_free (handle); +} + +/*****************************************************************************/ + static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) @@ -312,6 +419,7 @@ dispose (GObject *object) nm_assert (nm_g_hash_table_size (priv->l3cfgs) == 0); nm_assert (c_list_is_empty (&priv->l3cfg_signal_pending_lst_head)); + nm_assert (!priv->shared_ips); nm_clear_g_source (&priv->signal_pending_idle_id); diff --git a/src/nm-netns.h b/src/nm-netns.h index 2af0242b8d..080caa30e3 100644 --- a/src/nm-netns.h +++ b/src/nm-netns.h @@ -34,4 +34,16 @@ struct _NMDedupMultiIndex *nm_netns_get_multi_idx (NMNetns *self); NML3Cfg *nm_netns_access_l3cfg (NMNetns *netns, int ifindex); +/*****************************************************************************/ + +typedef struct { + in_addr_t addr; + int _ref_count; + NMNetns *_self; +} NMNetnsSharedIPHandle; + +NMNetnsSharedIPHandle *nm_netns_shared_ip_reserve (NMNetns *self); + +void nm_netns_shared_ip_release (NMNetnsSharedIPHandle *handle); + #endif /* __NM_NETNS_H__ */ |