ip neigh: Add support for filtering dumps by master device
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>
This commit is contained in:
parent
23e905096c
commit
0d238ca2b8
|
|
@ -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 rtnl_dump_request(struct rtnl_handle *rth, int type, void *req,
|
||||||
int len)
|
int len)
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
|
int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
|
||||||
|
__attribute__((warn_unused_result));
|
||||||
|
|
||||||
struct rtnl_ctrl_data {
|
struct rtnl_ctrl_data {
|
||||||
int nsid;
|
int nsid;
|
||||||
|
|
|
||||||
35
ip/ipneigh.c
35
ip/ipneigh.c
|
|
@ -39,6 +39,7 @@ static struct
|
||||||
char *flushb;
|
char *flushb;
|
||||||
int flushp;
|
int flushp;
|
||||||
int flushe;
|
int flushe;
|
||||||
|
int master;
|
||||||
} filter;
|
} filter;
|
||||||
|
|
||||||
static void usage(void) __attribute__((noreturn));
|
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;
|
int len = n->nlmsg_len;
|
||||||
struct rtattr * tb[NDA_MAX+1];
|
struct rtattr * tb[NDA_MAX+1];
|
||||||
char abuf[256];
|
char abuf[256];
|
||||||
|
static int logit = 1;
|
||||||
|
|
||||||
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
|
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
|
||||||
n->nlmsg_type != RTM_GETNEIGH) {
|
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))
|
(r->ndm_family != AF_DECnet))
|
||||||
return 0;
|
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)));
|
parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
|
||||||
|
|
||||||
if (tb[NDA_DST]) {
|
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)
|
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;
|
char *filter_dev = NULL;
|
||||||
int state_given = 0;
|
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);
|
ipneigh_reset_filter(0);
|
||||||
|
|
||||||
|
|
@ -351,6 +370,14 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
||||||
if (filter_dev)
|
if (filter_dev)
|
||||||
duparg("dev", *argv);
|
duparg("dev", *argv);
|
||||||
filter_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) {
|
} else if (strcmp(*argv, "unused") == 0) {
|
||||||
filter.unused_only = 1;
|
filter.unused_only = 1;
|
||||||
} else if (strcmp(*argv, "nud") == 0) {
|
} else if (strcmp(*argv, "nud") == 0) {
|
||||||
|
|
@ -371,7 +398,7 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
||||||
state = 0x100;
|
state = 0x100;
|
||||||
filter.state |= state;
|
filter.state |= state;
|
||||||
} else if (strcmp(*argv, "proxy") == 0)
|
} else if (strcmp(*argv, "proxy") == 0)
|
||||||
ndm.ndm_flags = NTF_PROXY;
|
req.ndm.ndm_flags = NTF_PROXY;
|
||||||
else {
|
else {
|
||||||
if (strcmp(*argv, "to") == 0) {
|
if (strcmp(*argv, "to") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
|
|
@ -436,9 +463,9 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
||||||
return 1;
|
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");
|
perror("Cannot send dump request");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,27 @@ int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
|
||||||
return sendmsg(rth->fd, &msg, 0);
|
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,
|
int rtnl_dump_filter_l(struct rtnl_handle *rth,
|
||||||
const struct rtnl_dump_filter_arg *arg)
|
const struct rtnl_dump_filter_arg *arg)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue