]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/ipneigh.c
ip: iplink: Convert to use parse_on_off()
[mirror_iproute2.git] / ip / ipneigh.c
CommitLineData
aba5acdf
SH
1/*
2 * ipneigh.c "ip neigh".
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
aba5acdf
SH
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
aba5acdf
SH
16#include <fcntl.h>
17#include <string.h>
18#include <sys/time.h>
aba5acdf
SH
19#include <sys/socket.h>
20#include <netinet/in.h>
21#include <netinet/ip.h>
22
23#include "rt_names.h"
24#include "utils.h"
25#include "ip_common.h"
aac7f725 26#include "json_print.h"
aba5acdf
SH
27
28#define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
66081849 29#define MAX_ROUNDS 10
aba5acdf
SH
30
31static struct
32{
33 int family;
56f5daac 34 int index;
aba5acdf
SH
35 int state;
36 int unused_only;
37 inet_prefix pfx;
38 int flushed;
39 char *flushb;
40 int flushp;
41 int flushe;
0d238ca2 42 int master;
6b83edc0 43 int protocol;
101ec10a 44 __u8 ndm_flags;
aba5acdf
SH
45} filter;
46
47static void usage(void) __attribute__((noreturn));
48
49static void usage(void)
50{
8589eb4e
MC
51 fprintf(stderr,
52 "Usage: ip neigh { add | del | change | replace }\n"
53 " { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n"
54 " [ router ] [ extern_learn ] [ protocol PROTO ]\n"
55 "\n"
56 " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n"
57 " [ vrf NAME ]\n"
62842362 58 " ip neigh get { ADDR | proxy ADDR } dev DEV\n"
8589eb4e
MC
59 "\n"
60 "STATE := { permanent | noarp | stale | reachable | none |\n"
61 " incomplete | delay | probe | failed }\n");
aba5acdf
SH
62 exit(-1);
63}
64
56f5daac 65static int nud_state_a2n(unsigned int *state, const char *arg)
aba5acdf
SH
66{
67 if (matches(arg, "permanent") == 0)
68 *state = NUD_PERMANENT;
69 else if (matches(arg, "reachable") == 0)
70 *state = NUD_REACHABLE;
71 else if (strcmp(arg, "noarp") == 0)
72 *state = NUD_NOARP;
73 else if (strcmp(arg, "none") == 0)
74 *state = NUD_NONE;
75 else if (strcmp(arg, "stale") == 0)
76 *state = NUD_STALE;
77 else if (strcmp(arg, "incomplete") == 0)
78 *state = NUD_INCOMPLETE;
79 else if (strcmp(arg, "delay") == 0)
80 *state = NUD_DELAY;
81 else if (strcmp(arg, "probe") == 0)
82 *state = NUD_PROBE;
83 else if (matches(arg, "failed") == 0)
84 *state = NUD_FAILED;
85 else {
86 if (get_unsigned(state, arg, 0))
87 return -1;
56f5daac 88 if (*state >= 0x100 || (*state&((*state)-1)))
aba5acdf
SH
89 return -1;
90 }
91 return 0;
92}
93
aba5acdf
SH
94static int flush_update(void)
95{
f31a37f7 96 if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
1fb0a998 97 perror("Failed to send flush request");
aba5acdf
SH
98 return -1;
99 }
100 filter.flushp = 0;
101 return 0;
102}
103
104
105static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
106{
aba5acdf 107 struct {
4806867a
SH
108 struct nlmsghdr n;
109 struct ndmsg ndm;
56f5daac 110 char buf[256];
d17b136f
PS
111 } req = {
112 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
113 .n.nlmsg_flags = NLM_F_REQUEST | flags,
114 .n.nlmsg_type = cmd,
115 .ndm.ndm_family = preferred_family,
116 .ndm.ndm_state = NUD_PERMANENT,
117 };
e834eb8e 118 char *dev = NULL;
aba5acdf 119 int dst_ok = 0;
e834eb8e 120 int dev_ok = 0;
aba5acdf 121 int lladdr_ok = 0;
56f5daac 122 char *lla = NULL;
aba5acdf
SH
123 inet_prefix dst;
124
aba5acdf
SH
125 while (argc > 0) {
126 if (matches(*argv, "lladdr") == 0) {
127 NEXT_ARG();
128 if (lladdr_ok)
129 duparg("lladdr", *argv);
130 lla = *argv;
131 lladdr_ok = 1;
132 } else if (strcmp(*argv, "nud") == 0) {
56f5daac
SH
133 unsigned int state;
134
aba5acdf
SH
135 NEXT_ARG();
136 if (nud_state_a2n(&state, *argv))
137 invarg("nud state is bad", *argv);
138 req.ndm.ndm_state = state;
139 } else if (matches(*argv, "proxy") == 0) {
140 NEXT_ARG();
141 if (matches(*argv, "help") == 0)
142 usage();
143 if (dst_ok)
144 duparg("address", *argv);
145 get_addr(&dst, *argv, preferred_family);
146 dst_ok = 1;
e834eb8e 147 dev_ok = 1;
aba5acdf 148 req.ndm.ndm_flags |= NTF_PROXY;
c2cd14ac
RP
149 } else if (strcmp(*argv, "router") == 0) {
150 req.ndm.ndm_flags |= NTF_ROUTER;
4c45b684
RP
151 } else if (matches(*argv, "extern_learn") == 0) {
152 req.ndm.ndm_flags |= NTF_EXT_LEARNED;
aba5acdf
SH
153 } else if (strcmp(*argv, "dev") == 0) {
154 NEXT_ARG();
e834eb8e
KK
155 dev = *argv;
156 dev_ok = 1;
6b83edc0
DA
157 } else if (matches(*argv, "protocol") == 0) {
158 __u32 proto;
159
160 NEXT_ARG();
161 if (rtnl_rtprot_a2n(&proto, *argv))
162 invarg("\"protocol\" value is invalid\n", *argv);
163 if (addattr8(&req.n, sizeof(req), NDA_PROTOCOL, proto))
164 return -1;
aba5acdf
SH
165 } else {
166 if (strcmp(*argv, "to") == 0) {
167 NEXT_ARG();
168 }
169 if (matches(*argv, "help") == 0) {
170 NEXT_ARG();
171 }
172 if (dst_ok)
173 duparg2("to", *argv);
174 get_addr(&dst, *argv, preferred_family);
175 dst_ok = 1;
176 }
177 argc--; argv++;
178 }
e834eb8e 179 if (!dev_ok || !dst_ok || dst.family == AF_UNSPEC) {
aba5acdf
SH
180 fprintf(stderr, "Device and destination are required arguments.\n");
181 exit(-1);
182 }
183 req.ndm.ndm_family = dst.family;
542b0cc7
SH
184 if (addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen) < 0)
185 return -1;
aba5acdf
SH
186
187 if (lla && strcmp(lla, "null")) {
7b565754 188 char llabuf[20];
aba5acdf
SH
189 int l;
190
191 l = ll_addr_a2n(llabuf, sizeof(llabuf), lla);
542b0cc7
SH
192 if (l < 0)
193 return -1;
194
195 if (addattr_l(&req.n, sizeof(req), NDA_LLADDR, llabuf, l) < 0)
196 return -1;
aba5acdf
SH
197 }
198
aba5acdf
SH
199 ll_init_map(&rth);
200
fe99adbc
SP
201 if (dev) {
202 req.ndm.ndm_ifindex = ll_name_to_index(dev);
203 if (!req.ndm.ndm_ifindex)
204 return nodev(dev);
aba5acdf
SH
205 }
206
86bf43c7 207 if (rtnl_talk(&rth, &req.n, NULL) < 0)
aba5acdf
SH
208 exit(2);
209
351efcde 210 return 0;
aba5acdf
SH
211}
212
aac7f725
SH
213static void print_cacheinfo(const struct nda_cacheinfo *ci)
214{
215 static int hz;
216
217 if (!hz)
218 hz = get_user_hz();
219
220 if (ci->ndm_refcnt)
221 print_uint(PRINT_ANY, "refcnt",
222 " ref %u", ci->ndm_refcnt);
223
224 print_uint(PRINT_ANY, "used", " used %u", ci->ndm_used / hz);
225 print_uint(PRINT_ANY, "confirmed", "/%u", ci->ndm_confirmed / hz);
7cd3f08b 226 print_uint(PRINT_ANY, "updated", "/%u", ci->ndm_updated / hz);
aac7f725
SH
227}
228
229static void print_neigh_state(unsigned int nud)
230{
231
232 open_json_array(PRINT_JSON,
233 is_json_context() ? "state" : "");
234
235#define PRINT_FLAG(f) \
236 if (nud & NUD_##f) { \
237 nud &= ~NUD_##f; \
238 print_string(PRINT_ANY, NULL, " %s", #f); \
239 }
240
241 PRINT_FLAG(INCOMPLETE);
242 PRINT_FLAG(REACHABLE);
243 PRINT_FLAG(STALE);
244 PRINT_FLAG(DELAY);
245 PRINT_FLAG(PROBE);
246 PRINT_FLAG(FAILED);
247 PRINT_FLAG(NOARP);
248 PRINT_FLAG(PERMANENT);
249#undef PRINT_FLAG
250
251 close_json_array(PRINT_JSON, NULL);
252}
aba5acdf 253
cd554f2c 254int print_neigh(struct nlmsghdr *n, void *arg)
aba5acdf 255{
56f5daac 256 FILE *fp = (FILE *)arg;
aba5acdf
SH
257 struct ndmsg *r = NLMSG_DATA(n);
258 int len = n->nlmsg_len;
56f5daac 259 struct rtattr *tb[NDA_MAX+1];
0d238ca2 260 static int logit = 1;
6b83edc0 261 __u8 protocol = 0;
aba5acdf 262
1556e29d
DS
263 if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
264 n->nlmsg_type != RTM_GETNEIGH) {
aba5acdf
SH
265 fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
266 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
ae665a52 267
aba5acdf
SH
268 return 0;
269 }
270 len -= NLMSG_LENGTH(sizeof(*r));
271 if (len < 0) {
272 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
273 return -1;
274 }
275
276 if (filter.flushb && n->nlmsg_type != RTM_NEWNEIGH)
277 return 0;
278
279 if (filter.family && filter.family != r->ndm_family)
280 return 0;
281 if (filter.index && filter.index != r->ndm_ifindex)
282 return 0;
283 if (!(filter.state&r->ndm_state) &&
1dac7817 284 !(r->ndm_flags & NTF_PROXY) &&
9c6a6d84 285 !(r->ndm_flags & NTF_EXT_LEARNED) &&
aba5acdf 286 (r->ndm_state || !(filter.state&0x100)) &&
aac7f725 287 (r->ndm_family != AF_DECnet))
aba5acdf
SH
288 return 0;
289
0d238ca2
DA
290 if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) {
291 if (logit) {
292 logit = 0;
293 fprintf(fp,
294 "\nWARNING: Kernel does not support filtering by master device\n\n");
295 }
296 }
297
aba5acdf
SH
298 parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
299
a4270fd8
SP
300 if (inet_addr_match_rta(&filter.pfx, tb[NDA_DST]))
301 return 0;
56f5daac 302
6b83edc0
DA
303 if (tb[NDA_PROTOCOL])
304 protocol = rta_getattr_u8(tb[NDA_PROTOCOL]);
305
306 if (filter.protocol && filter.protocol != protocol)
307 return 0;
308
aba5acdf
SH
309 if (filter.unused_only && tb[NDA_CACHEINFO]) {
310 struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
56f5daac 311
aba5acdf
SH
312 if (ci->ndm_refcnt)
313 return 0;
314 }
315
316 if (filter.flushb) {
317 struct nlmsghdr *fn;
56f5daac 318
aba5acdf
SH
319 if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
320 if (flush_update())
321 return -1;
322 }
56f5daac 323 fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp));
aba5acdf
SH
324 memcpy(fn, n, n->nlmsg_len);
325 fn->nlmsg_type = RTM_DELNEIGH;
326 fn->nlmsg_flags = NLM_F_REQUEST;
351efcde 327 fn->nlmsg_seq = ++rth.seq;
56f5daac 328 filter.flushp = (((char *)fn) + n->nlmsg_len) - filter.flushb;
aba5acdf
SH
329 filter.flushed++;
330 if (show_stats < 2)
331 return 0;
332 }
333
aac7f725 334 open_json_object(NULL);
6ea3ebaf 335 if (n->nlmsg_type == RTM_DELNEIGH)
aac7f725 336 print_bool(PRINT_ANY, "deleted", "Deleted ", true);
1556e29d 337 else if (n->nlmsg_type == RTM_GETNEIGH)
aac7f725
SH
338 print_null(PRINT_ANY, "miss", "%s ", "miss");
339
aba5acdf 340 if (tb[NDA_DST]) {
aac7f725 341 const char *dst;
c9159af5 342 int family = r->ndm_family;
aac7f725 343
c9159af5
TJ
344 if (family == AF_BRIDGE) {
345 if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
346 family = AF_INET6;
347 else
348 family = AF_INET;
349 }
350
351 dst = format_host_rta(family, tb[NDA_DST]);
aac7f725 352 print_color_string(PRINT_ANY,
c9159af5 353 ifa_family_color(family),
aac7f725 354 "dst", "%s ", dst);
aba5acdf 355 }
aac7f725
SH
356
357 if (!filter.index && r->ndm_ifindex) {
358 if (!is_json_context())
359 fprintf(fp, "dev ");
360
361 print_color_string(PRINT_ANY, COLOR_IFNAME,
362 "dev", "%s ",
363 ll_index_to_name(r->ndm_ifindex));
364 }
365
aba5acdf 366 if (tb[NDA_LLADDR]) {
aac7f725 367 const char *lladdr;
aba5acdf 368 SPRINT_BUF(b1);
6a34d291 369
aac7f725
SH
370 lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
371 RTA_PAYLOAD(tb[NDA_LLADDR]),
372 ll_index_to_type(r->ndm_ifindex),
373 b1, sizeof(b1));
aba5acdf 374
aac7f725
SH
375 if (!is_json_context())
376 fprintf(fp, "lladdr ");
56f5daac 377
aac7f725
SH
378 print_color_string(PRINT_ANY, COLOR_MAC,
379 "lladdr", "%s", lladdr);
69410a49 380 }
381
aac7f725
SH
382 if (r->ndm_flags & NTF_ROUTER)
383 print_null(PRINT_ANY, "router", " %s", "router");
384
385 if (r->ndm_flags & NTF_PROXY)
386 print_null(PRINT_ANY, "proxy", " %s", "proxy");
387
4c45b684
RP
388 if (r->ndm_flags & NTF_EXT_LEARNED)
389 print_null(PRINT_ANY, "extern_learn", " %s ", "extern_learn");
390
185ba5e2
IS
391 if (r->ndm_flags & NTF_OFFLOADED)
392 print_null(PRINT_ANY, "offload", " %s", "offload");
393
aac7f725
SH
394 if (show_stats) {
395 if (tb[NDA_CACHEINFO])
396 print_cacheinfo(RTA_DATA(tb[NDA_CACHEINFO]));
397
398 if (tb[NDA_PROBES])
399 print_uint(PRINT_ANY, "probes", " probes %u",
400 rta_getattr_u32(tb[NDA_PROBES]));
aba5acdf 401 }
aba5acdf 402
aac7f725
SH
403 if (r->ndm_state)
404 print_neigh_state(r->ndm_state);
405
6b83edc0
DA
406 if (protocol) {
407 SPRINT_BUF(b1);
408
409 print_string(PRINT_ANY, "protocol", " proto %s ",
410 rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
411 }
412
aac7f725
SH
413 print_string(PRINT_FP, NULL, "\n", "");
414 close_json_object();
415 fflush(stdout);
416
aba5acdf
SH
417 return 0;
418}
419
093b7646 420void ipneigh_reset_filter(int ifindex)
aba5acdf
SH
421{
422 memset(&filter, 0, sizeof(filter));
423 filter.state = ~0;
093b7646 424 filter.index = ifindex;
aba5acdf
SH
425}
426
101ec10a
DA
427static int ipneigh_dump_filter(struct nlmsghdr *nlh, int reqlen)
428{
429 struct ndmsg *ndm = NLMSG_DATA(nlh);
430 int err;
431
432 ndm->ndm_flags = filter.ndm_flags;
433
434 if (filter.index) {
435 err = addattr32(nlh, reqlen, NDA_IFINDEX, filter.index);
436 if (err)
437 return err;
438 }
439 if (filter.master) {
440 err = addattr32(nlh, reqlen, NDA_MASTER, filter.master);
441 if (err)
442 return err;
443 }
444
445 return 0;
446}
447
d1f28cf1 448static int do_show_or_flush(int argc, char **argv, int flush)
aba5acdf
SH
449{
450 char *filter_dev = NULL;
aba5acdf 451 int state_given = 0;
0d238ca2 452
093b7646 453 ipneigh_reset_filter(0);
aba5acdf
SH
454
455 if (!filter.family)
456 filter.family = preferred_family;
457
458 if (flush) {
459 if (argc <= 0) {
460 fprintf(stderr, "Flush requires arguments.\n");
461 return -1;
462 }
463 filter.state = ~(NUD_PERMANENT|NUD_NOARP);
464 } else
465 filter.state = 0xFF & ~NUD_NOARP;
466
467 while (argc > 0) {
468 if (strcmp(*argv, "dev") == 0) {
469 NEXT_ARG();
470 if (filter_dev)
471 duparg("dev", *argv);
472 filter_dev = *argv;
0d238ca2
DA
473 } else if (strcmp(*argv, "master") == 0) {
474 int ifindex;
56f5daac 475
0d238ca2
DA
476 NEXT_ARG();
477 ifindex = ll_name_to_index(*argv);
478 if (!ifindex)
479 invarg("Device does not exist\n", *argv);
0d238ca2 480 filter.master = ifindex;
5db1adae
DA
481 } else if (strcmp(*argv, "vrf") == 0) {
482 int ifindex;
483
484 NEXT_ARG();
485 ifindex = ll_name_to_index(*argv);
486 if (!ifindex)
487 invarg("Not a valid VRF name\n", *argv);
488 if (!name_is_vrf(*argv))
489 invarg("Not a valid VRF name\n", *argv);
5db1adae 490 filter.master = ifindex;
aba5acdf
SH
491 } else if (strcmp(*argv, "unused") == 0) {
492 filter.unused_only = 1;
493 } else if (strcmp(*argv, "nud") == 0) {
56f5daac
SH
494 unsigned int state;
495
aba5acdf
SH
496 NEXT_ARG();
497 if (!state_given) {
498 state_given = 1;
499 filter.state = 0;
500 }
501 if (nud_state_a2n(&state, *argv)) {
502 if (strcmp(*argv, "all") != 0)
503 invarg("nud state is bad", *argv);
504 state = ~0;
505 if (flush)
506 state &= ~NUD_NOARP;
507 }
508 if (state == 0)
509 state = 0x100;
510 filter.state |= state;
6b83edc0 511 } else if (strcmp(*argv, "proxy") == 0) {
101ec10a 512 filter.ndm_flags = NTF_PROXY;
6b83edc0
DA
513 } else if (matches(*argv, "protocol") == 0) {
514 __u32 prot;
515
516 NEXT_ARG();
517 if (rtnl_rtprot_a2n(&prot, *argv)) {
518 if (strcmp(*argv, "all"))
519 invarg("invalid \"protocol\"\n", *argv);
520 prot = 0;
521 }
522 filter.protocol = prot;
523 } else {
aba5acdf
SH
524 if (strcmp(*argv, "to") == 0) {
525 NEXT_ARG();
526 }
527 if (matches(*argv, "help") == 0)
528 usage();
a4270fd8
SP
529 if (get_prefix(&filter.pfx, *argv, filter.family))
530 invarg("to value is invalid\n", *argv);
aba5acdf
SH
531 if (filter.family == AF_UNSPEC)
532 filter.family = filter.pfx.family;
533 }
534 argc--; argv++;
535 }
536
aba5acdf
SH
537 ll_init_map(&rth);
538
539 if (filter_dev) {
fe99adbc
SP
540 filter.index = ll_name_to_index(filter_dev);
541 if (!filter.index)
542 return nodev(filter_dev);
aba5acdf
SH
543 }
544
545 if (flush) {
546 int round = 0;
547 char flushb[4096-512];
548
549 filter.flushb = flushb;
550 filter.flushp = 0;
551 filter.flushe = sizeof(flushb);
aba5acdf 552
66081849 553 while (round < MAX_ROUNDS) {
101ec10a
DA
554 if (rtnl_neighdump_req(&rth, filter.family,
555 ipneigh_dump_filter) < 0) {
aba5acdf
SH
556 perror("Cannot send dump request");
557 exit(1);
558 }
559 filter.flushed = 0;
cd70f3f5 560 if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
aba5acdf
SH
561 fprintf(stderr, "Flush terminated\n");
562 exit(1);
563 }
564 if (filter.flushed == 0) {
f0b34d2d
AH
565 if (show_stats) {
566 if (round == 0)
567 printf("Nothing to flush.\n");
568 else
56f5daac 569 printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":"");
f0b34d2d 570 }
aba5acdf
SH
571 fflush(stdout);
572 return 0;
573 }
574 round++;
575 if (flush_update() < 0)
576 exit(1);
577 if (show_stats) {
578 printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
579 fflush(stdout);
580 }
ad0a6a2c 581 filter.state &= ~NUD_FAILED;
aba5acdf 582 }
66081849
SH
583 printf("*** Flush not complete bailing out after %d rounds\n",
584 MAX_ROUNDS);
585 return 1;
aba5acdf
SH
586 }
587
101ec10a 588 if (rtnl_neighdump_req(&rth, filter.family, ipneigh_dump_filter) < 0) {
aba5acdf
SH
589 perror("Cannot send dump request");
590 exit(1);
591 }
592
aac7f725 593 new_json_obj(json);
cd70f3f5 594 if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
aba5acdf
SH
595 fprintf(stderr, "Dump terminated\n");
596 exit(1);
597 }
aac7f725 598 delete_json_obj();
aba5acdf
SH
599
600 return 0;
601}
602
62842362
RP
603static int ipneigh_get(int argc, char **argv)
604{
605 struct {
606 struct nlmsghdr n;
607 struct ndmsg ndm;
608 char buf[1024];
609 } req = {
610 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
611 .n.nlmsg_flags = NLM_F_REQUEST,
612 .n.nlmsg_type = RTM_GETNEIGH,
613 .ndm.ndm_family = preferred_family,
614 };
615 struct nlmsghdr *answer;
616 char *d = NULL;
617 int dst_ok = 0;
618 int dev_ok = 0;
619 inet_prefix dst;
620
621 while (argc > 0) {
622 if (strcmp(*argv, "dev") == 0) {
623 NEXT_ARG();
624 d = *argv;
625 dev_ok = 1;
626 } else if (matches(*argv, "proxy") == 0) {
627 NEXT_ARG();
628 if (matches(*argv, "help") == 0)
629 usage();
630 if (dst_ok)
631 duparg("address", *argv);
632 get_addr(&dst, *argv, preferred_family);
633 dst_ok = 1;
634 dev_ok = 1;
635 req.ndm.ndm_flags |= NTF_PROXY;
636 } else {
637 if (strcmp(*argv, "to") == 0)
638 NEXT_ARG();
639
640 if (matches(*argv, "help") == 0)
641 usage();
642 if (dst_ok)
643 duparg2("to", *argv);
644 get_addr(&dst, *argv, preferred_family);
645 dst_ok = 1;
646 }
647 argc--; argv++;
648 }
649
650 if (!dev_ok || !dst_ok || dst.family == AF_UNSPEC) {
651 fprintf(stderr, "Device and address are required arguments.\n");
652 return -1;
653 }
654
655 req.ndm.ndm_family = dst.family;
656 if (addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen) < 0)
657 return -1;
658
659 if (d) {
660 req.ndm.ndm_ifindex = ll_name_to_index(d);
661 if (!req.ndm.ndm_ifindex) {
662 fprintf(stderr, "Cannot find device \"%s\"\n", d);
663 return -1;
664 }
665 }
666
667 if (rtnl_talk(&rth, &req.n, &answer) < 0)
668 return -2;
669
670 ipneigh_reset_filter(0);
671 if (print_neigh(answer, stdout) < 0) {
672 fprintf(stderr, "An error :-)\n");
673 return -1;
674 }
675
676 return 0;
677}
678
aba5acdf
SH
679int do_ipneigh(int argc, char **argv)
680{
681 if (argc > 0) {
682 if (matches(*argv, "add") == 0)
683 return ipneigh_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
684 if (matches(*argv, "change") == 0 ||
685 strcmp(*argv, "chg") == 0)
686 return ipneigh_modify(RTM_NEWNEIGH, NLM_F_REPLACE, argc-1, argv+1);
687 if (matches(*argv, "replace") == 0)
688 return ipneigh_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
689 if (matches(*argv, "delete") == 0)
690 return ipneigh_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
62842362
RP
691 if (matches(*argv, "get") == 0)
692 return ipneigh_get(argc-1, argv+1);
aba5acdf
SH
693 if (matches(*argv, "show") == 0 ||
694 matches(*argv, "lst") == 0 ||
695 matches(*argv, "list") == 0)
696 return do_show_or_flush(argc-1, argv+1, 0);
697 if (matches(*argv, "flush") == 0)
698 return do_show_or_flush(argc-1, argv+1, 1);
699 if (matches(*argv, "help") == 0)
700 usage();
701 } else
702 return do_show_or_flush(0, NULL, 0);
703
704 fprintf(stderr, "Command \"%s\" is unknown, try \"ip neigh help\".\n", *argv);
705 exit(-1);
706}