int flushp;
int flushe;
int master;
+ int protocol;
+ __u8 ndm_flags;
} filter;
static void usage(void) __attribute__((noreturn));
{
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 ] [ 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"
dst_ok = 1;
dev_ok = 1;
req.ndm.ndm_flags |= NTF_PROXY;
+ } else if (strcmp(*argv, "router") == 0) {
+ req.ndm.ndm_flags |= NTF_ROUTER;
+ } else if (matches(*argv, "extern_learn") == 0) {
+ req.ndm.ndm_flags |= NTF_EXT_LEARNED;
} else if (strcmp(*argv, "dev") == 0) {
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();
close_json_array(PRINT_JSON, NULL);
}
-int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+int print_neigh(struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE *)arg;
struct ndmsg *r = NLMSG_DATA(n);
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) {
return 0;
if (!(filter.state&r->ndm_state) &&
!(r->ndm_flags & NTF_PROXY) &&
+ !(r->ndm_flags & NTF_EXT_LEARNED) &&
(r->ndm_state || !(filter.state&0x100)) &&
(r->ndm_family != AF_DECnet))
return 0;
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]);
if (tb[NDA_DST]) {
const char *dst;
+ int family = r->ndm_family;
+
+ if (family == AF_BRIDGE) {
+ if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
+ family = AF_INET6;
+ else
+ family = AF_INET;
+ }
- dst = format_host_rta(r->ndm_family, tb[NDA_DST]);
+ dst = format_host_rta(family, tb[NDA_DST]);
print_color_string(PRINT_ANY,
- ifa_family_color(r->ndm_family),
+ ifa_family_color(family),
"dst", "%s ", dst);
}
if (r->ndm_flags & NTF_PROXY)
print_null(PRINT_ANY, "proxy", " %s", "proxy");
+ if (r->ndm_flags & NTF_EXT_LEARNED)
+ print_null(PRINT_ANY, "extern_learn", " %s ", "extern_learn");
+
if (show_stats) {
if (tb[NDA_CACHEINFO])
print_cacheinfo(RTA_DATA(tb[NDA_CACHEINFO]));
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);
filter.index = ifindex;
}
+static int ipneigh_dump_filter(struct nlmsghdr *nlh, int reqlen)
+{
+ struct ndmsg *ndm = NLMSG_DATA(nlh);
+ int err;
+
+ ndm->ndm_flags = filter.ndm_flags;
+
+ if (filter.index) {
+ err = addattr32(nlh, reqlen, NDA_IFINDEX, filter.index);
+ if (err)
+ return err;
+ }
+ if (filter.master) {
+ err = addattr32(nlh, reqlen, NDA_MASTER, filter.master);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int do_show_or_flush(int argc, char **argv, int flush)
{
- struct {
- struct nlmsghdr n;
- struct ndmsg ndm;
- char buf[256];
- } req = {
- .n.nlmsg_type = RTM_GETNEIGH,
- .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
- };
char *filter_dev = NULL;
int state_given = 0;
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, "vrf") == 0) {
int ifindex;
invarg("Not a valid VRF name\n", *argv);
if (!name_is_vrf(*argv))
invarg("Not a valid VRF name\n", *argv);
- addattr32(&req.n, sizeof(req), NDA_MASTER, ifindex);
filter.master = ifindex;
} else if (strcmp(*argv, "unused") == 0) {
filter.unused_only = 1;
if (state == 0)
state = 0x100;
filter.state |= state;
- } else if (strcmp(*argv, "proxy") == 0)
- req.ndm.ndm_flags = NTF_PROXY;
- else {
+ } else if (strcmp(*argv, "proxy") == 0) {
+ filter.ndm_flags = NTF_PROXY;
+ } 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();
}
filter.index = ll_name_to_index(filter_dev);
if (!filter.index)
return nodev(filter_dev);
- addattr32(&req.n, sizeof(req), NDA_IFINDEX, filter.index);
}
- req.ndm.ndm_family = filter.family;
-
if (flush) {
int round = 0;
char flushb[4096-512];
filter.flushe = sizeof(flushb);
while (round < MAX_ROUNDS) {
- if (rtnl_dump_request_n(&rth, &req.n) < 0) {
+ if (rtnl_neighdump_req(&rth, filter.family,
+ ipneigh_dump_filter) < 0) {
perror("Cannot send dump request");
exit(1);
}
return 1;
}
- if (rtnl_dump_request_n(&rth, &req.n) < 0) {
+ if (rtnl_neighdump_req(&rth, filter.family, ipneigh_dump_filter) < 0) {
perror("Cannot send dump request");
exit(1);
}