platform: add compare functions for routes with different compare semantics

Routes are complicated.

`ip route add` and `ip route append` behaves differently with respect to
determine whether an existing route is idential or not.

Extend the cmp() and hash() functions to have a compare type, that
covers the different semantics.
This commit is contained in:
Thomas Haller 2017-07-26 10:50:23 +02:00
parent 54f8c2ac22
commit 372f14a6ef
11 changed files with 310 additions and 178 deletions

View file

@ -111,12 +111,6 @@ extern const NMIPAddr nm_ip_addr_zero;
guint nm_utils_in6_addr_hash (const struct in6_addr *addr);
static inline guint
NM_HASH_COMBINE_IN6_ADDR (guint h, const struct in6_addr *addr)
{
return NM_HASH_COMBINE (h, addr ? nm_utils_in6_addr_hash (addr) : 0);
}
gboolean nm_ethernet_address_is_valid (gconstpointer addr, gssize len);
gconstpointer nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen);
@ -143,6 +137,26 @@ nm_utils_ip6_address_same_prefix (const struct in6_addr *addr_a, const struct in
htonl (nm_utils_ip4_address_clear_host_address (_ab, _plen))); \
} G_STMT_END
static inline guint
NM_HASH_COMBINE_IN6ADDR (guint h, const struct in6_addr *addr)
{
if (!addr)
g_return_val_if_reached (h);
return NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (addr));
}
static inline guint
NM_HASH_COMBINE_IN6ADDR_PREFIX (guint h, const struct in6_addr *addr, guint8 plen)
{
struct in6_addr a;
if (!addr)
g_return_val_if_reached (h);
nm_utils_ip6_address_clear_host_address (&a, addr, plen);
/* we don't hash plen itself. The caller may want to do that.*/
return NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&a));
}
double nm_utils_exp10 (gint16 e);
/**

View file

@ -212,7 +212,7 @@ _vt_routes_has_entry (const VTableIP *vtable, const GPtrArray *routes, const Ent
const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (routes->pdata[i]);
route.rx.rt_source = r->rt_source;
if (nm_platform_ip4_route_cmp (r, &route.r4) == 0)
if (nm_platform_ip4_route_cmp_full (r, &route.r4) == 0)
return TRUE;
}
} else {
@ -220,7 +220,7 @@ _vt_routes_has_entry (const VTableIP *vtable, const GPtrArray *routes, const Ent
const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (routes->pdata[i]);
route.rx.rt_source = r->rt_source;
if (nm_platform_ip6_route_cmp (r, &route.r6) == 0)
if (nm_platform_ip6_route_cmp_full (r, &route.r6) == 0)
return TRUE;
}
}

View file

@ -104,7 +104,7 @@ _idx_obj_id_hash (const NMDedupMultiIdxType *idx_type,
break;
case NMP_OBJECT_TYPE_IP6_ADDRESS:
h = 851146661;
h = NM_HASH_COMBINE_IN6_ADDR (h, &o->ip6_address.address);
h = NM_HASH_COMBINE_IN6ADDR (h, &o->ip6_address.address);
break;
case NMP_OBJECT_TYPE_IP4_ROUTE:
h = 40303327;
@ -113,7 +113,7 @@ _idx_obj_id_hash (const NMDedupMultiIdxType *idx_type,
break;
case NMP_OBJECT_TYPE_IP6_ROUTE:
h = 577629323;
h = NM_HASH_COMBINE_IN6_ADDR (h, &o->ip6_route.network);
h = NM_HASH_COMBINE_IN6ADDR (h, &o->ip6_route.network);
h = NM_HASH_COMBINE (h, o->ip_route.plen);
break;
default:
@ -1512,7 +1512,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
if (!has)
break;
if (nm_platform_ip4_route_cmp (r_src, r_dst) != 0) {
if (nm_platform_ip4_route_cmp_full (r_src, r_dst) != 0) {
are_equal = FALSE;
if ( !nm_ip_config_obj_id_equal_ip4_route (r_src, r_dst)
|| r_src->gateway != r_dst->gateway

View file

@ -1291,7 +1291,7 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
if (!has)
break;
if (nm_platform_ip6_route_cmp (r_src, r_dst) != 0) {
if (nm_platform_ip6_route_cmp_full (r_src, r_dst) != 0) {
are_equal = FALSE;
if ( !nm_ip_config_obj_id_equal_ip6_route (r_src, r_dst)
|| r_src->metric != r_dst->metric

View file

@ -428,7 +428,7 @@ _route_equals_ignoring_ifindex (const VTableIP *vtable, const NMPlatformIPXRoute
r2_backup.rx.metric = (guint32) r2_metric;
r2 = &r2_backup;
}
return vtable->vt->route_cmp (r1, r2, FALSE) == 0;
return vtable->vt->route_cmp (r1, r2, NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) == 0;
}
static NMPlatformIPXRoute *

View file

@ -195,7 +195,7 @@ nmtst_platform_ip6_route_full (const char *network, guint plen, const char *gate
static inline int
_nmtst_platform_ip4_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data)
{
return nm_platform_ip4_route_cmp ((const NMPlatformIP4Route *) a, (const NMPlatformIP4Route *) b);
return nm_platform_ip4_route_cmp_full ((const NMPlatformIP4Route *) a, (const NMPlatformIP4Route *) b);
}
static inline void
@ -215,7 +215,7 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP
}
for (i = 0; i < len; i++) {
if (nm_platform_ip4_route_cmp (&a[i], &b[i]) != 0) {
if (nm_platform_ip4_route_cmp_full (&a[i], &b[i]) != 0) {
char buf[sizeof (_nm_utils_to_string_buffer)];
g_error ("Error comparing IPv4 route[%lu]: %s vs %s", (unsigned long) i,
@ -248,7 +248,7 @@ nmtst_platform_ip4_routes_equal_aptr (const NMPObject *const*a, const NMPlatform
static inline int
_nmtst_platform_ip6_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data)
{
return nm_platform_ip6_route_cmp ((const NMPlatformIP6Route *) a, (const NMPlatformIP6Route *) b);
return nm_platform_ip6_route_cmp_full ((const NMPlatformIP6Route *) a, (const NMPlatformIP6Route *) b);
}
static inline void
@ -268,7 +268,7 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP
}
for (i = 0; i < len; i++) {
if (nm_platform_ip6_route_cmp (&a[i], &b[i]) != 0) {
if (nm_platform_ip6_route_cmp_full (&a[i], &b[i]) != 0) {
char buf[sizeof (_nm_utils_to_string_buffer)];
g_error ("Error comparing IPv6 route[%lu]: %s vs %s", (unsigned long) i,

View file

@ -4442,8 +4442,8 @@ nm_platform_lnk_ip6tnl_hash (const NMPlatformLnkIp6Tnl *obj)
guint h = 1651660009;
h = NM_HASH_COMBINE (h, obj->parent_ifindex);
h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->local));
h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->remote));
h = NM_HASH_COMBINE_IN6ADDR (h, &obj->local);
h = NM_HASH_COMBINE_IN6ADDR (h, &obj->remote);
h = NM_HASH_COMBINE (h, obj->ttl);
h = NM_HASH_COMBINE (h, obj->tclass);
h = NM_HASH_COMBINE (h, obj->encap_limit);
@ -4613,8 +4613,8 @@ nm_platform_lnk_vxlan_hash (const NMPlatformLnkVxlan *obj)
h = NM_HASH_COMBINE (h, obj->id);
h = NM_HASH_COMBINE (h, obj->group);
h = NM_HASH_COMBINE (h, obj->local);
h = NM_HASH_COMBINE_IN6_ADDR (h, &obj->group6);
h = NM_HASH_COMBINE_IN6_ADDR (h, &obj->local6);
h = NM_HASH_COMBINE_IN6ADDR (h, &obj->group6);
h = NM_HASH_COMBINE_IN6ADDR (h, &obj->local6);
h = NM_HASH_COMBINE (h, obj->tos);
h = NM_HASH_COMBINE (h, obj->ttl);
h = NM_HASH_COMBINE (h, obj->learning);
@ -4699,9 +4699,9 @@ nm_platform_ip6_address_hash (const NMPlatformIP6Address *obj)
if (obj) {
h = NM_HASH_COMBINE (h, obj->ifindex);
h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->address));
h = NM_HASH_COMBINE_IN6ADDR (h, &obj->address);
h = NM_HASH_COMBINE (h, obj->plen);
h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->peer_address));
h = NM_HASH_COMBINE_IN6ADDR (h, &obj->peer_address);
h = NM_HASH_COMBINE (h, obj->addr_source);
h = NM_HASH_COMBINE (h, obj->timestamp);
h = NM_HASH_COMBINE (h, obj->lifetime);
@ -4732,135 +4732,210 @@ nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6A
}
guint
nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj)
nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpType cmp_type)
{
guint h = 1228913327;
guint h = NM_HASH_COMBINE (1228913327, cmp_type);
if (obj) {
h = NM_HASH_COMBINE (h, obj->ifindex);
h = NM_HASH_COMBINE (h, obj->network);
h = NM_HASH_COMBINE (h, obj->plen);
h = NM_HASH_COMBINE (h, obj->metric);
h = NM_HASH_COMBINE (h, obj->gateway);
h = NM_HASH_COMBINE (h, obj->rt_source);
h = NM_HASH_COMBINE (h, obj->mss);
h = NM_HASH_COMBINE (h, obj->scope_inv);
h = NM_HASH_COMBINE (h, obj->pref_src);
h = NM_HASH_COMBINE (h, obj->rt_cloned);
h = NM_HASH_COMBINE (h, obj->tos);
h = NM_HASH_COMBINE (h, obj->lock_window);
h = NM_HASH_COMBINE (h, obj->lock_cwnd);
h = NM_HASH_COMBINE (h, obj->lock_initcwnd);
h = NM_HASH_COMBINE (h, obj->lock_initrwnd);
h = NM_HASH_COMBINE (h, obj->lock_mtu);
h = NM_HASH_COMBINE (h, obj->window);
h = NM_HASH_COMBINE (h, obj->cwnd);
h = NM_HASH_COMBINE (h, obj->initcwnd);
h = NM_HASH_COMBINE (h, obj->initrwnd);
h = NM_HASH_COMBINE (h, obj->mtu);
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE:
h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
h = NM_HASH_COMBINE (h, obj->plen);
h = NM_HASH_COMBINE (h, obj->metric);
h = NM_HASH_COMBINE (h, obj->ifindex);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
h = NM_HASH_COMBINE (h, obj->plen);
h = NM_HASH_COMBINE (h, obj->metric);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)
h = NM_HASH_COMBINE (h, obj->ifindex);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
h = NM_HASH_COMBINE (h, obj->ifindex);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
else
h = NM_HASH_COMBINE (h, obj->network);
h = NM_HASH_COMBINE (h, obj->plen);
h = NM_HASH_COMBINE (h, obj->metric);
h = NM_HASH_COMBINE (h, obj->gateway);
h = NM_HASH_COMBINE (h, obj->rt_source);
h = NM_HASH_COMBINE (h, obj->mss);
h = NM_HASH_COMBINE (h, obj->scope_inv);
h = NM_HASH_COMBINE (h, obj->pref_src);
h = NM_HASH_COMBINE (h, obj->rt_cloned);
h = NM_HASH_COMBINE (h, obj->tos);
h = NM_HASH_COMBINE (h, obj->lock_window);
h = NM_HASH_COMBINE (h, obj->lock_cwnd);
h = NM_HASH_COMBINE (h, obj->lock_initcwnd);
h = NM_HASH_COMBINE (h, obj->lock_initrwnd);
h = NM_HASH_COMBINE (h, obj->lock_mtu);
h = NM_HASH_COMBINE (h, obj->window);
h = NM_HASH_COMBINE (h, obj->cwnd);
h = NM_HASH_COMBINE (h, obj->initcwnd);
h = NM_HASH_COMBINE (h, obj->initrwnd);
h = NM_HASH_COMBINE (h, obj->mtu);
break;
}
}
return h;
}
int
nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gboolean consider_host_part)
nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, NMPlatformIPRouteCmpType cmp_type)
{
NM_CMP_SELF (a, b);
NM_CMP_FIELD (a, b, ifindex);
if (consider_host_part)
NM_CMP_FIELD (a, b, network);
else {
NM_CMP_DIRECT (nm_utils_ip4_address_clear_host_address (a->network, a->plen),
nm_utils_ip4_address_clear_host_address (b->network, b->plen));
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE:
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX (a->network, b->network, MIN (a->plen, b->plen));
NM_CMP_FIELD (a, b, plen);
NM_CMP_FIELD (a, b, metric);
NM_CMP_FIELD (a, b, ifindex);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX (a->network, b->network, MIN (a->plen, b->plen));
NM_CMP_FIELD (a, b, plen);
NM_CMP_FIELD (a, b, metric);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)
NM_CMP_FIELD (a, b, ifindex);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
NM_CMP_FIELD (a, b, ifindex);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX (a->network, b->network, MIN (a->plen, b->plen));
else
NM_CMP_FIELD (a, b, network);
NM_CMP_FIELD (a, b, plen);
NM_CMP_FIELD (a, b, metric);
NM_CMP_FIELD (a, b, gateway);
NM_CMP_FIELD (a, b, rt_source);
NM_CMP_FIELD (a, b, mss);
NM_CMP_FIELD (a, b, scope_inv);
NM_CMP_FIELD (a, b, pref_src);
NM_CMP_FIELD_UNSAFE (a, b, rt_cloned);
NM_CMP_FIELD (a, b, tos);
NM_CMP_FIELD_UNSAFE (a, b, lock_window);
NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_initcwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_initrwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_mtu);
NM_CMP_FIELD (a, b, window);
NM_CMP_FIELD (a, b, cwnd);
NM_CMP_FIELD (a, b, initcwnd);
NM_CMP_FIELD (a, b, initrwnd);
NM_CMP_FIELD (a, b, mtu);
break;
}
NM_CMP_FIELD (a, b, plen);
NM_CMP_FIELD (a, b, metric);
NM_CMP_FIELD (a, b, gateway);
NM_CMP_FIELD (a, b, rt_source);
NM_CMP_FIELD (a, b, mss);
NM_CMP_FIELD (a, b, scope_inv);
NM_CMP_FIELD (a, b, pref_src);
NM_CMP_FIELD_UNSAFE (a, b, rt_cloned);
NM_CMP_FIELD (a, b, tos);
NM_CMP_FIELD_UNSAFE (a, b, lock_window);
NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_initcwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_initrwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_mtu);
NM_CMP_FIELD (a, b, window);
NM_CMP_FIELD (a, b, cwnd);
NM_CMP_FIELD (a, b, initcwnd);
NM_CMP_FIELD (a, b, initrwnd);
NM_CMP_FIELD (a, b, mtu);
return 0;
}
guint
nm_platform_ip6_route_hash (const NMPlatformIP6Route *obj)
nm_platform_ip6_route_hash (const NMPlatformIP6Route *obj, NMPlatformIPRouteCmpType cmp_type)
{
guint h = 1053326051;
guint h = NM_HASH_COMBINE (1053326051, cmp_type);
if (obj) {
h = NM_HASH_COMBINE (h, obj->ifindex);
h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->network));
h = NM_HASH_COMBINE (h, obj->plen);
h = NM_HASH_COMBINE (h, obj->metric);
h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->gateway));
h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->pref_src));
h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->src));
h = NM_HASH_COMBINE (h, obj->src_plen);
h = NM_HASH_COMBINE (h, obj->rt_source);
h = NM_HASH_COMBINE (h, obj->mss);
h = NM_HASH_COMBINE (h, obj->rt_cloned);
h = NM_HASH_COMBINE (h, obj->tos);
h = NM_HASH_COMBINE (h, obj->lock_window);
h = NM_HASH_COMBINE (h, obj->lock_cwnd);
h = NM_HASH_COMBINE (h, obj->lock_initcwnd);
h = NM_HASH_COMBINE (h, obj->lock_initrwnd);
h = NM_HASH_COMBINE (h, obj->lock_mtu);
h = NM_HASH_COMBINE (h, obj->window);
h = NM_HASH_COMBINE (h, obj->cwnd);
h = NM_HASH_COMBINE (h, obj->initcwnd);
h = NM_HASH_COMBINE (h, obj->initrwnd);
h = NM_HASH_COMBINE (h, obj->mtu);
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE:
h = NM_HASH_COMBINE_IN6ADDR_PREFIX (h, &obj->network, obj->plen);
h = NM_HASH_COMBINE (h, obj->plen);
h = NM_HASH_COMBINE (h, obj->metric);
h = NM_HASH_COMBINE (h, obj->ifindex);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
h = NM_HASH_COMBINE_IN6ADDR_PREFIX (h, &obj->network, obj->plen);
h = NM_HASH_COMBINE (h, obj->plen);
h = NM_HASH_COMBINE (h, obj->metric);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)
h = NM_HASH_COMBINE (h, obj->ifindex);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
h = NM_HASH_COMBINE (h, obj->ifindex);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
h = NM_HASH_COMBINE_IN6ADDR_PREFIX (h, &obj->network, obj->plen);
else
h = NM_HASH_COMBINE_IN6ADDR (h, &obj->network);
h = NM_HASH_COMBINE (h, obj->plen);
h = NM_HASH_COMBINE (h, obj->metric);
h = NM_HASH_COMBINE_IN6ADDR (h, &obj->gateway);
h = NM_HASH_COMBINE_IN6ADDR (h, &obj->pref_src);
h = NM_HASH_COMBINE_IN6ADDR (h, &obj->src);
h = NM_HASH_COMBINE (h, obj->src_plen);
h = NM_HASH_COMBINE (h, obj->rt_source);
h = NM_HASH_COMBINE (h, obj->mss);
h = NM_HASH_COMBINE (h, obj->rt_cloned);
h = NM_HASH_COMBINE (h, obj->tos);
h = NM_HASH_COMBINE (h, obj->lock_window);
h = NM_HASH_COMBINE (h, obj->lock_cwnd);
h = NM_HASH_COMBINE (h, obj->lock_initcwnd);
h = NM_HASH_COMBINE (h, obj->lock_initrwnd);
h = NM_HASH_COMBINE (h, obj->lock_mtu);
h = NM_HASH_COMBINE (h, obj->window);
h = NM_HASH_COMBINE (h, obj->cwnd);
h = NM_HASH_COMBINE (h, obj->initcwnd);
h = NM_HASH_COMBINE (h, obj->initrwnd);
h = NM_HASH_COMBINE (h, obj->mtu);
break;
}
}
return h;
}
int
nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_host_part)
nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, NMPlatformIPRouteCmpType cmp_type)
{
NM_CMP_SELF (a, b);
NM_CMP_FIELD (a, b, ifindex);
if (consider_host_part)
NM_CMP_FIELD_IN6ADDR (a, b, network);
else {
struct in6_addr n1, n2;
nm_utils_ip6_address_clear_host_address (&n1, &a->network, a->plen);
nm_utils_ip6_address_clear_host_address (&n2, &b->network, b->plen);
NM_CMP_DIRECT_IN6ADDR (&n1, &n2);
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE:
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen));
NM_CMP_FIELD (a, b, plen);
NM_CMP_FIELD (a, b, metric);
NM_CMP_FIELD (a, b, ifindex);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen));
NM_CMP_FIELD (a, b, plen);
NM_CMP_FIELD (a, b, metric);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)
NM_CMP_FIELD (a, b, ifindex);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
NM_CMP_FIELD (a, b, ifindex);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen));
else
NM_CMP_FIELD_IN6ADDR (a, b, network);
NM_CMP_FIELD (a, b, plen);
NM_CMP_FIELD (a, b, metric);
NM_CMP_FIELD_IN6ADDR (a, b, gateway);
NM_CMP_FIELD_IN6ADDR (a, b, pref_src);
NM_CMP_FIELD_IN6ADDR (a, b, src);
NM_CMP_FIELD (a, b, src_plen);
NM_CMP_FIELD (a, b, rt_source);
NM_CMP_FIELD (a, b, mss);
NM_CMP_FIELD_UNSAFE (a, b, rt_cloned);
NM_CMP_FIELD (a, b, tos);
NM_CMP_FIELD_UNSAFE (a, b, lock_window);
NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_initcwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_initrwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_mtu);
NM_CMP_FIELD (a, b, window);
NM_CMP_FIELD (a, b, cwnd);
NM_CMP_FIELD (a, b, initcwnd);
NM_CMP_FIELD (a, b, initrwnd);
NM_CMP_FIELD (a, b, mtu);
break;
}
NM_CMP_FIELD (a, b, plen);
NM_CMP_FIELD (a, b, metric);
NM_CMP_FIELD_IN6ADDR (a, b, gateway);
NM_CMP_FIELD_IN6ADDR (a, b, pref_src);
NM_CMP_FIELD_IN6ADDR (a, b, src);
NM_CMP_FIELD (a, b, src_plen);
NM_CMP_FIELD (a, b, rt_source);
NM_CMP_FIELD (a, b, mss);
NM_CMP_FIELD_UNSAFE (a, b, rt_cloned);
NM_CMP_FIELD (a, b, tos);
NM_CMP_FIELD_UNSAFE (a, b, lock_window);
NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_initcwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_initrwnd);
NM_CMP_FIELD_UNSAFE (a, b, lock_mtu);
NM_CMP_FIELD (a, b, window);
NM_CMP_FIELD (a, b, cwnd);
NM_CMP_FIELD (a, b, initcwnd);
NM_CMP_FIELD (a, b, initrwnd);
NM_CMP_FIELD (a, b, mtu);
return 0;
}
@ -5101,7 +5176,7 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
.obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
.addr_family = AF_INET,
.sizeof_route = sizeof (NMPlatformIP4Route),
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip4_route_cmp_full,
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip4_route_cmp,
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string,
.route_add = _vtr_v4_route_add,
.metric_normalize = _vtr_v4_metric_normalize,
@ -5112,7 +5187,7 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v6 = {
.obj_type = NMP_OBJECT_TYPE_IP6_ROUTE,
.addr_family = AF_INET6,
.sizeof_route = sizeof (NMPlatformIP6Route),
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip6_route_cmp_full,
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip6_route_cmp,
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string,
.route_add = _vtr_v6_route_add,
.metric_normalize = nm_utils_ip6_route_metric_normalize,

View file

@ -73,6 +73,48 @@ struct udev_device;
/* Redefine this in host's endianness */
#define NM_GRE_KEY 0x2000
typedef enum {
/* compare fields which kernel considers as similar routes.
* It is a looser comparisong then NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID
* and means that `ip route add` would fail to add two routes
* that have the same NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID.
* On the other hand, `ip route append` would allow that, as
* long as NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID differs. */
NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID,
/* compare two routes as kernel would allow to add them with
* `ip route append`. In other words, kernel does not allow you to
* add two routes (at the same time) which compare equal according
* to NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID.
*
* For the ID we can only recognize route fields that we actually implement.
* However, kernel supports more routing options, some of them also part of
* the ID. NetworkManager is oblivious to these options and will wrongly think
* that two routes are idential, while they are not. That can lead to an
* inconsistent platform cache. Not much what we can do about that, except
* implementing all options that kernel supports *sigh*. See rh#1337860.
*/
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID,
/* FIXME: this type is what NMPCache currently uses for object identity.
* Eventually, we want to use NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID,
* which is the same what kernel does. */
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE,
/* compare all fields as they make sense for kernel. For example,
* a route destination 192.168.1.5/24 is not accepted by kernel and
* we treat it identical to 192.168.1.0/24. Semantically these
* routes are identical, but NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL will
* report them as different. */
NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY,
/* compare all fields. This should have the same effect as memcmp(),
* except allowing for undefined data in holes between field alignment.
*/
NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL,
} NMPlatformIPRouteCmpType;
typedef enum { /*< skip >*/
/* dummy value, to enforce that the enum type is signed and has a size
@ -364,7 +406,7 @@ typedef struct {
NMPObjectType obj_type;
int addr_family;
gsize sizeof_route;
int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part);
int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type);
const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len);
gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric);
guint32 (*metric_normalize) (guint32 metric);
@ -991,26 +1033,27 @@ int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVla
int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b);
int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b);
int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b);
int nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gboolean consider_host_part);
int nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_host_part);
int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, NMPlatformIPRouteCmpType cmp_type);
int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, NMPlatformIPRouteCmpType cmp_type);
static inline int
nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b)
nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b)
{
return nm_platform_ip4_route_cmp_full (a, b, TRUE);
return nm_platform_ip4_route_cmp (a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
}
static inline int
nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b)
nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b)
{
return nm_platform_ip6_route_cmp_full (a, b, TRUE);
return nm_platform_ip6_route_cmp (a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
}
guint nm_platform_link_hash (const NMPlatformLink *obj);
guint nm_platform_ip4_address_hash (const NMPlatformIP4Address *obj);
guint nm_platform_ip6_address_hash (const NMPlatformIP6Address *obj);
guint nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj);
guint nm_platform_ip6_route_hash (const NMPlatformIP6Route *obj);
guint nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpType cmp_type);
guint nm_platform_ip6_route_hash (const NMPlatformIP6Route *obj, NMPlatformIPRouteCmpType cmp_type);
guint nm_platform_lnk_gre_hash (const NMPlatformLnkGre *obj);
guint nm_platform_lnk_infiniband_hash (const NMPlatformLnkInfiniband *obj);
guint nm_platform_lnk_ip6tnl_hash (const NMPlatformLnkIp6Tnl *obj);
@ -1021,6 +1064,18 @@ guint nm_platform_lnk_sit_hash (const NMPlatformLnkSit *obj);
guint nm_platform_lnk_vlan_hash (const NMPlatformLnkVlan *obj);
guint nm_platform_lnk_vxlan_hash (const NMPlatformLnkVxlan *obj);
static inline guint
nm_platform_ip4_route_hash_full (const NMPlatformIP4Route *obj)
{
return nm_platform_ip4_route_hash (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
}
static inline guint
nm_platform_ip6_route_hash_full (const NMPlatformIP6Route *obj)
{
return nm_platform_ip6_route_hash (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
}
gboolean nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self);
gboolean nm_platform_check_support_user_ipv6ll (NMPlatform *self);

View file

@ -225,21 +225,16 @@ _idx_obj_part (const DedupMultiIdxType *idx_type,
if (obj_b) {
return obj_type == NMP_OBJECT_GET_TYPE (obj_b)
&& obj_b->object.ifindex > 0
&& obj_a->ip_route.plen == obj_b->ip_route.plen
&& obj_a->ip_route.metric == obj_b->ip_route.metric
&& (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE
? obj_a->ip4_route.network == obj_b->ip4_route.network
: IN6_ARE_ADDR_EQUAL (&obj_a->ip6_route.network, &obj_b->ip6_route.network));
? (nm_platform_ip4_route_cmp (&obj_a->ip4_route, &obj_b->ip4_route, NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID) == 0)
: (nm_platform_ip6_route_cmp (&obj_a->ip6_route, &obj_b->ip6_route, NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID) == 0));
}
if (request_hash) {
h = (guint) idx_type->cache_id_type;
h = NM_HASH_COMBINE (h, obj_a->ip_route.plen);
h = NM_HASH_COMBINE (h, obj_a->ip_route.metric);
h = NM_HASH_COMBINE (h, obj_type);
if (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE)
h = NM_HASH_COMBINE (h, obj_a->ip4_route.network);
h = NM_HASH_COMBINE (h, nm_platform_ip4_route_hash (&obj_a->ip4_route, NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID));
else
h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj_a->ip6_route.network));
h = NM_HASH_COMBINE (h, nm_platform_ip6_route_hash (&obj_a->ip6_route, NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID));
return _HASH_NON_ZERO (h);
}
return 1;
@ -1024,12 +1019,14 @@ _vt_cmd_plobj_id_copy (ip4_route, NMPlatformIP4Route, {
dst->plen = src->plen;
dst->metric = src->metric;
dst->network = src->network;
nm_assert (nm_platform_ip4_route_cmp (dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE) == 0);
});
_vt_cmd_plobj_id_copy (ip6_route, NMPlatformIP6Route, {
dst->ifindex = src->ifindex;
dst->plen = src->plen;
dst->metric = src->metric;
dst->network = src->network;
nm_assert (nm_platform_ip6_route_cmp (dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE) == 0);
});
/* Uses internally nmp_object_copy(), hence it also violates the const
@ -1091,20 +1088,9 @@ _vt_cmd_plobj_id_equal (ip6_address, NMPlatformIP6Address,
/* for IPv6 addresses, the prefix length is not part of the primary identifier. */
&& IN6_ARE_ADDR_EQUAL (&obj1->address, &obj2->address));
_vt_cmd_plobj_id_equal (ip4_route, NMPlatformIP4Route,
obj1->ifindex == obj2->ifindex
&& obj1->plen == obj2->plen
&& obj1->metric == obj2->metric
&& nm_utils_ip4_address_clear_host_address (obj1->network, obj1->plen) == nm_utils_ip4_address_clear_host_address (obj2->network, obj2->plen));
nm_platform_ip4_route_cmp (obj1, obj2, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE) == 0);
_vt_cmd_plobj_id_equal (ip6_route, NMPlatformIP6Route,
obj1->ifindex == obj2->ifindex
&& obj1->plen == obj2->plen
&& obj1->metric == obj2->metric
&& ({
struct in6_addr n1, n2;
IN6_ARE_ADDR_EQUAL(nm_utils_ip6_address_clear_host_address (&n1, &obj1->network, obj1->plen),
nm_utils_ip6_address_clear_host_address (&n2, &obj2->network, obj2->plen));
}));
nm_platform_ip6_route_cmp (obj1, obj2, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE) == 0);
guint
nmp_object_id_hash (const NMPObject *obj)
@ -1153,22 +1139,10 @@ _vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, {
hash = NM_HASH_COMBINE (hash, nm_utils_in6_addr_hash (&obj->address));
})
_vt_cmd_plobj_id_hash (ip4_route, NMPlatformIP4Route, {
hash = (guint) 2569857221u;
hash = hash + ((guint) obj->ifindex);
hash = NM_HASH_COMBINE (hash, obj->plen);
hash = NM_HASH_COMBINE (hash, obj->metric);
hash = NM_HASH_COMBINE (hash, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
hash = nm_platform_ip4_route_hash (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE);
})
_vt_cmd_plobj_id_hash (ip6_route, NMPlatformIP6Route, {
hash = (guint) 3999787007u;
hash = hash + ((guint) obj->ifindex);
hash = NM_HASH_COMBINE (hash, obj->plen);
hash = NM_HASH_COMBINE (hash, obj->metric);
hash = NM_HASH_COMBINE (hash,
({
struct in6_addr n1;
nm_utils_in6_addr_hash (nm_utils_ip6_address_clear_host_address (&n1, &obj->network, obj->plen));
}));
hash = nm_platform_ip6_route_hash (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE);
})
gboolean
@ -2428,8 +2402,8 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_route,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_route,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_route_to_string,
.cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip4_route_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_route_cmp,
.cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip4_route_hash_full,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_route_cmp_full,
},
[NMP_OBJECT_TYPE_IP6_ROUTE - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
@ -2449,8 +2423,8 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_route,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_route,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_route_to_string,
.cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip6_route_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp,
.cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip6_route_hash_full,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp_full,
},
[NMP_OBJECT_TYPE_LNK_GRE - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),

View file

@ -69,6 +69,8 @@ ip4_route_callback (NMPlatform *platform, int obj_type_i, int ifindex, const NMP
{
const NMPObjectType obj_type = obj_type_i;
const NMPlatformSignalChangeType change_type = change_type_i;
NMPObject o_id;
nm_auto_nmpobj NMPObject *o_id_p = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, NULL);
g_assert_cmpint (obj_type, ==, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert (received);
@ -76,6 +78,11 @@ ip4_route_callback (NMPlatform *platform, int obj_type_i, int ifindex, const NMP
g_assert (data && data->name);
g_assert_cmpstr (data->name, ==, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED);
/* run code for initializing the ID only */
nmp_object_stackinit_id (&o_id, NMP_OBJECT_UP_CAST (received));
nmp_object_copy (o_id_p, NMP_OBJECT_UP_CAST (received), TRUE);
nmp_object_copy (o_id_p, NMP_OBJECT_UP_CAST (received), FALSE);
if (data->ifindex && data->ifindex != received->ifindex)
return;
if (data->change_type != change_type)
@ -93,6 +100,8 @@ ip6_route_callback (NMPlatform *platform, int obj_type_i, int ifindex, const NMP
{
const NMPObjectType obj_type = obj_type_i;
const NMPlatformSignalChangeType change_type = change_type_i;
NMPObject o_id;
nm_auto_nmpobj NMPObject *o_id_p = nmp_object_new (NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
g_assert_cmpint (obj_type, ==, NMP_OBJECT_TYPE_IP6_ROUTE);
g_assert (received);
@ -100,6 +109,11 @@ ip6_route_callback (NMPlatform *platform, int obj_type_i, int ifindex, const NMP
g_assert (data && data->name);
g_assert_cmpstr (data->name, ==, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED);
/* run code for initializing the ID only */
nmp_object_stackinit_id (&o_id, NMP_OBJECT_UP_CAST (received));
nmp_object_copy (o_id_p, NMP_OBJECT_UP_CAST (received), TRUE);
nmp_object_copy (o_id_p, NMP_OBJECT_UP_CAST (received), FALSE);
if (data->ifindex && data->ifindex != received->ifindex)
return;
if (data->change_type != change_type)

View file

@ -822,7 +822,7 @@ _assert_route_check (const NMPlatformVTableRoute *vtable, gboolean has, const NM
c.r6 = route->r6;
c.rx.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (c.rx.rt_source);
}
if (!r || vtable->route_cmp (r, &c, TRUE) != 0) {
if (!r || vtable->route_cmp (r, &c, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) != 0) {
g_error ("Invalid route. Expect %s, has %s",
vtable->route_to_string (&c, NULL, 0),
vtable->route_to_string (r, buf, sizeof (buf)));