Add support for filtering neighbor dumps by master device. Kernel side support provided by commit 21fdd092acc7. Since the feature is not available in older kernels the user is given a warning message if the kernel does not support the request.
Signed-off-by: David Ahern <d...@cumulusnetworks.com> --- include/libnetlink.h | 2 ++ ip/ipneigh.c | 35 +++++++++++++++++++++++++++++++---- lib/libnetlink.c | 21 +++++++++++++++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/include/libnetlink.h b/include/libnetlink.h index 0503dea5c367..4813359172ca 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -42,6 +42,8 @@ int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int fam, int type, int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) __attribute__((warn_unused_result)); +int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n) + __attribute__((warn_unused_result)); struct rtnl_ctrl_data { int nsid; diff --git a/ip/ipneigh.c b/ip/ipneigh.c index a9e23f450c16..ba25a00b2a78 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -39,6 +39,7 @@ static struct char *flushb; int flushp; int flushe; + int master; } filter; static void usage(void) __attribute__((noreturn)); @@ -193,6 +194,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) int len = n->nlmsg_len; struct rtattr * tb[NDA_MAX+1]; char abuf[256]; + static int logit = 1; if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH && n->nlmsg_type != RTM_GETNEIGH) { @@ -220,6 +222,14 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) (r->ndm_family != AF_DECnet)) return 0; + if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) { + if (logit) { + logit = 0; + fprintf(fp, + "\nWARNING: Kernel does not support filtering by master device\n\n"); + } + } + parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); if (tb[NDA_DST]) { @@ -327,9 +337,18 @@ void ipneigh_reset_filter(int ifindex) static int do_show_or_flush(int argc, char **argv, int flush) { + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; char *filter_dev = NULL; int state_given = 0; - struct ndmsg ndm = { 0 }; + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_type = RTM_GETNEIGH; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); ipneigh_reset_filter(0); @@ -351,6 +370,14 @@ static int do_show_or_flush(int argc, char **argv, int flush) if (filter_dev) duparg("dev", *argv); filter_dev = *argv; + } else if (strcmp(*argv, "master") == 0) { + int ifindex; + NEXT_ARG(); + ifindex = ll_name_to_index(*argv); + if (!ifindex) + invarg("Device does not exist\n", *argv); + addattr32(&req.n, sizeof(req), NDA_MASTER, ifindex); + filter.master = ifindex; } else if (strcmp(*argv, "unused") == 0) { filter.unused_only = 1; } else if (strcmp(*argv, "nud") == 0) { @@ -371,7 +398,7 @@ static int do_show_or_flush(int argc, char **argv, int flush) state = 0x100; filter.state |= state; } else if (strcmp(*argv, "proxy") == 0) - ndm.ndm_flags = NTF_PROXY; + req.ndm.ndm_flags = NTF_PROXY; else { if (strcmp(*argv, "to") == 0) { NEXT_ARG(); @@ -436,9 +463,9 @@ static int do_show_or_flush(int argc, char **argv, int flush) return 1; } - ndm.ndm_family = filter.family; + req.ndm.ndm_family = filter.family; - if (rtnl_dump_request(&rth, RTM_GETNEIGH, &ndm, sizeof(struct ndmsg)) < 0) { + if (rtnl_dump_request_n(&rth, &req.n) < 0) { perror("Cannot send dump request"); exit(1); } diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 46cac34c7581..8e3762c1795d 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -191,6 +191,27 @@ int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) return sendmsg(rth->fd, &msg, 0); } +int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n) +{ + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; + struct iovec iov = { + .iov_base = (void*) n, + .iov_len = n->nlmsg_len + }; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + n->nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; + n->nlmsg_pid = 0; + n->nlmsg_seq = rth->dump = ++rth->seq; + + return sendmsg(rth->fd, &msg, 0); +} + int rtnl_dump_filter_l(struct rtnl_handle *rth, const struct rtnl_dump_filter_arg *arg) { -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html