mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-20 07:00:05 +01:00
core: generalize IP reservation functions
Generalize the functions to reserve an IP address from the netns, so that it becomes easy to define new IP ranges for different purposes.
This commit is contained in:
parent
1504d12714
commit
d3e4f3344e
4 changed files with 149 additions and 95 deletions
|
|
@ -265,11 +265,11 @@ typedef struct {
|
||||||
NMDeviceIPState state;
|
NMDeviceIPState state;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
NMDnsMasqManager *dnsmasq_manager;
|
NMDnsMasqManager *dnsmasq_manager;
|
||||||
NMNetnsSharedIPHandle *shared_ip_handle;
|
NMNetnsIPReservation *ip_reservation;
|
||||||
NMFirewallConfig *firewall_config;
|
NMFirewallConfig *firewall_config;
|
||||||
gulong dnsmasq_state_id;
|
gulong dnsmasq_state_id;
|
||||||
const NML3ConfigData *l3cd;
|
const NML3ConfigData *l3cd;
|
||||||
} v4;
|
} v4;
|
||||||
struct {
|
struct {
|
||||||
} v6;
|
} 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.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);
|
nm_clear_l3cd(&priv->ipshared_data_4.v4.l3cd);
|
||||||
|
|
||||||
_dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SHARED_4, NULL, FALSE);
|
_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_ip_address_get_address_binary(user, &a);
|
||||||
nm_platform_ip4_address_set_addr(&address, a, nm_ip_address_get_prefix(user));
|
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 {
|
} else {
|
||||||
if (!priv->ipshared_data_4.v4.shared_ip_handle)
|
if (!priv->ipshared_data_4.v4.ip_reservation)
|
||||||
priv->ipshared_data_4.v4.shared_ip_handle =
|
priv->ipshared_data_4.v4.ip_reservation =
|
||||||
nm_netns_shared_ip_reserve(nm_device_get_netns(self));
|
nm_netns_ip_reservation_get(nm_device_get_netns(self),
|
||||||
|
NM_NETNS_IP_RESERVATION_TYPE_SHARED4);
|
||||||
nm_platform_ip4_address_set_addr(&address,
|
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);
|
24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ typedef struct {
|
||||||
NMPNetns *platform_netns;
|
NMPNetns *platform_netns;
|
||||||
NMPGlobalTracker *global_tracker;
|
NMPGlobalTracker *global_tracker;
|
||||||
GHashTable *l3cfgs;
|
GHashTable *l3cfgs;
|
||||||
GHashTable *shared_ips;
|
GHashTable *ip_reservation[_NM_NETNS_IP_RESERVATION_TYPE_NUM];
|
||||||
GHashTable *ecmp_track_by_obj;
|
GHashTable *ecmp_track_by_obj;
|
||||||
GHashTable *ecmp_track_by_ecmpid;
|
GHashTable *ecmp_track_by_ecmpid;
|
||||||
|
|
||||||
|
|
@ -571,106 +571,150 @@ notify_watcher:
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
NMNetnsSharedIPHandle *
|
typedef struct {
|
||||||
nm_netns_shared_ip_reserve(NMNetns *self)
|
const char *name;
|
||||||
{
|
guint32 start_addr; /* host byte order */
|
||||||
NMNetnsPrivate *priv;
|
guint prefix_len;
|
||||||
NMNetnsSharedIPHandle *handle;
|
guint num_addrs;
|
||||||
const in_addr_t addr_start = ntohl(0x0a2a0001u); /* 10.42.0.1 */
|
gboolean allow_reuse;
|
||||||
in_addr_t addr;
|
} IPReservationTypeDesc;
|
||||||
char sbuf_addr[NM_INET_ADDRSTRLEN];
|
|
||||||
|
|
||||||
/* 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(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) {
|
if (!*table) {
|
||||||
addr = addr_start;
|
addr = htonl(desc->start_addr);
|
||||||
priv->shared_ips = g_hash_table_new(nm_puint32_hash, nm_puint32_equal);
|
*table = g_hash_table_new(nm_puint32_hash, nm_puint32_equal);
|
||||||
g_object_ref(self);
|
g_object_ref(self);
|
||||||
} else {
|
} else {
|
||||||
guint32 count;
|
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;
|
count = 0u;
|
||||||
for (;;) {
|
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);
|
res = g_hash_table_lookup(*table, &addr);
|
||||||
if (!handle)
|
if (!res)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if (count > 0xFFu) {
|
if (count >= desc->num_addrs) {
|
||||||
if (handle->_ref_count == 1) {
|
if (!desc->allow_reuse) {
|
||||||
_LOGE("shared-ip4: ran out of shared IP addresses. Reuse %s/24",
|
_LOGE("%s: ran out of IP addresses", desc->name);
|
||||||
nm_inet4_ntop(handle->addr, sbuf_addr));
|
return NULL;
|
||||||
} else {
|
|
||||||
_LOGD("shared-ip4: reserved IP address range %s/24 (duplicate)",
|
|
||||||
nm_inet4_ntop(handle->addr, sbuf_addr));
|
|
||||||
}
|
}
|
||||||
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);
|
res = g_slice_new(NMNetnsIPReservation);
|
||||||
*handle = (NMNetnsSharedIPHandle) {
|
*res = (NMNetnsIPReservation) {
|
||||||
.addr = addr,
|
.addr = addr,
|
||||||
._ref_count = 1,
|
._ref_count = 1,
|
||||||
._self = self,
|
._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));
|
_LOGD("%s: reserved IP address %s/%u",
|
||||||
return handle;
|
desc->name,
|
||||||
|
nm_inet4_ntop(res->addr, buf),
|
||||||
|
desc->prefix_len);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nm_netns_shared_ip_release(NMNetnsSharedIPHandle *handle)
|
nm_netns_ip_reservation_release(NMNetnsIPReservation *res)
|
||||||
{
|
{
|
||||||
NMNetns *self;
|
NMNetns *self;
|
||||||
NMNetnsPrivate *priv;
|
NMNetnsPrivate *priv;
|
||||||
char sbuf_addr[NM_INET_ADDRSTRLEN];
|
const IPReservationTypeDesc *desc;
|
||||||
|
GHashTable **table;
|
||||||
|
char buf[NM_INET_ADDRSTRLEN];
|
||||||
|
|
||||||
g_return_if_fail(handle);
|
g_return_if_fail(res);
|
||||||
|
g_return_if_fail(res->_type < _NM_NETNS_IP_RESERVATION_TYPE_NUM);
|
||||||
self = handle->_self;
|
|
||||||
|
|
||||||
|
self = res->_self;
|
||||||
g_return_if_fail(NM_IS_NETNS(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(res->_ref_count > 0);
|
||||||
nm_assert(handle == nm_g_hash_table_lookup(priv->shared_ips, handle));
|
nm_assert(res == nm_g_hash_table_lookup(*table, res));
|
||||||
|
|
||||||
if (handle->_ref_count > 1) {
|
if (res->_ref_count > 1) {
|
||||||
nm_assert(handle->addr == ntohl(0x0A2AFF01u)); /* 10.42.255.1 */
|
nm_assert(desc->allow_reuse);
|
||||||
handle->_ref_count--;
|
res->_ref_count--;
|
||||||
_LOGD("shared-ip4: release IP address range %s/24 (%d more references held)",
|
_LOGD("%s: release IP address reservation %s/%u (%d more references held)",
|
||||||
nm_inet4_ntop(handle->addr, sbuf_addr),
|
desc->name,
|
||||||
handle->_ref_count);
|
nm_inet4_ntop(res->addr, buf),
|
||||||
|
desc->prefix_len,
|
||||||
|
res->_ref_count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_hash_table_remove(priv->shared_ips, handle))
|
if (!g_hash_table_remove(*table, res))
|
||||||
nm_assert_not_reached();
|
nm_assert_not_reached();
|
||||||
|
|
||||||
if (g_hash_table_size(priv->shared_ips) == 0) {
|
if (g_hash_table_size(*table) == 0) {
|
||||||
nm_clear_pointer(&priv->shared_ips, g_hash_table_unref);
|
nm_clear_pointer(table, g_hash_table_unref);
|
||||||
g_object_unref(self);
|
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;
|
res->_self = NULL;
|
||||||
nm_g_slice_free(handle);
|
nm_g_slice_free(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
@ -1560,11 +1604,14 @@ dispose(GObject *object)
|
||||||
|
|
||||||
nm_assert(nm_g_hash_table_size(priv->l3cfgs) == 0);
|
nm_assert(nm_g_hash_table_size(priv->l3cfgs) == 0);
|
||||||
nm_assert(c_list_is_empty(&priv->l3cfg_signal_pending_lst_head));
|
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_idx) == 0);
|
||||||
nm_assert(nm_g_hash_table_size(priv->watcher_by_tag_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);
|
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_obj, g_hash_table_destroy);
|
||||||
nm_clear_pointer(&priv->ecmp_track_by_ecmpid, g_hash_table_destroy);
|
nm_clear_pointer(&priv->ecmp_track_by_ecmpid, g_hash_table_destroy);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
typedef struct {
|
||||||
in_addr_t addr;
|
in_addr_t addr;
|
||||||
int _ref_count;
|
int _ref_count;
|
||||||
NMNetns *_self;
|
NMNetnsIPReservationType _type;
|
||||||
} NMNetnsSharedIPHandle;
|
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);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@
|
||||||
#include "nm-test-utils-core.h"
|
#include "nm-test-utils-core.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_shared_ip(void)
|
test_ip_reservation_shared4(void)
|
||||||
{
|
{
|
||||||
gs_unref_object NMPlatform *platform = NULL;
|
gs_unref_object NMPlatform *platform = NULL;
|
||||||
gs_unref_object NMNetns *netns = NULL;
|
gs_unref_object NMNetns *netns = NULL;
|
||||||
NMNetnsSharedIPHandle *handles[256];
|
NMNetnsIPReservation *res[256];
|
||||||
NMNetnsSharedIPHandle *handle1;
|
NMNetnsIPReservation *res1;
|
||||||
NMNetnsSharedIPHandle *handle2;
|
NMNetnsIPReservation *res2;
|
||||||
char buf[NM_INET_ADDRSTRLEN];
|
char buf[NM_INET_ADDRSTRLEN];
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
|
|
@ -21,36 +21,35 @@ test_shared_ip(void)
|
||||||
|
|
||||||
/* Allocate addresses from 10.42.0.1 to 10.42.255.1 */
|
/* Allocate addresses from 10.42.0.1 to 10.42.255.1 */
|
||||||
for (i = 0; i < 256; i++) {
|
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);
|
g_snprintf(buf, sizeof(buf), "10.42.%u.1", i);
|
||||||
nmtst_assert_ip4_address(handles[i]->addr, buf);
|
nmtst_assert_ip4_address(res[i]->addr, buf);
|
||||||
g_assert_cmpint(handles[i]->_ref_count, ==, 1);
|
g_assert_cmpint(res[i]->_ref_count, ==, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release an address and get it back */
|
/* Release an address and get it back */
|
||||||
nm_netns_shared_ip_release(handles[139]);
|
nm_netns_ip_reservation_release(res[139]);
|
||||||
handles[139] = nm_netns_shared_ip_reserve(netns);
|
res[139] = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4);
|
||||||
nmtst_assert_ip4_address(handles[139]->addr, "10.42.139.1");
|
nmtst_assert_ip4_address(res[139]->addr, "10.42.139.1");
|
||||||
|
|
||||||
/* Reuse 10.42.255.1 once */
|
/* Reuse 10.42.255.1 once */
|
||||||
NMTST_EXPECT_NM_ERROR(
|
NMTST_EXPECT_NM_ERROR("netns[*]: shared-ip4: ran out of IP addresses. Reuse 10.42.255.1/24");
|
||||||
"netns[*]: shared-ip4: ran out of shared IP addresses. Reuse 10.42.255.1/24");
|
res1 = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4);
|
||||||
handle1 = nm_netns_shared_ip_reserve(netns);
|
|
||||||
g_test_assert_expected_messages();
|
g_test_assert_expected_messages();
|
||||||
nmtst_assert_ip4_address(handle1->addr, "10.42.255.1");
|
nmtst_assert_ip4_address(res1->addr, "10.42.255.1");
|
||||||
g_assert_cmpint(handle1->_ref_count, ==, 2);
|
g_assert_cmpint(res1->_ref_count, ==, 2);
|
||||||
|
|
||||||
/* Reuse 10.42.255.1 twice */
|
/* Reuse 10.42.255.1 twice */
|
||||||
handle2 = nm_netns_shared_ip_reserve(netns);
|
res2 = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4);
|
||||||
g_assert(handle2 == handle1);
|
g_assert(res2 == res1);
|
||||||
nmtst_assert_ip4_address(handle1->addr, "10.42.255.1");
|
nmtst_assert_ip4_address(res1->addr, "10.42.255.1");
|
||||||
g_assert_cmpint(handle2->_ref_count, ==, 3);
|
g_assert_cmpint(res2->_ref_count, ==, 3);
|
||||||
|
|
||||||
/* Release all */
|
/* Release all */
|
||||||
nm_netns_shared_ip_release(handle1);
|
nm_netns_ip_reservation_release(res1);
|
||||||
nm_netns_shared_ip_release(handle2);
|
nm_netns_ip_reservation_release(res2);
|
||||||
for (i = 0; i < 256; i++) {
|
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");
|
nmtst_init_with_logging(&argc, &argv, NULL, "ALL");
|
||||||
nm_linux_platform_setup();
|
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();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue