mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-11 11:00:17 +01:00
platform: track IPv4 subnets with prefix length in nm_platform_ip_address_sync()
The entire point of the dance in nm_platform_ip_address_sync() is to ensure that
conflicting IPv4 addresses are in their right order, that is, they have
the right primary/secondary flag.
Kernel only sets secondary flags for addresses that are in the same
subnet, and we also only care about the relative order of addresses
that are in the same subnet. In particular, because we rely on kernel's
"secondary" flag to implement this.
But kernel only treads addresses as secondary, if they share the exact
same subnet. For example, 192.168.0.5/24 and 192.168.0.6/25 would not
be treated as primary/secondary but just as unrelated addresses, even if
the address cleared of it's host part is the same.
This means, we must not only hash the network part of the addresses, but
also the prefix length. Implement that, by tracking the full NMPObject.
(cherry picked from commit 619dc2fcab)
This commit is contained in:
parent
a8e96e3c4b
commit
0bdb2e97d9
1 changed files with 41 additions and 21 deletions
|
|
@ -3797,6 +3797,30 @@ ip4_addr_subnets_destroy_index(GHashTable *subnets, const GPtrArray *addresses)
|
|||
g_hash_table_unref(subnets);
|
||||
}
|
||||
|
||||
static guint
|
||||
_ip4_addr_subnets_hash(gconstpointer ptr)
|
||||
{
|
||||
const NMPlatformIP4Address *addr = NMP_OBJECT_CAST_IP4_ADDRESS(ptr);
|
||||
NMHashState h;
|
||||
|
||||
nm_hash_init(&h, 3282159733);
|
||||
nm_hash_update_vals(&h,
|
||||
addr->plen,
|
||||
nm_utils_ip4_address_clear_host_address(addr->address, addr->plen));
|
||||
return nm_hash_complete(&h);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_ip4_addr_subnets_equal(gconstpointer p_a, gconstpointer p_b)
|
||||
{
|
||||
const NMPlatformIP4Address *a = NMP_OBJECT_CAST_IP4_ADDRESS(p_a);
|
||||
const NMPlatformIP4Address *b = NMP_OBJECT_CAST_IP4_ADDRESS(p_b);
|
||||
|
||||
return a->plen == b->plen
|
||||
&& (nm_utils_ip4_address_clear_host_address(a->address, a->plen)
|
||||
== nm_utils_ip4_address_clear_host_address(b->address, b->plen));
|
||||
}
|
||||
|
||||
static GHashTable *
|
||||
ip4_addr_subnets_build_index(const GPtrArray *addresses,
|
||||
gboolean consider_flags,
|
||||
|
|
@ -3807,34 +3831,35 @@ ip4_addr_subnets_build_index(const GPtrArray *addresses,
|
|||
|
||||
nm_assert(addresses && addresses->len);
|
||||
|
||||
subnets = g_hash_table_new(nm_direct_hash, NULL);
|
||||
subnets = g_hash_table_new(_ip4_addr_subnets_hash, _ip4_addr_subnets_equal);
|
||||
|
||||
/* Build a hash table of all addresses per subnet */
|
||||
for (i = 0; i < addresses->len; i++) {
|
||||
const NMPObject **p_obj;
|
||||
const NMPObject *obj;
|
||||
const NMPlatformIP4Address *address;
|
||||
gpointer p_address;
|
||||
GPtrArray *addr_list;
|
||||
guint32 net;
|
||||
int position;
|
||||
gpointer p;
|
||||
|
||||
if (!addresses->pdata[i])
|
||||
continue;
|
||||
|
||||
p_address = &addresses->pdata[i];
|
||||
address = NMP_OBJECT_CAST_IP4_ADDRESS(addresses->pdata[i]);
|
||||
p_obj = (const NMPObject **) &addresses->pdata[i];
|
||||
obj = *p_obj;
|
||||
|
||||
net = address->address & _nm_utils_ip4_prefix_to_netmask(address->plen);
|
||||
if (!g_hash_table_lookup_extended(subnets, GUINT_TO_POINTER(net), NULL, &p)) {
|
||||
g_hash_table_insert(subnets, GUINT_TO_POINTER(net), p_address);
|
||||
if (!g_hash_table_lookup_extended(subnets, obj, NULL, &p)) {
|
||||
g_hash_table_insert(subnets, (gpointer) obj, p_obj);
|
||||
continue;
|
||||
}
|
||||
nm_assert(p);
|
||||
|
||||
address = NMP_OBJECT_CAST_IP4_ADDRESS(obj);
|
||||
|
||||
if (full_index) {
|
||||
if (ip4_addr_subnets_is_plain_address(addresses, p)) {
|
||||
addr_list = g_ptr_array_new();
|
||||
g_hash_table_insert(subnets, GUINT_TO_POINTER(net), addr_list);
|
||||
g_hash_table_insert(subnets, (gpointer) obj, addr_list);
|
||||
g_ptr_array_add(addr_list, p);
|
||||
} else
|
||||
addr_list = p;
|
||||
|
|
@ -3843,13 +3868,13 @@ ip4_addr_subnets_build_index(const GPtrArray *addresses,
|
|||
position = -1; /* append */
|
||||
else
|
||||
position = 0; /* prepend */
|
||||
g_ptr_array_insert(addr_list, position, p_address);
|
||||
g_ptr_array_insert(addr_list, position, p_obj);
|
||||
} else {
|
||||
/* we only care about the primary. No need to track the secondaries
|
||||
* as a GPtrArray. */
|
||||
nm_assert(ip4_addr_subnets_is_plain_address(addresses, p));
|
||||
if (consider_flags && !NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_SECONDARY)) {
|
||||
g_hash_table_insert(subnets, GUINT_TO_POINTER(net), p_address);
|
||||
g_hash_table_insert(subnets, (gpointer) obj, p_obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3875,16 +3900,11 @@ ip4_addr_subnets_is_secondary(const NMPObject *address,
|
|||
const GPtrArray *addresses,
|
||||
const GPtrArray **out_addr_list)
|
||||
{
|
||||
const NMPlatformIP4Address *a;
|
||||
const GPtrArray *addr_list;
|
||||
gconstpointer p;
|
||||
guint32 net;
|
||||
const NMPObject **o;
|
||||
const GPtrArray *addr_list;
|
||||
gconstpointer p;
|
||||
const NMPObject **o;
|
||||
|
||||
a = NMP_OBJECT_CAST_IP4_ADDRESS(address);
|
||||
|
||||
net = a->address & _nm_utils_ip4_prefix_to_netmask(a->plen);
|
||||
p = g_hash_table_lookup(subnets, GUINT_TO_POINTER(net));
|
||||
p = g_hash_table_lookup(subnets, address);
|
||||
nm_assert(p);
|
||||
if (!ip4_addr_subnets_is_plain_address(addresses, p)) {
|
||||
addr_list = p;
|
||||
|
|
@ -4030,7 +4050,7 @@ nm_platform_ip_address_sync(NMPlatform *self,
|
|||
if (nm_g_ptr_array_len(plat_addresses) > 0) {
|
||||
/* Delete addresses that interfere with our intended order. */
|
||||
if (IS_IPv4) {
|
||||
GHashTable *known_subnets = NULL;
|
||||
GHashTable *known_subnets = NULL;
|
||||
GHashTable *plat_subnets;
|
||||
gs_free bool *plat_handled_to_free = NULL;
|
||||
bool *plat_handled = NULL;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue