core: add nm_netns_shared_ip_reserve() API

Add a better way of tracking the shared IP addresses that are in use.
This will replace NMDevice's usage of a global hash table. For one, the
API is more formalized with reserve() and release() functions.
Also, it ties the used IP addresses to the netns, which would be more
correct (in the future when we may support more netns).
This commit is contained in:
Thomas Haller 2020-09-14 15:07:18 +02:00
parent 991999489a
commit 3fcfb53c4b
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
2 changed files with 120 additions and 0 deletions

View file

@ -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);

View file

@ -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__ */