]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
ip neigh: Add support for filtering dumps by master device
authorDavid Ahern <dsa@cumulusnetworks.com>
Fri, 2 Oct 2015 16:42:27 +0000 (09:42 -0700)
committerStephen Hemminger <shemming@brocade.com>
Mon, 12 Oct 2015 16:39:37 +0000 (09:39 -0700)
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 <dsa@cumulusnetworks.com>
include/libnetlink.h
ip/ipneigh.c
lib/libnetlink.c

index 0503dea5c36726e27c2af761ee5b1b6fc9df3828..4813359172cadce0658dc4c4add2268d8a5770c4 100644 (file)
@@ -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;
index a9e23f450c16ecc0ac4a8ca80472cc6cd641aa50..b8973a2d0a0800a74caf7ed251bb9a9b85a4e885 100644 (file)
@@ -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);
        }
index 46cac34c7581e45c038a3e37d71f2eeb8dd962b7..8e3762c1795d93f10f9d59c2086b5ab6bdeadcce 100644 (file)
@@ -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)
 {