mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-20 08:10:06 +01:00
merge: branch 'bg/ip-reservation'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2276
This commit is contained in:
commit
d8971cceed
5 changed files with 197 additions and 72 deletions
|
|
@ -266,7 +266,7 @@ typedef struct {
|
||||||
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;
|
||||||
|
|
@ -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 */
|
||||||
|
guint prefix_len;
|
||||||
|
guint num_addrs;
|
||||||
|
gboolean allow_reuse;
|
||||||
|
} IPReservationTypeDesc;
|
||||||
|
|
||||||
|
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;
|
NMNetnsPrivate *priv;
|
||||||
NMNetnsSharedIPHandle *handle;
|
const IPReservationTypeDesc *desc;
|
||||||
const in_addr_t addr_start = ntohl(0x0a2a0001u); /* 10.42.0.1 */
|
NMNetnsIPReservation *res;
|
||||||
|
GHashTable **table;
|
||||||
in_addr_t addr;
|
in_addr_t addr;
|
||||||
char sbuf_addr[NM_INET_ADDRSTRLEN];
|
char buf[NM_INET_ADDRSTRLEN];
|
||||||
|
|
||||||
/* Find an unused address in the 10.42.x.x range */
|
|
||||||
|
|
||||||
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;
|
||||||
|
NMNetnsIPReservationType _type;
|
||||||
NMNetns *_self;
|
NMNetns *_self;
|
||||||
} NMNetnsSharedIPHandle;
|
} 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,6 +6,7 @@ test_units = [
|
||||||
'test-core',
|
'test-core',
|
||||||
'test-core-with-expect',
|
'test-core-with-expect',
|
||||||
'test-dcb',
|
'test-dcb',
|
||||||
|
'test-netns',
|
||||||
'test-l3cfg',
|
'test-l3cfg',
|
||||||
'test-utils',
|
'test-utils',
|
||||||
'test-wired-defname',
|
'test-wired-defname',
|
||||||
|
|
|
||||||
69
src/core/tests/test-netns.c
Normal file
69
src/core/tests/test-netns.c
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "src/core/nm-default-daemon.h"
|
||||||
|
|
||||||
|
#include "nm-netns.h"
|
||||||
|
#include "nm-test-utils-core.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_ip_reservation_shared4(void)
|
||||||
|
{
|
||||||
|
gs_unref_object NMPlatform *platform = NULL;
|
||||||
|
gs_unref_object NMNetns *netns = NULL;
|
||||||
|
NMNetnsIPReservation *res[256];
|
||||||
|
NMNetnsIPReservation *res1;
|
||||||
|
NMNetnsIPReservation *res2;
|
||||||
|
char buf[NM_INET_ADDRSTRLEN];
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
platform = g_object_ref(NM_PLATFORM_GET);
|
||||||
|
netns = nm_netns_new(platform);
|
||||||
|
|
||||||
|
/* Allocate addresses from 10.42.0.1 to 10.42.255.1 */
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
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(res[i]->addr, buf);
|
||||||
|
g_assert_cmpint(res[i]->_ref_count, ==, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release an address and get it back */
|
||||||
|
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 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(res1->addr, "10.42.255.1");
|
||||||
|
g_assert_cmpint(res1->_ref_count, ==, 2);
|
||||||
|
|
||||||
|
/* Reuse 10.42.255.1 twice */
|
||||||
|
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_ip_reservation_release(res1);
|
||||||
|
nm_netns_ip_reservation_release(res2);
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
nm_netns_ip_reservation_release(res[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
NMTST_DEFINE();
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
nmtst_init_with_logging(&argc, &argv, NULL, "ALL");
|
||||||
|
nm_linux_platform_setup();
|
||||||
|
|
||||||
|
g_test_add_func("/netns/ip_reservation/shared4", test_ip_reservation_shared4);
|
||||||
|
|
||||||
|
return g_test_run();
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue