[PATCH 1/2] route/addr: fix ID comparison for AF_INET and AF_INET6 addresses

Thomas Haller thaller at redhat.com
Tue Jun 28 07:56:21 PDT 2016


For AF_INET/IPv4 addresses, the ID equality comparison must include
the net-part of the peer address:

    unshare -n
    ip link add T type dummy
    ip link set T up
    ip addr add 192.168.5.10/24 dev T
    ip addr add 192.168.5.10 peer 192.168.6.1/24 dev T
    ip addr add 192.168.5.10 peer 192.168.7.1/24 dev T
    ip addr add 192.168.5.10 peer 192.168.7.2/24 dev T
    # RTNETLINK answers: File exists

    ip addr change 192.168.5.10 peer 192.168.7.2/24 dev T
    ip addr show | grep 192.168.7.
    # inet 192.168.5.10 peer 192.168.7.1/24 scope global T

For AF_INET6/IPv6 addresses, the prefix length of the address
is not part of the ID:

    unshare -n
    ip link add T type dummy
    ip link set T up
    ip addr add 192.168.7.10/24 dev T
    ip addr add 192.168.7.10/23 dev T
    ip addr add 1:2:3:4:5::1/64 dev T
    ip addr add 1:2:3:4:5::1/63 dev T
    # RTNETLINK answers: File exists

    ip addr change 1:2:3:4:5::1/63 dev T
    ip addr show | grep 1:2:3:4:5::1
    # inet6 1:2:3:4:5::1/64 scope global

Signed-off-by: Thomas Haller <thaller at redhat.com>
---
 include/netlink-private/types.h |  1 +
 lib/object.c                    |  2 +-
 lib/route/addr.c                | 34 +++++++++++++++++++++++++++++++++-
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h
index 5da8f59..0f67ddd 100644
--- a/include/netlink-private/types.h
+++ b/include/netlink-private/types.h
@@ -111,6 +111,7 @@ struct nl_cache_mngr
 struct nl_parser_param;
 
 #define LOOSE_COMPARISON	1
+#define ID_COMPARISON           2
 
 #define NL_OBJ_MARK		1
 
diff --git a/lib/object.c b/lib/object.c
index a88ac00..06c2a95 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -343,7 +343,7 @@ int nl_object_identical(struct nl_object *a, struct nl_object *b)
 	if (ops->oo_compare == NULL)
 		return 0;
 
-	return !(ops->oo_compare(a, b, req_attrs, 0));
+	return !(ops->oo_compare(a, b, req_attrs, ID_COMPARISON));
 }
 
 /**
diff --git a/lib/route/addr.c b/lib/route/addr.c
index 33df1c8..8dad736 100644
--- a/lib/route/addr.c
+++ b/lib/route/addr.c
@@ -429,6 +429,24 @@ static void addr_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
 	addr_dump_details(obj, p);
 }
 
+static uint32_t addr_id_attrs_get(struct nl_object *obj)
+{
+	struct rtnl_addr *addr = (struct rtnl_addr *)obj;
+
+	switch (addr->a_family) {
+	case AF_INET:
+		return (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
+		        ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN |
+		        ADDR_ATTR_PEER);
+	case AF_INET6:
+		return (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
+		        ADDR_ATTR_LOCAL);
+	default:
+		return (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
+		        ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN);
+	}
+}
+
 static uint64_t addr_compare(struct nl_object *_a, struct nl_object *_b,
 			     uint64_t attrs, int flags)
 {
@@ -442,7 +460,20 @@ static uint64_t addr_compare(struct nl_object *_a, struct nl_object *_b,
 	diff |= ADDR_DIFF(FAMILY,	a->a_family != b->a_family);
 	diff |= ADDR_DIFF(SCOPE,	a->a_scope != b->a_scope);
 	diff |= ADDR_DIFF(LABEL,	strcmp(a->a_label, b->a_label));
-	diff |= ADDR_DIFF(PEER,		nl_addr_cmp(a->a_peer, b->a_peer));
+	if (attrs & ADDR_ATTR_PEER) {
+		if (   (flags & ID_COMPARISON)
+		    && a->a_family == AF_INET
+		    && b->a_family == AF_INET
+		    && a->a_peer
+		    && b->a_peer
+		    && a->a_prefixlen == b->a_prefixlen) {
+			/* when comparing two IPv4 addresses for id-equality, the network part
+			 * of the PEER address shall be compared.
+			 */
+			diff |= ADDR_DIFF(PEER, nl_addr_cmp_prefix(a->a_peer, b->a_peer));
+		} else
+			diff |= ADDR_DIFF(PEER, nl_addr_cmp(a->a_peer, b->a_peer));
+	}
 	diff |= ADDR_DIFF(LOCAL,	nl_addr_cmp(a->a_local, b->a_local));
 	diff |= ADDR_DIFF(MULTICAST,	nl_addr_cmp(a->a_multicast,
 						    b->a_multicast));
@@ -1100,6 +1131,7 @@ static struct nl_object_ops addr_obj_ops = {
 	},
 	.oo_compare		= addr_compare,
 	.oo_attrs2str		= addr_attrs2str,
+	.oo_id_attrs_get	= addr_id_attrs_get,
 	.oo_id_attrs		= (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
 				   ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN),
 };
-- 
2.7.4




More information about the libnl mailing list