diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 63a29c2df6..d4ca304adf 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -265,11 +265,11 @@ typedef struct { NMDeviceIPState state; union { struct { - NMDnsMasqManager *dnsmasq_manager; - NMNetnsSharedIPHandle *shared_ip_handle; - NMFirewallConfig *firewall_config; - gulong dnsmasq_state_id; - const NML3ConfigData *l3cd; + NMDnsMasqManager *dnsmasq_manager; + NMNetnsIPReservation *ip_reservation; + NMFirewallConfig *firewall_config; + gulong dnsmasq_state_id; + const NML3ConfigData *l3cd; } v4; struct { } v6; @@ -13524,7 +13524,7 @@ _dev_ipsharedx_cleanup(NMDevice *self, int addr_family) nm_clear_pointer(&priv->ipshared_data_4.v4.firewall_config, nm_firewall_config_free); } - nm_clear_pointer(&priv->ipshared_data_4.v4.shared_ip_handle, nm_netns_shared_ip_release); + nm_clear_pointer(&priv->ipshared_data_4.v4.ip_reservation, nm_netns_ip_reservation_release); nm_clear_l3cd(&priv->ipshared_data_4.v4.l3cd); _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SHARED_4, NULL, FALSE); @@ -13558,13 +13558,14 @@ _dev_ipshared4_new_l3cd(NMDevice *self, NMConnection *connection, NMPlatformIP4A 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->ipshared_data_4.v4.shared_ip_handle, nm_netns_shared_ip_release); + nm_clear_pointer(&priv->ipshared_data_4.v4.ip_reservation, nm_netns_ip_reservation_release); } else { - if (!priv->ipshared_data_4.v4.shared_ip_handle) - priv->ipshared_data_4.v4.shared_ip_handle = - nm_netns_shared_ip_reserve(nm_device_get_netns(self)); + if (!priv->ipshared_data_4.v4.ip_reservation) + priv->ipshared_data_4.v4.ip_reservation = + nm_netns_ip_reservation_get(nm_device_get_netns(self), + NM_NETNS_IP_RESERVATION_TYPE_SHARED4); nm_platform_ip4_address_set_addr(&address, - priv->ipshared_data_4.v4.shared_ip_handle->addr, + priv->ipshared_data_4.v4.ip_reservation->addr, 24); } diff --git a/src/core/nm-netns.c b/src/core/nm-netns.c index f481bc3676..7e4b3ccc15 100644 --- a/src/core/nm-netns.c +++ b/src/core/nm-netns.c @@ -68,7 +68,7 @@ typedef struct { NMPNetns *platform_netns; NMPGlobalTracker *global_tracker; GHashTable *l3cfgs; - GHashTable *shared_ips; + GHashTable *ip_reservation[_NM_NETNS_IP_RESERVATION_TYPE_NUM]; GHashTable *ecmp_track_by_obj; GHashTable *ecmp_track_by_ecmpid; @@ -571,106 +571,150 @@ notify_watcher: /*****************************************************************************/ -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_INET_ADDRSTRLEN]; +typedef struct { + const char *name; + guint32 start_addr; /* host byte order */ + guint prefix_len; + guint num_addrs; + gboolean allow_reuse; +} IPReservationTypeDesc; - /* Find an unused address in the 10.42.x.x range */ +static const IPReservationTypeDesc ip_reservation_types[_NM_NETNS_IP_RESERVATION_TYPE_NUM] = { + [NM_NETNS_IP_RESERVATION_TYPE_SHARED4] = + { + .name = "shared-ip4", + .start_addr = 0x0a2a0001, /* 10.42.0.1 */ + .prefix_len = 24, + .num_addrs = 256, + .allow_reuse = TRUE, + }, +}; + +NMNetnsIPReservation * +nm_netns_ip_reservation_get(NMNetns *self, NMNetnsIPReservationType type) +{ + NMNetnsPrivate *priv; + const IPReservationTypeDesc *desc; + NMNetnsIPReservation *res; + GHashTable **table; + in_addr_t addr; + char buf[NM_INET_ADDRSTRLEN]; g_return_val_if_fail(NM_IS_NETNS(self), NULL); + g_return_val_if_fail(type < _NM_NETNS_IP_RESERVATION_TYPE_NUM, NULL); - priv = NM_NETNS_GET_PRIVATE(self); + priv = NM_NETNS_GET_PRIVATE(self); + desc = &ip_reservation_types[type]; + table = &priv->ip_reservation[type]; - if (!priv->shared_ips) { - addr = addr_start; - priv->shared_ips = g_hash_table_new(nm_puint32_hash, nm_puint32_equal); + if (!*table) { + addr = htonl(desc->start_addr); + *table = g_hash_table_new(nm_puint32_hash, nm_puint32_equal); g_object_ref(self); } else { guint32 count; - nm_assert(g_hash_table_size(priv->shared_ips) > 0); + nm_assert(g_hash_table_size(*table) > 0); + nm_assert(desc->prefix_len > 0 && desc->prefix_len <= 32); count = 0u; for (;;) { - addr = addr_start + htonl(count << 8u); + addr = htonl(desc->start_addr + (count << (32 - desc->prefix_len))); - handle = g_hash_table_lookup(priv->shared_ips, &addr); - if (!handle) + res = g_hash_table_lookup(*table, &addr); + if (!res) break; count++; - if (count > 0xFFu) { - if (handle->_ref_count == 1) { - _LOGE("shared-ip4: ran out of shared IP addresses. Reuse %s/24", - nm_inet4_ntop(handle->addr, sbuf_addr)); - } else { - _LOGD("shared-ip4: reserved IP address range %s/24 (duplicate)", - nm_inet4_ntop(handle->addr, sbuf_addr)); + if (count >= desc->num_addrs) { + if (!desc->allow_reuse) { + _LOGE("%s: ran out of IP addresses", desc->name); + return NULL; } - handle->_ref_count++; - return handle; + + if (res->_ref_count == 1) { + _LOGE("%s: ran out of IP addresses. Reuse %s/%u", + desc->name, + nm_inet4_ntop(res->addr, buf), + desc->prefix_len); + } else { + _LOGD("%s: reserved IP address %s/%u (duplicate)", + desc->name, + nm_inet4_ntop(res->addr, buf), + desc->prefix_len); + } + res->_ref_count++; + return res; } } } - handle = g_slice_new(NMNetnsSharedIPHandle); - *handle = (NMNetnsSharedIPHandle) { + res = g_slice_new(NMNetnsIPReservation); + *res = (NMNetnsIPReservation) { .addr = addr, ._ref_count = 1, ._self = self, + ._type = type, }; - g_hash_table_add(priv->shared_ips, handle); + g_hash_table_add(*table, res); - _LOGD("shared-ip4: reserved IP address range %s/24", nm_inet4_ntop(handle->addr, sbuf_addr)); - return handle; + _LOGD("%s: reserved IP address %s/%u", + desc->name, + nm_inet4_ntop(res->addr, buf), + desc->prefix_len); + return res; } void -nm_netns_shared_ip_release(NMNetnsSharedIPHandle *handle) +nm_netns_ip_reservation_release(NMNetnsIPReservation *res) { - NMNetns *self; - NMNetnsPrivate *priv; - char sbuf_addr[NM_INET_ADDRSTRLEN]; + NMNetns *self; + NMNetnsPrivate *priv; + const IPReservationTypeDesc *desc; + GHashTable **table; + char buf[NM_INET_ADDRSTRLEN]; - g_return_if_fail(handle); - - self = handle->_self; + g_return_if_fail(res); + g_return_if_fail(res->_type < _NM_NETNS_IP_RESERVATION_TYPE_NUM); + self = res->_self; g_return_if_fail(NM_IS_NETNS(self)); - priv = NM_NETNS_GET_PRIVATE(self); + priv = NM_NETNS_GET_PRIVATE(self); + desc = &ip_reservation_types[res->_type]; + table = &priv->ip_reservation[res->_type]; - nm_assert(handle->_ref_count > 0); - nm_assert(handle == nm_g_hash_table_lookup(priv->shared_ips, handle)); + nm_assert(res->_ref_count > 0); + nm_assert(res == nm_g_hash_table_lookup(*table, res)); - 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_inet4_ntop(handle->addr, sbuf_addr), - handle->_ref_count); + if (res->_ref_count > 1) { + nm_assert(desc->allow_reuse); + res->_ref_count--; + _LOGD("%s: release IP address reservation %s/%u (%d more references held)", + desc->name, + nm_inet4_ntop(res->addr, buf), + desc->prefix_len, + res->_ref_count); return; } - if (!g_hash_table_remove(priv->shared_ips, handle)) + if (!g_hash_table_remove(*table, res)) nm_assert_not_reached(); - if (g_hash_table_size(priv->shared_ips) == 0) { - nm_clear_pointer(&priv->shared_ips, g_hash_table_unref); + if (g_hash_table_size(*table) == 0) { + nm_clear_pointer(table, g_hash_table_unref); g_object_unref(self); } - _LOGD("shared-ip4: release IP address range %s/24", nm_inet4_ntop(handle->addr, sbuf_addr)); + _LOGD("%s: release IP address reservation %s/%u", + desc->name, + nm_inet4_ntop(res->addr, buf), + desc->prefix_len); - handle->_self = NULL; - nm_g_slice_free(handle); + res->_self = NULL; + nm_g_slice_free(res); } /*****************************************************************************/ @@ -1560,11 +1604,14 @@ 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_assert(nm_g_hash_table_size(priv->watcher_idx) == 0); nm_assert(nm_g_hash_table_size(priv->watcher_by_tag_idx) == 0); nm_assert(nm_g_hash_table_size(priv->watcher_ip_data_idx) == 0); + for (guint i = 0; i < _NM_NETNS_IP_RESERVATION_TYPE_NUM; i++) { + nm_assert(!priv->ip_reservation[i]); + } + nm_clear_pointer(&priv->ecmp_track_by_obj, g_hash_table_destroy); nm_clear_pointer(&priv->ecmp_track_by_ecmpid, g_hash_table_destroy); diff --git a/src/core/nm-netns.h b/src/core/nm-netns.h index 43e9c7818a..5ddb852ad5 100644 --- a/src/core/nm-netns.h +++ b/src/core/nm-netns.h @@ -41,15 +41,22 @@ NML3Cfg *nm_netns_l3cfg_acquire(NMNetns *netns, int ifindex); /*****************************************************************************/ +typedef enum { + NM_NETNS_IP_RESERVATION_TYPE_SHARED4, + + _NM_NETNS_IP_RESERVATION_TYPE_NUM, +} NMNetnsIPReservationType; + typedef struct { - in_addr_t addr; - int _ref_count; - NMNetns *_self; -} NMNetnsSharedIPHandle; + in_addr_t addr; + int _ref_count; + NMNetnsIPReservationType _type; + NMNetns *_self; +} NMNetnsIPReservation; -NMNetnsSharedIPHandle *nm_netns_shared_ip_reserve(NMNetns *self); +NMNetnsIPReservation *nm_netns_ip_reservation_get(NMNetns *self, NMNetnsIPReservationType type); -void nm_netns_shared_ip_release(NMNetnsSharedIPHandle *handle); +void nm_netns_ip_reservation_release(NMNetnsIPReservation *reservation); /*****************************************************************************/ diff --git a/src/core/tests/test-netns.c b/src/core/tests/test-netns.c index e54c99e813..26ecbcb8b8 100644 --- a/src/core/tests/test-netns.c +++ b/src/core/tests/test-netns.c @@ -6,13 +6,13 @@ #include "nm-test-utils-core.h" static void -test_shared_ip(void) +test_ip_reservation_shared4(void) { gs_unref_object NMPlatform *platform = NULL; gs_unref_object NMNetns *netns = NULL; - NMNetnsSharedIPHandle *handles[256]; - NMNetnsSharedIPHandle *handle1; - NMNetnsSharedIPHandle *handle2; + NMNetnsIPReservation *res[256]; + NMNetnsIPReservation *res1; + NMNetnsIPReservation *res2; char buf[NM_INET_ADDRSTRLEN]; guint i; @@ -21,36 +21,35 @@ test_shared_ip(void) /* Allocate addresses from 10.42.0.1 to 10.42.255.1 */ for (i = 0; i < 256; i++) { - handles[i] = nm_netns_shared_ip_reserve(netns); + res[i] = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4); g_snprintf(buf, sizeof(buf), "10.42.%u.1", i); - nmtst_assert_ip4_address(handles[i]->addr, buf); - g_assert_cmpint(handles[i]->_ref_count, ==, 1); + nmtst_assert_ip4_address(res[i]->addr, buf); + g_assert_cmpint(res[i]->_ref_count, ==, 1); } /* Release an address and get it back */ - nm_netns_shared_ip_release(handles[139]); - handles[139] = nm_netns_shared_ip_reserve(netns); - nmtst_assert_ip4_address(handles[139]->addr, "10.42.139.1"); + nm_netns_ip_reservation_release(res[139]); + res[139] = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4); + nmtst_assert_ip4_address(res[139]->addr, "10.42.139.1"); /* Reuse 10.42.255.1 once */ - NMTST_EXPECT_NM_ERROR( - "netns[*]: shared-ip4: ran out of shared IP addresses. Reuse 10.42.255.1/24"); - handle1 = nm_netns_shared_ip_reserve(netns); + NMTST_EXPECT_NM_ERROR("netns[*]: shared-ip4: ran out of IP addresses. Reuse 10.42.255.1/24"); + res1 = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4); g_test_assert_expected_messages(); - nmtst_assert_ip4_address(handle1->addr, "10.42.255.1"); - g_assert_cmpint(handle1->_ref_count, ==, 2); + nmtst_assert_ip4_address(res1->addr, "10.42.255.1"); + g_assert_cmpint(res1->_ref_count, ==, 2); /* Reuse 10.42.255.1 twice */ - handle2 = nm_netns_shared_ip_reserve(netns); - g_assert(handle2 == handle1); - nmtst_assert_ip4_address(handle1->addr, "10.42.255.1"); - g_assert_cmpint(handle2->_ref_count, ==, 3); + res2 = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4); + g_assert(res2 == res1); + nmtst_assert_ip4_address(res1->addr, "10.42.255.1"); + g_assert_cmpint(res2->_ref_count, ==, 3); /* Release all */ - nm_netns_shared_ip_release(handle1); - nm_netns_shared_ip_release(handle2); + nm_netns_ip_reservation_release(res1); + nm_netns_ip_reservation_release(res2); for (i = 0; i < 256; i++) { - nm_netns_shared_ip_release(handles[i]); + nm_netns_ip_reservation_release(res[i]); } } @@ -64,7 +63,7 @@ main(int argc, char **argv) nmtst_init_with_logging(&argc, &argv, NULL, "ALL"); nm_linux_platform_setup(); - g_test_add_func("/netns/shared_ip", test_shared_ip); + g_test_add_func("/netns/ip_reservation/shared4", test_ip_reservation_shared4); return g_test_run(); }