summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-03-29 18:20:31 +0200
committerFernando Fernandez Mancera <ffmancera@riseup.net>2022-04-28 12:03:41 +0200
commitea6625ce97629b287f484e0d5caeb0d08ed44843 (patch)
tree5b302d67898c3e79fd2a27f7094df1fa795643a2
parent3a98ecfa0edce51c5ed8446bc3a74efc6ec6ac65 (diff)
platform: add semantic comparison for IP addresses and add "nm_platform_vtable_address"
We already have a comparison of NMPlatformIPXAddress with the modes "full" and "id". The former is needed to fully compare two addresses, the latter as identity for tracking addresses in the cache. In NetworkManager we also use the NMPlatformIP[46]Address structure to track the addresses we want to configure. When we add them in kernel, we will later see them in the platform cache. However, some fields will be slightly different. For example, "addr_source" address will always be "kernel", because that one is not a field we configure in kernel. Also, the "n_ifa_flags" probably differ (getting "permanent" and "secondary" flags). Add a compare function that can ignore such differences. Also add nm_platform_vtable_address for accessing the IPv4 and IPv6 methods generically (based on an "IS_IPv4" variable). (cherry picked from commit ef1b60c061f85b60329d37d62dc81683ff56f4b7)
-rw-r--r--src/libnm-platform/nm-platform.c165
-rw-r--r--src/libnm-platform/nm-platform.h49
-rw-r--r--src/libnm-platform/nmp-object.c82
3 files changed, 224 insertions, 72 deletions
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index 5bd934a24b..d4116f0f11 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -7895,6 +7895,25 @@ _address_pretty_sort_get_prio_6(const struct in6_addr *addr)
return 6;
}
+static int
+_address_cmp_expiry(const NMPlatformIPAddress *a, const NMPlatformIPAddress *b)
+{
+ guint32 lifetime_a;
+ guint32 lifetime_b;
+ guint32 preferred_a;
+ guint32 preferred_b;
+ gint32 now = 0;
+
+ lifetime_a =
+ nmp_utils_lifetime_get(a->timestamp, a->lifetime, a->preferred, &now, &preferred_a);
+ lifetime_b =
+ nmp_utils_lifetime_get(b->timestamp, b->lifetime, b->preferred, &now, &preferred_b);
+
+ NM_CMP_DIRECT(lifetime_a, lifetime_b);
+ NM_CMP_DIRECT(preferred_a, preferred_b);
+ return 0;
+}
+
int
nm_platform_ip6_address_pretty_sort_cmp(const NMPlatformIP6Address *a1,
const NMPlatformIP6Address *a2,
@@ -7974,26 +7993,55 @@ nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState
}
int
-nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a, const NMPlatformIP4Address *b)
+nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a,
+ const NMPlatformIP4Address *b,
+ NMPlatformIPAddressCmpType cmp_type)
{
NM_CMP_SELF(a, b);
+
NM_CMP_FIELD(a, b, ifindex);
- NM_CMP_FIELD(a, b, address);
NM_CMP_FIELD(a, b, plen);
- NM_CMP_FIELD(a, b, peer_address);
- NM_CMP_FIELD_UNSAFE(a, b, use_ip4_broadcast_address);
- if (a->use_ip4_broadcast_address)
- NM_CMP_FIELD(a, b, broadcast_address);
- NM_CMP_FIELD(a, b, addr_source);
- NM_CMP_FIELD(a, b, timestamp);
- NM_CMP_FIELD(a, b, lifetime);
- NM_CMP_FIELD(a, b, preferred);
- NM_CMP_FIELD(a, b, n_ifa_flags);
- NM_CMP_FIELD_STR(a, b, label);
- NM_CMP_FIELD_UNSAFE(a, b, a_acd_not_ready);
- NM_CMP_FIELD_UNSAFE(a, b, a_assume_config_once);
- NM_CMP_FIELD_UNSAFE(a, b, a_force_commit);
- return 0;
+ NM_CMP_FIELD(a, b, address);
+
+ switch (cmp_type) {
+ case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID:
+ /* for IPv4 addresses, you can add the same local address with differing peer-address
+ * (IFA_ADDRESS), provided that their net-part differs. */
+ NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a->peer_address, b->peer_address, a->plen);
+ return 0;
+ case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY:
+ case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL:
+ NM_CMP_FIELD(a, b, peer_address);
+ NM_CMP_FIELD_STR(a, b, label);
+ if (cmp_type == NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY) {
+ NM_CMP_RETURN(_address_cmp_expiry((const NMPlatformIPAddress *) a,
+ (const NMPlatformIPAddress *) b));
+
+ /* Most flags are set by kernel. We only compare the ones that
+ * NetworkManager actively sets.
+ *
+ * NM actively only sets IFA_F_NOPREFIXROUTE (and IFA_F_MANAGETEMPADDR for IPv6),
+ * where nm_platform_ip_address_sync() always sets IFA_F_NOPREFIXROUTE.
+ * There are thus no flags to compare for IPv4. */
+
+ NM_CMP_DIRECT(nm_platform_ip4_broadcast_address_from_addr(a),
+ nm_platform_ip4_broadcast_address_from_addr(b));
+ } else {
+ NM_CMP_FIELD(a, b, timestamp);
+ NM_CMP_FIELD(a, b, lifetime);
+ NM_CMP_FIELD(a, b, preferred);
+ NM_CMP_FIELD(a, b, n_ifa_flags);
+ NM_CMP_FIELD(a, b, addr_source);
+ NM_CMP_FIELD_UNSAFE(a, b, use_ip4_broadcast_address);
+ if (a->use_ip4_broadcast_address)
+ NM_CMP_FIELD(a, b, broadcast_address);
+ NM_CMP_FIELD_UNSAFE(a, b, a_acd_not_ready);
+ NM_CMP_FIELD_UNSAFE(a, b, a_assume_config_once);
+ NM_CMP_FIELD_UNSAFE(a, b, a_force_commit);
+ }
+ return 0;
+ }
+ return nm_assert_unreachable_val(0);
}
void
@@ -8014,25 +8062,51 @@ nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState
}
int
-nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a, const NMPlatformIP6Address *b)
+nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a,
+ const NMPlatformIP6Address *b,
+ NMPlatformIPAddressCmpType cmp_type)
{
const struct in6_addr *p_a, *p_b;
NM_CMP_SELF(a, b);
+
NM_CMP_FIELD(a, b, ifindex);
- NM_CMP_FIELD_MEMCMP(a, b, address);
- NM_CMP_FIELD(a, b, plen);
- p_a = nm_platform_ip6_address_get_peer(a);
- p_b = nm_platform_ip6_address_get_peer(b);
- NM_CMP_DIRECT_MEMCMP(p_a, p_b, sizeof(*p_a));
- NM_CMP_FIELD(a, b, addr_source);
- NM_CMP_FIELD(a, b, timestamp);
- NM_CMP_FIELD(a, b, lifetime);
- NM_CMP_FIELD(a, b, preferred);
- NM_CMP_FIELD(a, b, n_ifa_flags);
- NM_CMP_FIELD_UNSAFE(a, b, a_assume_config_once);
- NM_CMP_FIELD_UNSAFE(a, b, a_force_commit);
- return 0;
+ NM_CMP_FIELD_IN6ADDR(a, b, address);
+
+ switch (cmp_type) {
+ case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID:
+ /* for IPv6 addresses, the prefix length is not part of the primary identifier. */
+ return 0;
+ case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY:
+ case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL:
+ NM_CMP_FIELD(a, b, plen);
+ p_a = nm_platform_ip6_address_get_peer(a);
+ p_b = nm_platform_ip6_address_get_peer(b);
+ NM_CMP_DIRECT_MEMCMP(p_a, p_b, sizeof(*p_a));
+ if (cmp_type == NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY) {
+ NM_CMP_RETURN(_address_cmp_expiry((const NMPlatformIPAddress *) a,
+ (const NMPlatformIPAddress *) b));
+
+ /* Most flags are set by kernel. We only compare the ones that
+ * NetworkManager actively sets.
+ *
+ * NM actively only sets IFA_F_NOPREFIXROUTE and IFA_F_MANAGETEMPADDR,
+ * where nm_platform_ip_address_sync() always sets IFA_F_NOPREFIXROUTE.
+ * We thus only care about IFA_F_MANAGETEMPADDR. */
+ NM_CMP_DIRECT(a->n_ifa_flags & IFA_F_MANAGETEMPADDR,
+ b->n_ifa_flags & IFA_F_MANAGETEMPADDR);
+ } else {
+ NM_CMP_FIELD(a, b, timestamp);
+ NM_CMP_FIELD(a, b, lifetime);
+ NM_CMP_FIELD(a, b, preferred);
+ NM_CMP_FIELD(a, b, n_ifa_flags);
+ NM_CMP_FIELD(a, b, addr_source);
+ NM_CMP_FIELD_UNSAFE(a, b, a_assume_config_once);
+ NM_CMP_FIELD_UNSAFE(a, b, a_force_commit);
+ }
+ return 0;
+ }
+ return nm_assert_unreachable_val(0);
}
void
@@ -8988,6 +9062,37 @@ nm_platform_netns_push(NMPlatform *self, NMPNetns **netns)
/*****************************************************************************/
+const _NMPlatformVTableAddressUnion nm_platform_vtable_address = {
+ .v4 =
+ {
+ .is_ip4 = TRUE,
+ .obj_type = NMP_OBJECT_TYPE_IP4_ADDRESS,
+ .addr_family = AF_INET,
+ .sizeof_address = sizeof(NMPlatformIP4Address),
+ .address_cmp =
+ (int (*)(const NMPlatformIPXAddress *a,
+ const NMPlatformIPXAddress *b,
+ NMPlatformIPAddressCmpType cmp_type)) nm_platform_ip4_address_cmp,
+ .address_to_string = (const char *(*) (const NMPlatformIPXAddress *address,
+ char *buf,
+ gsize len)) nm_platform_ip4_address_to_string,
+ },
+ .v6 =
+ {
+ .is_ip4 = FALSE,
+ .obj_type = NMP_OBJECT_TYPE_IP6_ADDRESS,
+ .addr_family = AF_INET6,
+ .sizeof_address = sizeof(NMPlatformIP6Address),
+ .address_cmp =
+ (int (*)(const NMPlatformIPXAddress *a,
+ const NMPlatformIPXAddress *b,
+ NMPlatformIPAddressCmpType cmp_type)) nm_platform_ip6_address_cmp,
+ .address_to_string = (const char *(*) (const NMPlatformIPXAddress *address,
+ char *buf,
+ gsize len)) nm_platform_ip6_address_to_string,
+ },
+};
+
const _NMPlatformVTableRouteUnion nm_platform_vtable_route = {
.v4 =
{
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index 93b644a3d8..111fbfc208 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -95,6 +95,14 @@ typedef enum {
} NMPNlmFlags;
typedef enum {
+ NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID,
+
+ NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY,
+
+ NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL,
+} NMPlatformIPAddressCmpType;
+
+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
@@ -777,6 +785,27 @@ typedef struct {
typedef struct {
bool is_ip4;
+ NMPObjectType obj_type;
+ gint8 addr_family;
+ guint8 sizeof_address;
+ int (*address_cmp)(const NMPlatformIPXAddress *a,
+ const NMPlatformIPXAddress *b,
+ NMPlatformIPAddressCmpType cmp_type);
+ const char *(*address_to_string)(const NMPlatformIPXAddress *address, char *buf, gsize len);
+} NMPlatformVTableAddress;
+
+typedef union {
+ struct {
+ NMPlatformVTableAddress v6;
+ NMPlatformVTableAddress v4;
+ };
+ NMPlatformVTableAddress vx[2];
+} _NMPlatformVTableAddressUnion;
+
+extern const _NMPlatformVTableAddressUnion nm_platform_vtable_address;
+
+typedef struct {
+ bool is_ip4;
gint8 addr_family;
guint8 sizeof_route;
NMPObjectType obj_type;
@@ -2343,8 +2372,24 @@ int nm_platform_lnk_vlan_cmp(const NMPlatformLnkVlan *a, const NMPlatformLnkVlan
int nm_platform_lnk_vrf_cmp(const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b);
int nm_platform_lnk_vxlan_cmp(const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b);
int nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *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_address_cmp(const NMPlatformIP4Address *a,
+ const NMPlatformIP4Address *b,
+ NMPlatformIPAddressCmpType cmp_type);
+int nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a,
+ const NMPlatformIP6Address *b,
+ NMPlatformIPAddressCmpType cmp_type);
+
+static inline int
+nm_platform_ip4_address_cmp_full(const NMPlatformIP4Address *a, const NMPlatformIP4Address *b)
+{
+ return nm_platform_ip4_address_cmp(a, b, NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL);
+}
+
+static inline int
+nm_platform_ip6_address_cmp_full(const NMPlatformIP6Address *a, const NMPlatformIP6Address *b)
+{
+ return nm_platform_ip6_address_cmp(a, b, NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL);
+}
int nm_platform_ip4_address_pretty_sort_cmp(const NMPlatformIP4Address *a1,
const NMPlatformIP4Address *a2);
diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c
index d518e6e589..0102e943ff 100644
--- a/src/libnm-platform/nmp-object.c
+++ b/src/libnm-platform/nmp-object.c
@@ -1523,20 +1523,21 @@ nmp_object_id_cmp(const NMPObject *obj1, const NMPObject *obj2)
_vt_cmd_plobj_id_cmp(link, NMPlatformLink, { NM_CMP_FIELD(obj1, obj2, ifindex); });
-_vt_cmd_plobj_id_cmp(ip4_address, NMPlatformIP4Address, {
- NM_CMP_FIELD(obj1, obj2, ifindex);
- NM_CMP_FIELD(obj1, obj2, plen);
- NM_CMP_FIELD(obj1, obj2, address);
- /* for IPv4 addresses, you can add the same local address with differing peer-address
- * (IFA_ADDRESS), provided that their net-part differs. */
- NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(obj1->peer_address, obj2->peer_address, obj1->plen);
-});
+static int
+_vt_cmd_plobj_id_cmp_ip4_address(const NMPlatformObject *obj1, const NMPlatformObject *obj2)
+{
+ return nm_platform_ip4_address_cmp((const NMPlatformIP4Address *) obj1,
+ (const NMPlatformIP4Address *) obj2,
+ NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID);
+}
-_vt_cmd_plobj_id_cmp(ip6_address, NMPlatformIP6Address, {
- NM_CMP_FIELD(obj1, obj2, ifindex);
- /* for IPv6 addresses, the prefix length is not part of the primary identifier. */
- NM_CMP_FIELD_IN6ADDR(obj1, obj2, address);
-});
+static int
+_vt_cmd_plobj_id_cmp_ip6_address(const NMPlatformObject *obj1, const NMPlatformObject *obj2)
+{
+ return nm_platform_ip6_address_cmp((const NMPlatformIP6Address *) obj1,
+ (const NMPlatformIP6Address *) obj2,
+ NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID);
+}
_vt_cmd_plobj_id_cmp(qdisc, NMPlatformQdisc, {
NM_CMP_FIELD(obj1, obj2, ifindex);
@@ -1551,24 +1552,24 @@ _vt_cmd_plobj_id_cmp(tfilter, NMPlatformTfilter, {
static int
_vt_cmd_plobj_id_cmp_ip4_route(const NMPlatformObject *obj1, const NMPlatformObject *obj2)
{
- return nm_platform_ip4_route_cmp((NMPlatformIP4Route *) obj1,
- (NMPlatformIP4Route *) obj2,
+ return nm_platform_ip4_route_cmp((const NMPlatformIP4Route *) obj1,
+ (const NMPlatformIP4Route *) obj2,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID);
}
static int
_vt_cmd_plobj_id_cmp_ip6_route(const NMPlatformObject *obj1, const NMPlatformObject *obj2)
{
- return nm_platform_ip6_route_cmp((NMPlatformIP6Route *) obj1,
- (NMPlatformIP6Route *) obj2,
+ return nm_platform_ip6_route_cmp((const NMPlatformIP6Route *) obj1,
+ (const NMPlatformIP6Route *) obj2,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID);
}
static int
_vt_cmd_plobj_id_cmp_routing_rule(const NMPlatformObject *obj1, const NMPlatformObject *obj2)
{
- return nm_platform_routing_rule_cmp((NMPlatformRoutingRule *) obj1,
- (NMPlatformRoutingRule *) obj2,
+ return nm_platform_routing_rule_cmp((const NMPlatformRoutingRule *) obj1,
+ (const NMPlatformRoutingRule *) obj2,
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID);
}
@@ -3158,28 +3159,29 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_address,
.cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_ip4_address_to_string,
.cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_ip4_address_hash_update,
- .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_ip4_address_cmp,
+ .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_ip4_address_cmp_full,
+ },
+ [NMP_OBJECT_TYPE_IP6_ADDRESS - 1] =
+ {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
+ .obj_type = NMP_OBJECT_TYPE_IP6_ADDRESS,
+ .sizeof_data = sizeof(NMPObjectIP6Address),
+ .sizeof_public = sizeof(NMPlatformIP6Address),
+ .obj_type_name = "ip6-address",
+ .addr_family = AF_INET6,
+ .rtm_gettype = RTM_GETADDR,
+ .signal_type_id = NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS,
+ .signal_type = NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED,
+ .supported_cache_ids = _supported_cache_ids_ipx_address,
+ .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address,
+ .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_address,
+ .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip6_address,
+ .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip6_address,
+ .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_address,
+ .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_ip6_address_to_string,
+ .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_ip6_address_hash_update,
+ .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_ip6_address_cmp_full,
},
- [NMP_OBJECT_TYPE_IP6_ADDRESS
- - 1] = {.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
- .obj_type = NMP_OBJECT_TYPE_IP6_ADDRESS,
- .sizeof_data = sizeof(NMPObjectIP6Address),
- .sizeof_public = sizeof(NMPlatformIP6Address),
- .obj_type_name = "ip6-address",
- .addr_family = AF_INET6,
- .rtm_gettype = RTM_GETADDR,
- .signal_type_id = NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS,
- .signal_type = NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED,
- .supported_cache_ids = _supported_cache_ids_ipx_address,
- .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address,
- .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_address,
- .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip6_address,
- .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip6_address,
- .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_address,
- .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_ip6_address_to_string,
- .cmd_plobj_hash_update =
- (CmdPlobjHashUpdateFunc) nm_platform_ip6_address_hash_update,
- .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_ip6_address_cmp},
[NMP_OBJECT_TYPE_IP4_ROUTE - 1] =
{
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),