[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