Skip to contentSkip to conversation

Updates for strict checking and kernel side filtering

PATCH In review David Ahern 3 participants 15 messages Dec 20, 2018 – Dec 30, 2018

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover Updates for strict checking and kernel side filtering

From: David Ahern <[email protected]>

Refactorings and updates to use the new strict checking in the kernel along with the new kernel side filtering.

David Ahern (12):
libnetlink: dump extack string in done message
libnetlink: Use NLMSG_LENGTH to set nlmsg_len
libnetlink: linkdump_req: Only AF_UNSPEC family expects an
ext_filter_mask
ip route: Remove rtnl_rtcache_request
ip route: Add protocol, table id and device to dump request
mroute: fix up family handling
mroute: Add table id attribute for kernel side filtering ip address: Split ip_linkaddr_list into link and addr functions ip address: Set device index in dump request
ip bridge: Set NETLINK_DUMP_STRICT_CHK on socket
ip route: Rename do_ipv6 to dump_family
neighbor: Add support for protocol attribute

 bridge/bridge.c      |   4 ++
 include/libnetlink.h |  11 +--
 ip/ip.c              |   2 +
 ip/ip_common.h       |   3 +-
 ip/ipaddress.c       |  92 ++++++++++++++++++------
 ip/ipmroute.c        |  31 ++++++---
 ip/ipneigh.c         |  39 ++++++++++-
 ip/iproute.c         |  89 ++++++++++++------------
 ip/ipvrf.c           |   2 +-
 lib/libnetlink.c     | 192 ++++++++++++++++++++++++++++++++++++++-------------
 10 files changed, 330 insertions(+), 135 deletions(-)
Signature · 1 line
2.11.0
#1 lore raw

PATCH 1/12 libnetlink: dump extack string in done message

From: David Ahern <[email protected]>

Print any extack message that has been appended to a NLMSG_DONE message. To avoid duplication, move the existing print code to a new helper.

---
 lib/libnetlink.c | 44 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 39 insertions(+), 5 deletions(-)
lib/libnetlink.c +39 -5
index 954571097ea8..e28e1ab6da5e 100644
@@ -67,6 +67,14 @@ static int err_attr_cb(const struct nlattr *attr, void *data)
 	return MNL_CB_OK;
 }
 
+static void print_ext_ack_msg(bool is_err, const char *msg)
+{
+	fprintf(stderr, "%s: %s", is_err ? "Error" : "Warning", msg);
+	if (msg[strlen(msg) - 1] != '.')
+		fprintf(stderr, ".");
+	fprintf(stderr, "\n");
+}
+
 /* dump netlink extended ack error message */
 int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
 {
@@ -108,12 +116,29 @@ int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
 	if (msg && *msg != '\0') {
 		bool is_err = !!err->error;
 
-		fprintf(stderr, "%s: %s",
-			is_err ? "Error" : "Warning", msg);
-		if (msg[strlen(msg) - 1] != '.')
-			fprintf(stderr, ".");
-		fprintf(stderr, "\n");
+		print_ext_ack_msg(is_err, msg);
+		return is_err ? 1 : 0;
+	}
 
+	return 0;
+}
+
+static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
+{
+	struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
+	unsigned int hlen = sizeof(int);
+	const char *msg = NULL;
+
+	if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
+		return 0;
+
+	if (tb[NLMSGERR_ATTR_MSG])
+		msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
+
+	if (msg && *msg != '\0') {
+		bool is_err = !!error;
+
+		print_ext_ack_msg(is_err, msg);
 		return is_err ? 1 : 0;
 	}
 
@@ -127,6 +152,11 @@ int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
 {
 	return 0;
 }
+
+static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
+{
+	return 0;
+}
 #endif
 
 void rtnl_close(struct rtnl_handle *rth)
@@ -512,6 +542,10 @@ static int rtnl_dump_done(struct nlmsghdr *h)
 	}
 
 	if (len < 0) {
+		/* check for any messages returned from kernel */
+		if (nl_dump_ext_ack_done(h, len))
+			return len;
+
 		errno = -len;
 		switch (errno) {
 		case ENOENT:
Signature · 1 line
2.11.0
#2 lore raw

PATCH 2/12 libnetlink: Use NLMSG_LENGTH to set nlmsg_len

In reply to David Ahern

From: David Ahern <[email protected]>

Change nlmsg_len from sizeof(req) to use NLMSG_LENGTH on the header. 2 of the inner headers are not 4-byte aligned, so add a 0-length buf after the header with the __aligned(NLMSG_ALIGNTO) to ensure the size of the request is large enough. Use NLMSG_ALIGN in NLMSG_LENGTH to set nlmsg_len.

---
 lib/libnetlink.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)
lib/libnetlink.c +14 -10
index e28e1ab6da5e..8ab2355fc26b 100644
@@ -28,6 +28,8 @@
 
 #include "libnetlink.h"
 
+#define __aligned(x)		__attribute__((aligned(x)))
+
 #ifndef SOL_NETLINK
 #define SOL_NETLINK 270
 #endif
@@ -238,7 +240,7 @@ int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
 		struct nlmsghdr nlh;
 		struct ifaddrmsg ifm;
 	} req = {
-		.nlh.nlmsg_len = sizeof(req),
+		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
 		.nlh.nlmsg_type = RTM_GETADDR,
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -254,7 +256,7 @@ int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
 		struct nlmsghdr nlh;
 		struct ifaddrlblmsg ifal;
 	} req = {
-		.nlh.nlmsg_len = sizeof(req),
+		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)),
 		.nlh.nlmsg_type = RTM_GETADDRLABEL,
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -270,7 +272,7 @@ int rtnl_routedump_req(struct rtnl_handle *rth, int family)
 		struct nlmsghdr nlh;
 		struct rtmsg rtm;
 	} req = {
-		.nlh.nlmsg_len = sizeof(req),
+		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
 		.nlh.nlmsg_type = RTM_GETROUTE,
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -286,7 +288,7 @@ int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
 		struct nlmsghdr nlh;
 		struct fib_rule_hdr frh;
 	} req = {
-		.nlh.nlmsg_len = sizeof(req),
+		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
 		.nlh.nlmsg_type = RTM_GETRULE,
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -302,7 +304,7 @@ int rtnl_neighdump_req(struct rtnl_handle *rth, int family)
 		struct nlmsghdr nlh;
 		struct ndmsg ndm;
 	} req = {
-		.nlh.nlmsg_len = sizeof(req),
+		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
 		.nlh.nlmsg_type = RTM_GETNEIGH,
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -318,7 +320,7 @@ int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
 		struct nlmsghdr nlh;
 		struct ndtmsg ndtmsg;
 	} req = {
-		.nlh.nlmsg_len = sizeof(req),
+		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)),
 		.nlh.nlmsg_type = RTM_GETNEIGHTBL,
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -334,7 +336,7 @@ int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
 		struct nlmsghdr nlh;
 		struct br_port_msg bpm;
 	} req = {
-		.nlh.nlmsg_len = sizeof(req),
+		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)),
 		.nlh.nlmsg_type = RTM_GETMDB,
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -349,8 +351,9 @@ int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
 	struct {
 		struct nlmsghdr nlh;
 		struct netconfmsg ncm;
+		char buf[0] __aligned(NLMSG_ALIGNTO);
 	} req = {
-		.nlh.nlmsg_len = sizeof(req),
+		.nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct netconfmsg))),
 		.nlh.nlmsg_type = RTM_GETNETCONF,
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -365,8 +368,9 @@ int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)
 	struct {
 		struct nlmsghdr nlh;
 		struct rtgenmsg rtm;
+		char buf[0] __aligned(NLMSG_ALIGNTO);
 	} req = {
-		.nlh.nlmsg_len = sizeof(req),
+		.nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg))),
 		.nlh.nlmsg_type = RTM_GETNSID,
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
@@ -388,7 +392,7 @@ int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
 		struct nlmsghdr nlh;
 		struct ifinfomsg ifm;
 		/* attribute has to be NLMSG aligned */
-		struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO)));
+		struct rtattr ext_req __aligned(NLMSG_ALIGNTO);
 		__u32 ext_filter_mask;
 	} req = {
 		.nlh.nlmsg_len = sizeof(req),
Signature · 1 line
2.11.0
#3 lore raw

PATCH 3/12 libnetlink: linkdump_req: Only AF_UNSPEC family expects an ext_filter_mask

In reply to David Ahern

From: David Ahern <[email protected]>

Only AF_UNSPEC handled by rtnl_dump_ifinfo expects an ext_filter_mask on a dump request. Update the linkdump request functions to only set and send ext_filter_mask for AF_UNSPEC.

---
 lib/libnetlink.c | 93 ++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 60 insertions(+), 33 deletions(-)
lib/libnetlink.c +60 -33
index 8ab2355fc26b..b9c37fd36211 100644
@@ -380,58 +380,85 @@ int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)
 	return send(rth->fd, &req, sizeof(req), 0);
 }
 
-int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
-{
-	return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
-}
-
-int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
-			    __u32 filt_mask)
+static int __rtnl_linkdump_req(struct rtnl_handle *rth, int family)
 {
 	struct {
 		struct nlmsghdr nlh;
 		struct ifinfomsg ifm;
-		/* attribute has to be NLMSG aligned */
-		struct rtattr ext_req __aligned(NLMSG_ALIGNTO);
-		__u32 ext_filter_mask;
 	} req = {
-		.nlh.nlmsg_len = sizeof(req),
+		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
 		.nlh.nlmsg_type = RTM_GETLINK,
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
 		.ifm.ifi_family = family,
-		.ext_req.rta_type = IFLA_EXT_MASK,
-		.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)),
-		.ext_filter_mask = filt_mask,
 	};
 
 	return send(rth->fd, &req, sizeof(req), 0);
 }
 
+int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
+{
+	if (family == AF_UNSPEC)
+		return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
+
+	return __rtnl_linkdump_req(rth, family);
+}
+
+int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
+			    __u32 filt_mask)
+{
+	if (family == AF_UNSPEC) {
+		struct {
+			struct nlmsghdr nlh;
+			struct ifinfomsg ifm;
+			/* attribute has to be NLMSG aligned */
+			struct rtattr ext_req __aligned(NLMSG_ALIGNTO);
+			__u32 ext_filter_mask;
+		} req = {
+			.nlh.nlmsg_len = sizeof(req),
+			.nlh.nlmsg_type = RTM_GETLINK,
+			.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+			.nlh.nlmsg_seq = rth->dump = ++rth->seq,
+			.ifm.ifi_family = family,
+			.ext_req.rta_type = IFLA_EXT_MASK,
+			.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)),
+			.ext_filter_mask = filt_mask,
+		};
+
+		return send(rth->fd, &req, sizeof(req), 0);
+	}
+
+	return __rtnl_linkdump_req(rth, family);
+}
+
 int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
 				req_filter_fn_t filter_fn)
 {
-	struct {
-		struct nlmsghdr nlh;
-		struct ifinfomsg ifm;
-		char buf[1024];
-	} req = {
-		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-		.nlh.nlmsg_type = RTM_GETLINK,
-		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
-		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
-		.ifm.ifi_family = family,
-	};
-	int err;
-
-	if (!filter_fn)
-		return -EINVAL;
+	if (family == AF_UNSPEC) {
+		struct {
+			struct nlmsghdr nlh;
+			struct ifinfomsg ifm;
+			char buf[1024];
+		} req = {
+			.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+			.nlh.nlmsg_type = RTM_GETLINK,
+			.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+			.nlh.nlmsg_seq = rth->dump = ++rth->seq,
+			.ifm.ifi_family = family,
+		};
+		int err;
+
+		if (!filter_fn)
+			return -EINVAL;
+
+		err = filter_fn(&req.nlh, sizeof(req));
+		if (err)
+			return err;
 
-	err = filter_fn(&req.nlh, sizeof(req));
-	if (err)
-		return err;
+		return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
+	}
 
-	return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
+	return __rtnl_linkdump_req(rth, family);
 }
 
 int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
Signature · 1 line
2.11.0
#5 lore raw

PATCH 5/12 ip route: Add protocol, table id and device to dump request

In reply to David Ahern

From: David Ahern <[email protected]>

Add protocol, table id and device to dump request if set in filter. If kernel side filtering is supported it is used to reduce the amount of data sent to userspace.

Older kernels do not parse attributes on a route dump request, so these are silently ignored and ip will do the filtering in userspace.

---
 ip/iproute.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
ip/iproute.c +14 -0
index 3c0be0a96d4e..5bffb9d88b58 100644
@@ -1669,10 +1669,24 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
 static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen)
 {
 	struct rtmsg *rtm = NLMSG_DATA(nlh);
+	int err;
 
+	rtm->rtm_protocol = filter.protocol;
 	if (filter.cloned)
 		rtm->rtm_flags |= RTM_F_CLONED;
 
+	if (filter.tb) {
+		err = addattr32(nlh, reqlen, RTA_TABLE, filter.tb);
+		if (err)
+			return err;
+	}
+
+	if (filter.oif) {
+		err = addattr32(nlh, reqlen, RTA_OIF, filter.oif);
+		if (err)
+			return err;
+	}
+
 	return 0;
 }
 
Signature · 1 line
2.11.0
#6 lore raw

PATCH 6/12 mroute: fix up family handling

In reply to David Ahern

From: David Ahern <[email protected]>

Only ipv4 and ipv6 have multicast routing. Set family accordingly and just return for other cases.

---
 ip/ipmroute.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)
ip/ipmroute.c +9 -7
index de7a035f852f..b8f0bc49b92e 100644
@@ -223,18 +223,20 @@ void ipmroute_reset_filter(int ifindex)
 static int mroute_list(int argc, char **argv)
 {
 	char *id = NULL;
-	int family;
+	int family = preferred_family;
 
 	ipmroute_reset_filter(0);
-	if (preferred_family == AF_UNSPEC)
-		family = AF_INET;
-	else
-		family = AF_INET6;
-	if (family == AF_INET) {
+	if (family == AF_INET || family == AF_UNSPEC) {
+		family = RTNL_FAMILY_IPMR;
 		filter.af = RTNL_FAMILY_IPMR;
 		filter.tb = RT_TABLE_DEFAULT;  /* for backward compatibility */
-	} else
+	} else if (family == AF_INET6) {
+		family = RTNL_FAMILY_IP6MR;
 		filter.af = RTNL_FAMILY_IP6MR;
+	} else {
+		/* family does not have multicast routing */
+		return 0;
+	}
 
 	filter.msrc.family = filter.mdst.family = family;
 
Signature · 1 line
2.11.0
#7 lore raw

PATCH 7/12 mroute: Add table id attribute for kernel side filtering

In reply to David Ahern

From: David Ahern <[email protected]>

Similar to 'ip route' add the table id to the dump request for kernel side filtering if it is supported.

---
 ip/ipmroute.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
ip/ipmroute.c +14 -1
index b8f0bc49b92e..b29c78e4cc86 100644
@@ -220,6 +220,19 @@ void ipmroute_reset_filter(int ifindex)
 	filter.iif = ifindex;
 }
 
+static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen)
+{
+	int err;
+
+	if (filter.tb) {
+		err = addattr32(nlh, reqlen, RTA_TABLE, filter.tb);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 static int mroute_list(int argc, char **argv)
 {
 	char *id = NULL;
@@ -285,7 +298,7 @@ static int mroute_list(int argc, char **argv)
 		filter.iif = idx;
 	}
 
-	if (rtnl_routedump_req(&rth, filter.af, NULL) < 0) {
+	if (rtnl_routedump_req(&rth, filter.af, iproute_dump_filter) < 0) {
 		perror("Cannot send dump request");
 		return 1;
 	}
Signature · 1 line
2.11.0
#4 lore raw

PATCH 4/12 ip route: Remove rtnl_rtcache_request

In reply to David Ahern

From: David Ahern <[email protected]>

Add a filter option to rtnl_routedump_req and use it to set rtm_flags removing the need for rtnl_rtcache_request for dump requests.

---
 include/libnetlink.h |  7 ++++---
 ip/ipmroute.c        |  2 +-
 ip/iproute.c         | 43 ++++++++++++++-----------------------------
 lib/libnetlink.c     | 12 +++++++++++-
 4 files changed, 30 insertions(+), 34 deletions(-)
include/libnetlink.h +4 -3
index 138840d5c892..b0051f390980 100644
@@ -47,11 +47,14 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,
 
 void rtnl_close(struct rtnl_handle *rth);
 
+typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
+
 int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
 	__attribute__((warn_unused_result));
 int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
 	__attribute__((warn_unused_result));
-int rtnl_routedump_req(struct rtnl_handle *rth, int family)
+int rtnl_routedump_req(struct rtnl_handle *rth, int family,
+		       req_filter_fn_t filter_fn)
 	__attribute__((warn_unused_result));
 int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
 	__attribute__((warn_unused_result));
@@ -71,8 +74,6 @@ int rtnl_linkdump_req(struct rtnl_handle *rth, int fam)
 int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
 	__attribute__((warn_unused_result));
 
-typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
-
 int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int fam,
 				req_filter_fn_t fn)
 	__attribute__((warn_unused_result));
ip/ipmroute.c +1 -1
index 4d8867d3219f..de7a035f852f 100644
@@ -283,7 +283,7 @@ static int mroute_list(int argc, char **argv)
 		filter.iif = idx;
 	}
 
-	if (rtnl_routedump_req(&rth, filter.af) < 0) {
+	if (rtnl_routedump_req(&rth, filter.af, NULL) < 0) {
 		perror("Cannot send dump request");
 		return 1;
 	}
ip/iproute.c +14 -29

67 lines not on this page · raw message

lib/libnetlink.c +11 -1
index b9c37fd36211..56a1cadeb3db 100644
@@ -266,11 +266,13 @@ int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
 	return send(rth->fd, &req, sizeof(req), 0);
 }
 
-int rtnl_routedump_req(struct rtnl_handle *rth, int family)
+int rtnl_routedump_req(struct rtnl_handle *rth, int family,
+		       req_filter_fn_t filter_fn)
 {
 	struct {
 		struct nlmsghdr nlh;
 		struct rtmsg rtm;
+		char buf[128];
 	} req = {
 		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
 		.nlh.nlmsg_type = RTM_GETROUTE,
@@ -279,6 +281,14 @@ int rtnl_routedump_req(struct rtnl_handle *rth, int family)
 		.rtm.rtm_family = family,
 	};
 
+	if (filter_fn) {
+		int err;
+
+		err = filter_fn(&req.nlh, sizeof(req));
+		if (err)
+			return err;
+	}
+
 	return send(rth->fd, &req, sizeof(req), 0);
 }
 
Signature · 1 line
2.11.0
#8 lore raw

PATCH 8/12 ip address: Split ip_linkaddr_list into link and addr functions

In reply to David Ahern

From: David Ahern <[email protected]>

Split ip_linkaddr_list into one function that generates a list of devices and a second that generates the list of addresses.

---
 ip/ip_common.h |  3 +--
 ip/ipaddress.c | 39 ++++++++++++++++++++-------------------
 ip/ipvrf.c     |  2 +-
 3 files changed, 22 insertions(+), 22 deletions(-)
ip/ip_common.h +1 -2
index 53668f598cd2..d67575c63c24 100644
@@ -84,8 +84,7 @@ int do_seg6(int argc, char **argv);
 int iplink_get(char *name, __u32 filt_mask);
 int iplink_ifla_xstats(int argc, char **argv);
 
-int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
-		     struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo);
+int ip_link_list(req_filter_fn_t filter_fn, struct nlmsg_chain *linfo);
 void free_nlmsg_chain(struct nlmsg_chain *info);
 
 static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
ip/ipaddress.c +20 -19
index 016662e910e9..746dbfc58627 100644
@@ -1766,8 +1766,7 @@ static int iplink_filter_req(struct nlmsghdr *nlh, int reqlen)
  * caller can walk lists as desired and must call free_nlmsg_chain for
  * both when done
  */
-int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
-		     struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
+int ip_link_list(req_filter_fn_t filter_fn, struct nlmsg_chain *linfo)
 {
 	if (rtnl_linkdump_req_filter_fn(&rth, preferred_family,
 					filter_fn) < 0) {
@@ -1780,16 +1779,19 @@ int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
 		return 1;
 	}
 
-	if (ainfo) {
-		if (rtnl_addrdump_req(&rth, family) < 0) {
-			perror("Cannot send dump request");
-			return 1;
-		}
+	return 0;
+}
 
-		if (rtnl_dump_filter(&rth, store_nlmsg, ainfo) < 0) {
-			fprintf(stderr, "Dump terminated\n");
-			return 1;
-		}
+static int ip_addr_list(struct nlmsg_chain *ainfo)
+{
+	if (rtnl_addrdump_req(&rth, filter.family) < 0) {
+		perror("Cannot send dump request");
+		return 1;
+	}
+
+	if (rtnl_dump_filter(&rth, store_nlmsg, ainfo) < 0) {
+		fprintf(stderr, "Dump terminated\n");
+		return 1;
 	}
 
 	return 0;
@@ -1798,7 +1800,7 @@ int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
 static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
 {
 	struct nlmsg_chain linfo = { NULL, NULL};
-	struct nlmsg_chain _ainfo = { NULL, NULL}, *ainfo = NULL;
+	struct nlmsg_chain _ainfo = { NULL, NULL}, *ainfo = &_ainfo;
 	struct nlmsg_list *l;
 	char *filter_dev = NULL;
 	int no_link = 0;
@@ -1940,19 +1942,18 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
 		goto out;
 	}
 
-	if (filter.family != AF_PACKET) {
-		ainfo = &_ainfo;
+	if (ip_link_list(iplink_filter_req, &linfo) != 0)
+		goto out;
 
+	if (filter.family != AF_PACKET) {
 		if (filter.oneline)
 			no_link = 1;
-	}
 
-	if (ip_linkaddr_list(filter.family, iplink_filter_req,
-			     &linfo, ainfo) != 0)
-		goto out;
+		if (ip_addr_list(ainfo) != 0)
+			goto out;
 
-	if (filter.family != AF_PACKET)
 		ipaddr_filter(&linfo, ainfo);
+	}
 
 	for (l = linfo.head; l; l = l->next) {
 		struct nlmsghdr *n = &l->h;
ip/ipvrf.c +1 -1
index 8a6b7f977b14..08a0d45b2570 100644
@@ -589,7 +589,7 @@ static int ipvrf_show(int argc, char **argv)
 		return 0;
 	}
 
-	if (ip_linkaddr_list(0, ipvrf_filter_req, &linfo, NULL) == 0) {
+	if (ip_link_list(ipvrf_filter_req, &linfo) == 0) {
 		struct nlmsg_list *l;
 		unsigned nvrf = 0;
 		int n;
Signature · 1 line
2.11.0
#10 lore raw

PATCH 10/12 ip bridge: Set NETLINK_DUMP_STRICT_CHK on socket

In reply to David Ahern

From: David Ahern <[email protected]>

iproute2 has been updated for the new strict policy in the kernel. Add a helper to call setsockopt to enable the feature. Add a call to ip.c and bridge.c

The setsockopt fails on older kernels and the error can be safely ignored
- any new fields or attributes are ignored by the older kernel.

---
 bridge/bridge.c      | 4 ++++
 include/libnetlink.h | 1 +
 ip/ip.c              | 2 ++
 lib/libnetlink.c     | 9 +++++++++
 4 files changed, 16 insertions(+)
bridge/bridge.c +4 -0
index a3d8154be898..a50d9d59b4c5 100644
@@ -97,6 +97,8 @@ static int batch(const char *name)
 		return EXIT_FAILURE;
 	}
 
+	rtnl_set_strict_dump(&rth);
+
 	cmdlineno = 0;
 	while (getcmdline(&line, &len, stdin) != -1) {
 		char *largv[100];
@@ -205,6 +207,8 @@ main(int argc, char **argv)
 	if (rtnl_open(&rth, 0) < 0)
 		exit(1);
 
+	rtnl_set_strict_dump(&rth);
+
 	if (argc > 1)
 		return do_cmd(argv[1], argc-1, argv+1);
 
include/libnetlink.h +1 -0
index 2621bc99ce7b..dc0c9c4eb3f5 100644
@@ -46,6 +46,7 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,
 	__attribute__((warn_unused_result));
 
 void rtnl_close(struct rtnl_handle *rth);
+void rtnl_set_strict_dump(struct rtnl_handle *rth);
 
 typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
 
ip/ip.c +2 -0
index a5bbacb4bb0f..e4131714018f 100644
@@ -308,6 +308,8 @@ int main(int argc, char **argv)
 	if (rtnl_open(&rth, 0) < 0)
 		exit(1);
 
+	rtnl_set_strict_dump(&rth);
+
 	if (strlen(basename) > 2)
 		return do_cmd(basename+2, argc, argv);
 
lib/libnetlink.c +9 -0
index 0ddd646a8775..7b02c754c1d0 100644
@@ -161,6 +161,15 @@ static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
 }
 #endif
 
+/* Older kernels may not support strict dump and filtering */
+void rtnl_set_strict_dump(struct rtnl_handle *rth)
+{
+	int one = 1;
+
+	setsockopt(rth->fd, SOL_NETLINK, NETLINK_DUMP_STRICT_CHK,
+		   &one, sizeof(one));
+}
+
 void rtnl_close(struct rtnl_handle *rth)
 {
 	if (rth->fd >= 0) {
Signature · 1 line
2.11.0
#11 lore raw

PATCH 11/12 ip route: Rename do_ipv6 to dump_family

In reply to David Ahern

From: David Ahern <[email protected]>

do_ipv6 is really the preferred dump family. Rename it to make that apparent.

---
 ip/iproute.c | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)
ip/iproute.c +18 -18
index 5bffb9d88b58..0440366ee26a 100644
@@ -1604,7 +1604,7 @@ static int save_route_prep(void)
 	return 0;
 }
 
-static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
+static int iproute_flush(int family, rtnl_filter_t filter_fn)
 {
 	time_t start = time(0);
 	char flushb[4096-512];
@@ -1612,12 +1612,12 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
 	int ret;
 
 	if (filter.cloned) {
-		if (do_ipv6 != AF_INET6) {
+		if (family != AF_INET6) {
 			iproute_flush_cache();
 			if (show_stats)
 				printf("*** IPv4 routing cache is flushed.\n");
 		}
-		if (do_ipv6 == AF_INET)
+		if (family == AF_INET)
 			return 0;
 	}
 
@@ -1626,7 +1626,7 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
 	filter.flushe = sizeof(flushb);
 
 	for (;;) {
-		if (rtnl_routedump_req(&rth, do_ipv6, NULL) < 0) {
+		if (rtnl_routedump_req(&rth, family, NULL) < 0) {
 			perror("Cannot send dump request");
 			return -2;
 		}
@@ -1638,7 +1638,7 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
 		if (filter.flushed == 0) {
 			if (show_stats) {
 				if (round == 0 &&
-				    (!filter.cloned || do_ipv6 == AF_INET6))
+				    (!filter.cloned || family == AF_INET6))
 					printf("Nothing to flush.\n");
 				else
 					printf("*** Flush is complete after %d round%s ***\n",
@@ -1692,7 +1692,7 @@ static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen)
 
 static int iproute_list_flush_or_save(int argc, char **argv, int action)
 {
-	int do_ipv6 = preferred_family;
+	int dump_family = preferred_family;
 	char *id = NULL;
 	char *od = NULL;
 	unsigned int mark = 0;
@@ -1811,13 +1811,13 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 			NEXT_ARG();
 			family = read_family(*argv);
 			if (family == AF_UNSPEC)
-				family = do_ipv6;
+				family = dump_family;
 			else
 				NEXT_ARG();
 			get_prefix(&filter.rvia, *argv, family);
 		} else if (strcmp(*argv, "src") == 0) {
 			NEXT_ARG();
-			get_prefix(&filter.rprefsrc, *argv, do_ipv6);
+			get_prefix(&filter.rprefsrc, *argv, dump_family);
 		} else if (matches(*argv, "realms") == 0) {
 			__u32 realm;
 
@@ -1837,15 +1837,15 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 			NEXT_ARG();
 			if (matches(*argv, "root") == 0) {
 				NEXT_ARG();
-				get_prefix(&filter.rsrc, *argv, do_ipv6);
+				get_prefix(&filter.rsrc, *argv, dump_family);
 			} else if (matches(*argv, "match") == 0) {
 				NEXT_ARG();
-				get_prefix(&filter.msrc, *argv, do_ipv6);
+				get_prefix(&filter.msrc, *argv, dump_family);
 			} else {
 				if (matches(*argv, "exact") == 0) {
 					NEXT_ARG();
 				}
-				get_prefix(&filter.msrc, *argv, do_ipv6);
+				get_prefix(&filter.msrc, *argv, dump_family);
 				filter.rsrc = filter.msrc;
 			}
 		} else {
@@ -1854,23 +1854,23 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 			}
 			if (matches(*argv, "root") == 0) {
 				NEXT_ARG();
-				get_prefix(&filter.rdst, *argv, do_ipv6);
+				get_prefix(&filter.rdst, *argv, dump_family);
 			} else if (matches(*argv, "match") == 0) {
 				NEXT_ARG();
-				get_prefix(&filter.mdst, *argv, do_ipv6);
+				get_prefix(&filter.mdst, *argv, dump_family);
 			} else {
 				if (matches(*argv, "exact") == 0) {
 					NEXT_ARG();
 				}
-				get_prefix(&filter.mdst, *argv, do_ipv6);
+				get_prefix(&filter.mdst, *argv, dump_family);
 				filter.rdst = filter.mdst;
 			}
 		}
 		argc--; argv++;
 	}
 
-	if (do_ipv6 == AF_UNSPEC && filter.tb)
-		do_ipv6 = AF_INET;
+	if (dump_family == AF_UNSPEC && filter.tb)
+		dump_family = AF_INET;
 
 	if (id || od)  {
 		int idx;
@@ -1893,9 +1893,9 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 	filter.mark = mark;
 
 	if (action == IPROUTE_FLUSH)
-		return iproute_flush(do_ipv6, filter_fn);
+		return iproute_flush(dump_family, filter_fn);
 
-	if (rtnl_routedump_req(&rth, do_ipv6, iproute_dump_filter) < 0) {
+	if (rtnl_routedump_req(&rth, dump_family, iproute_dump_filter) < 0) {
 		perror("Cannot send dump request");
 		return -2;
 	}
Signature · 1 line
2.11.0
#9 lore raw

PATCH 9/12 ip address: Set device index in dump request

In reply to David Ahern

From: David Ahern <[email protected]>

Add a filter function to rtnl_addrdump_req to set device index in the address dump request if the user is filtering addresses by device. In addition, add a new ipaddr_link_get to do a single RTM_GETLINK request instead of a device dump yet still store the data in the linfo list.

---
 include/libnetlink.h |  3 ++-
 ip/ipaddress.c       | 59 +++++++++++++++++++++++++++++++++++++++++++++-------
 lib/libnetlink.c     | 12 ++++++++++-
 3 files changed, 65 insertions(+), 9 deletions(-)
include/libnetlink.h +2 -1
index b0051f390980..2621bc99ce7b 100644
@@ -49,7 +49,8 @@ void rtnl_close(struct rtnl_handle *rth);
 
 typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
 
-int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
+int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
+		      req_filter_fn_t filter_fn)
 	__attribute__((warn_unused_result));
 int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
 	__attribute__((warn_unused_result));
ip/ipaddress.c +52 -7

101 lines not on this page · raw message

lib/libnetlink.c +11 -1
index 56a1cadeb3db..0ddd646a8775 100644
@@ -234,11 +234,13 @@ int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
 	return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
 }
 
-int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
+int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
+		      req_filter_fn_t filter_fn)
 {
 	struct {
 		struct nlmsghdr nlh;
 		struct ifaddrmsg ifm;
+		char buf[128];
 	} req = {
 		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
 		.nlh.nlmsg_type = RTM_GETADDR,
@@ -247,6 +249,14 @@ int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
 		.ifm.ifa_family = family,
 	};
 
+	if (filter_fn) {
+		int err;
+
+		err = filter_fn(&req.nlh, sizeof(req));
+		if (err)
+			return err;
+	}
+
 	return send(rth->fd, &req, sizeof(req), 0);
 }
 
Signature · 1 line
2.11.0
#12 lore raw

PATCH 12/12 neighbor: Add support for protocol attribute

In reply to David Ahern

From: David Ahern <[email protected]>

Add support to set protocol on neigh entries and to print the protocol on dumps.

---
 ip/ipneigh.c | 39 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)
ip/ipneigh.c +36 -3
index 6041c467749c..26ac2d1be21f 100644
@@ -40,6 +40,7 @@ static struct
 	int flushp;
 	int flushe;
 	int master;
+	int protocol;
 } filter;
 
 static void usage(void) __attribute__((noreturn));
@@ -48,7 +49,7 @@ static void usage(void)
 {
 	fprintf(stderr, "Usage: ip neigh { add | del | change | replace }\n"
 			"                { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n");
-	fprintf(stderr, "                                 [ router ] [ extern_learn ]\n\n");
+	fprintf(stderr, "                [ router ] [ extern_learn ] [ protocol PROTO ]\n\n");
 	fprintf(stderr, "       ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n");
 	fprintf(stderr, "                                 [ vrf NAME ]\n\n");
 	fprintf(stderr, "STATE := { permanent | noarp | stale | reachable | none |\n"
@@ -148,6 +149,14 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
 			NEXT_ARG();
 			dev = *argv;
 			dev_ok = 1;
+		} else if (matches(*argv, "protocol") == 0) {
+			__u32 proto;
+
+			NEXT_ARG();
+			if (rtnl_rtprot_a2n(&proto, *argv))
+				invarg("\"protocol\" value is invalid\n", *argv);
+			if (addattr8(&req.n, sizeof(req), NDA_PROTOCOL, proto))
+				return -1;
 		} else {
 			if (strcmp(*argv, "to") == 0) {
 				NEXT_ARG();
@@ -244,6 +253,7 @@ int print_neigh(struct nlmsghdr *n, void *arg)
 	int len = n->nlmsg_len;
 	struct rtattr *tb[NDA_MAX+1];
 	static int logit = 1;
+	__u8 protocol = 0;
 
 	if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
 	    n->nlmsg_type != RTM_GETNEIGH) {
@@ -285,6 +295,12 @@ int print_neigh(struct nlmsghdr *n, void *arg)
 	if (inet_addr_match_rta(&filter.pfx, tb[NDA_DST]))
 		return 0;
 
+	if (tb[NDA_PROTOCOL])
+		protocol = rta_getattr_u8(tb[NDA_PROTOCOL]);
+
+	if (filter.protocol && filter.protocol != protocol)
+		return 0;
+
 	if (filter.unused_only && tb[NDA_CACHEINFO]) {
 		struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
 
@@ -371,6 +387,13 @@ int print_neigh(struct nlmsghdr *n, void *arg)
 	if (r->ndm_state)
 		print_neigh_state(r->ndm_state);
 
+	if (protocol) {
+		SPRINT_BUF(b1);
+
+		print_string(PRINT_ANY, "protocol", " proto %s ",
+			     rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
+	}
+
 	print_string(PRINT_FP, NULL, "\n", "");
 	close_json_object();
 	fflush(stdout);
@@ -458,9 +481,19 @@ static int do_show_or_flush(int argc, char **argv, int flush)
 			if (state == 0)
 				state = 0x100;
 			filter.state |= state;
-		} else if (strcmp(*argv, "proxy") == 0)
+		} else if (strcmp(*argv, "proxy") == 0) {
 			req.ndm.ndm_flags = NTF_PROXY;
-		else {
+		} else if (matches(*argv, "protocol") == 0) {
+			__u32 prot;
+
+			NEXT_ARG();
+			if (rtnl_rtprot_a2n(&prot, *argv)) {
+				if (strcmp(*argv, "all"))
+					invarg("invalid \"protocol\"\n", *argv);
+				prot = 0;
+			}
+			filter.protocol = prot;
+		} else {
 			if (strcmp(*argv, "to") == 0) {
 				NEXT_ARG();
 			}
Signature · 1 line
2.11.0
#13 lore raw
In reply to David Ahern
Quoted 4 lines · David Ahern

From: David Ahern <[email protected]>

Refactorings and updates to use the new strict checking in the kernel along with the new kernel side filtering.

David,

Since this was applied to iproute2-next I get:

bash-4.4# bridge/bridge fdb show

[ 5365.137224] netlink: 4 bytes leftover after parsing attributes in process `bridge'.

Error: bytes leftover after parsing attributes.
Dump terminated

And a lot of tests are failing. Given you enabled strict checking, I assume we should be using 'struct ndmsg' in FDB dump? Following patch fixes it for me. I can submit formally if you don't already have a patch.

bridge/fdb.c +6 -6
index a5abc1b6c78d..a7a0d8052307 100644
@@ -260,16 +260,16 @@ static int fdb_show(int argc, char **argv)
 {
 	struct {
 		struct nlmsghdr	n;
-		struct ifinfomsg	ifm;
+		struct ndmsg		ndm;
 		char			buf[256];
 	} req = {
-		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-		.ifm.ifi_family = PF_BRIDGE,
+		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
+		.ndm.ndm_family = PF_BRIDGE,
 	};
 
 	char *filter_dev = NULL;
 	char *br = NULL;
-	int msg_size = sizeof(struct ifinfomsg);
+	int msg_size = sizeof(struct ndmsg);
 
 	while (argc > 0) {
 		if ((strcmp(*argv, "brport") == 0) || strcmp(*argv, "dev") == 0) {
@@ -313,10 +313,10 @@ static int fdb_show(int argc, char **argv)
 		filter_index = ll_name_to_index(filter_dev);
 		if (!filter_index)
 			return nodev(filter_dev);
-		req.ifm.ifi_index = filter_index;
+		req.ndm.ndm_ifindex = filter_index;
 	}
 
-	if (rtnl_dump_request(&rth, RTM_GETNEIGH, &req.ifm, msg_size) < 0) {
+	if (rtnl_dump_request(&rth, RTM_GETNEIGH, &req.ndm, msg_size) < 0) {
 		perror("Cannot send dump request");
 		exit(1);
 	}
#14 lore raw
Quoted 15 lines · Ido Schimmel
Quoted 6 lines · David Ahern

From: David Ahern <[email protected]>

Refactorings and updates to use the new strict checking in the kernel along with the new kernel side filtering.

David,

Since this was applied to iproute2-next I get:

bash-4.4# bridge/bridge fdb show

Quoted 8 lines
[ 5365.137224] netlink: 4 bytes leftover after parsing attributes in process `bridge'.

Error: bytes leftover after parsing attributes.
Dump terminated

And a lot of tests are failing. Given you enabled strict checking, I assume we should be using 'struct ndmsg' in FDB dump? Following patch fixes it for me. I can submit formally if you don't already have a patch.

Please submit formally. Thanks for the fix

Quoted 39 lines
bridge/fdb.c +6 -6
index a5abc1b6c78d..a7a0d8052307 100644
@@ -260,16 +260,16 @@ static int fdb_show(int argc, char **argv)
 {
   struct {
       struct nlmsghdr    n;
-        struct ifinfomsg    ifm;
+        struct ndmsg        ndm;
       char            buf[256];
   } req = {
-        .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-        .ifm.ifi_family = PF_BRIDGE,
+        .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
+        .ndm.ndm_family = PF_BRIDGE,
   };
 
   char *filter_dev = NULL;
   char *br = NULL;
-    int msg_size = sizeof(struct ifinfomsg);
+    int msg_size = sizeof(struct ndmsg);
 
   while (argc > 0) {
       if ((strcmp(*argv, "brport") == 0) || strcmp(*argv, "dev") == 0) {
@@ -313,10 +313,10 @@ static int fdb_show(int argc, char **argv)
       filter_index = ll_name_to_index(filter_dev);
       if (!filter_index)
           return nodev(filter_dev);
-        req.ifm.ifi_index = filter_index;
+        req.ndm.ndm_ifindex = filter_index;
   }
 
-    if (rtnl_dump_request(&rth, RTM_GETNEIGH, &req.ifm, msg_size) < 0) {
+    if (rtnl_dump_request(&rth, RTM_GETNEIGH, &req.ndm, msg_size) < 0) {
       perror("Cannot send dump request");
       exit(1);
   }