2 * Copyright (C)2006 USAGI/WIDE Project
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses>.
22 * Masahide NAKAMURA @USAGI
29 #include <sys/socket.h>
33 #include "ip_common.h"
43 static void usage(void) __attribute__((noreturn
));
45 static void usage(void)
48 "Usage: ip ntable change name NAME [ dev DEV ]\n"
49 " [ thresh1 VAL ] [ thresh2 VAL ] [ thresh3 VAL ] [ gc_int MSEC ]\n"
51 "Usage: ip ntable show [ dev DEV ] [ name NAME ]\n"
53 "PARMS := [ base_reachable MSEC ] [ retrans MSEC ] [ gc_stale MSEC ]\n"
54 " [ delay_probe MSEC ] [ queue LEN ]\n"
55 " [ app_probs VAL ] [ ucast_probes VAL ] [ mcast_probes VAL ]\n"
56 " [ anycast_delay MSEC ] [ proxy_delay MSEC ] [ proxy_queue LEN ]\n"
57 " [ locktime MSEC ]\n"
63 static int ipntable_modify(int cmd
, int flags
, int argc
, char **argv
)
71 char *threshsp
= NULL
;
74 struct rtattr
*parms_rta
= (struct rtattr
*)parms_buf
;
77 memset(&req
, 0, sizeof(req
));
79 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndtmsg
));
80 req
.n
.nlmsg_flags
= NLM_F_REQUEST
|flags
;
81 req
.n
.nlmsg_type
= cmd
;
83 req
.ndtm
.ndtm_family
= preferred_family
;
84 req
.ndtm
.ndtm_pad1
= 0;
85 req
.ndtm
.ndtm_pad2
= 0;
87 memset(&parms_buf
, 0, sizeof(parms_buf
));
89 parms_rta
->rta_type
= NDTA_PARMS
;
90 parms_rta
->rta_len
= RTA_LENGTH(0);
93 if (strcmp(*argv
, "name") == 0) {
98 duparg("NAME", *argv
);
101 len
= strlen(namep
) + 1;
102 addattr_l(&req
.n
, sizeof(req
), NDTA_NAME
, namep
, len
);
103 } else if (strcmp(*argv
, "thresh1") == 0) {
109 if (get_u32(&thresh1
, *argv
, 0))
110 invarg("\"thresh1\" value is invalid", *argv
);
112 addattr32(&req
.n
, sizeof(req
), NDTA_THRESH1
, thresh1
);
113 } else if (strcmp(*argv
, "thresh2") == 0) {
119 if (get_u32(&thresh2
, *argv
, 0))
120 invarg("\"thresh2\" value is invalid", *argv
);
122 addattr32(&req
.n
, sizeof(req
), NDTA_THRESH2
, thresh2
);
123 } else if (strcmp(*argv
, "thresh3") == 0) {
129 if (get_u32(&thresh3
, *argv
, 0))
130 invarg("\"thresh3\" value is invalid", *argv
);
132 addattr32(&req
.n
, sizeof(req
), NDTA_THRESH3
, thresh3
);
133 } else if (strcmp(*argv
, "gc_int") == 0) {
139 if (get_u64(&gc_int
, *argv
, 0))
140 invarg("\"gc_int\" value is invalid", *argv
);
142 addattr_l(&req
.n
, sizeof(req
), NDTA_GC_INTERVAL
,
143 &gc_int
, sizeof(gc_int
));
144 } else if (strcmp(*argv
, "dev") == 0) {
148 ifindex
= ll_name_to_index(*argv
);
150 fprintf(stderr
, "Cannot find device \"%s\"\n", *argv
);
154 rta_addattr32(parms_rta
, sizeof(parms_buf
),
155 NDTPA_IFINDEX
, ifindex
);
156 } else if (strcmp(*argv
, "base_reachable") == 0) {
161 if (get_u64(&breachable
, *argv
, 0))
162 invarg("\"base_reachable\" value is invalid", *argv
);
164 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
165 NDTPA_BASE_REACHABLE_TIME
,
166 &breachable
, sizeof(breachable
));
168 } else if (strcmp(*argv
, "retrans") == 0) {
173 if (get_u64(&retrans
, *argv
, 0))
174 invarg("\"retrans\" value is invalid", *argv
);
176 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
178 &retrans
, sizeof(retrans
));
180 } else if (strcmp(*argv
, "gc_stale") == 0) {
185 if (get_u64(&gc_stale
, *argv
, 0))
186 invarg("\"gc_stale\" value is invalid", *argv
);
188 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
190 &gc_stale
, sizeof(gc_stale
));
192 } else if (strcmp(*argv
, "delay_probe") == 0) {
197 if (get_u64(&delay_probe
, *argv
, 0))
198 invarg("\"delay_probe\" value is invalid", *argv
);
200 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
201 NDTPA_DELAY_PROBE_TIME
,
202 &delay_probe
, sizeof(delay_probe
));
204 } else if (strcmp(*argv
, "queue") == 0) {
209 if (get_u32(&queue
, *argv
, 0))
210 invarg("\"queue\" value is invalid", *argv
);
213 parms_rta
= (struct rtattr
*)&parms_buf
;
214 rta_addattr32(parms_rta
, sizeof(parms_buf
),
215 NDTPA_QUEUE_LEN
, queue
);
217 } else if (strcmp(*argv
, "app_probes") == 0) {
222 if (get_u32(&aprobe
, *argv
, 0))
223 invarg("\"app_probes\" value is invalid", *argv
);
225 rta_addattr32(parms_rta
, sizeof(parms_buf
),
226 NDTPA_APP_PROBES
, aprobe
);
228 } else if (strcmp(*argv
, "ucast_probes") == 0) {
233 if (get_u32(&uprobe
, *argv
, 0))
234 invarg("\"ucast_probes\" value is invalid", *argv
);
236 rta_addattr32(parms_rta
, sizeof(parms_buf
),
237 NDTPA_UCAST_PROBES
, uprobe
);
239 } else if (strcmp(*argv
, "mcast_probes") == 0) {
244 if (get_u32(&mprobe
, *argv
, 0))
245 invarg("\"mcast_probes\" value is invalid", *argv
);
247 rta_addattr32(parms_rta
, sizeof(parms_buf
),
248 NDTPA_MCAST_PROBES
, mprobe
);
250 } else if (strcmp(*argv
, "anycast_delay") == 0) {
255 if (get_u64(&anycast_delay
, *argv
, 0))
256 invarg("\"anycast_delay\" value is invalid", *argv
);
258 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
260 &anycast_delay
, sizeof(anycast_delay
));
262 } else if (strcmp(*argv
, "proxy_delay") == 0) {
267 if (get_u64(&proxy_delay
, *argv
, 0))
268 invarg("\"proxy_delay\" value is invalid", *argv
);
270 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
272 &proxy_delay
, sizeof(proxy_delay
));
274 } else if (strcmp(*argv
, "proxy_queue") == 0) {
279 if (get_u32(&pqueue
, *argv
, 0))
280 invarg("\"proxy_queue\" value is invalid", *argv
);
282 rta_addattr32(parms_rta
, sizeof(parms_buf
),
283 NDTPA_PROXY_QLEN
, pqueue
);
285 } else if (strcmp(*argv
, "locktime") == 0) {
290 if (get_u64(&locktime
, *argv
, 0))
291 invarg("\"locktime\" value is invalid", *argv
);
293 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
295 &locktime
, sizeof(locktime
));
298 invarg("unknown", *argv
);
306 if (!threshsp
&& !gc_intp
&& !parms_change
) {
307 fprintf(stderr
, "Not enough information: changeable attributes required.\n");
311 if (parms_rta
->rta_len
> RTA_LENGTH(0)) {
312 addattr_l(&req
.n
, sizeof(req
), NDTA_PARMS
, RTA_DATA(parms_rta
),
313 RTA_PAYLOAD(parms_rta
));
316 if (rtnl_talk(&rth
, &req
.n
, 0, 0, NULL
) < 0)
322 static const char *ntable_strtime_delta(__u32 msec
)
332 memset(&now
, 0, sizeof(now
));
334 if (gettimeofday(&now
, NULL
) < 0) {
335 perror("gettimeofday");
339 t
= now
.tv_sec
- (msec
/ 1000);
344 strftime(str
, sizeof(str
), "%Y-%m-%d %T", tp
);
348 strcpy(str
, "(error)");
352 int print_ntable(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
, void *arg
)
354 FILE *fp
= (FILE*)arg
;
355 struct ndtmsg
*ndtm
= NLMSG_DATA(n
);
356 int len
= n
->nlmsg_len
;
357 struct rtattr
*tb
[NDTA_MAX
+1];
358 struct rtattr
*tpb
[NDTPA_MAX
+1];
361 if (n
->nlmsg_type
!= RTM_NEWNEIGHTBL
) {
362 fprintf(stderr
, "Not NEIGHTBL: %08x %08x %08x\n",
363 n
->nlmsg_len
, n
->nlmsg_type
, n
->nlmsg_flags
);
366 len
-= NLMSG_LENGTH(sizeof(*ndtm
));
368 fprintf(stderr
, "BUG: wrong nlmsg len %d\n", len
);
372 if (preferred_family
&& preferred_family
!= ndtm
->ndtm_family
)
375 parse_rtattr(tb
, NDTA_MAX
, NDTA_RTA(ndtm
),
376 n
->nlmsg_len
- NLMSG_LENGTH(sizeof(*ndtm
)));
379 const char *name
= rta_getattr_str(tb
[NDTA_NAME
]);
381 if (strlen(filter
.name
) > 0 && strcmp(filter
.name
, name
))
384 if (tb
[NDTA_PARMS
]) {
385 parse_rtattr(tpb
, NDTPA_MAX
, RTA_DATA(tb
[NDTA_PARMS
]),
386 RTA_PAYLOAD(tb
[NDTA_PARMS
]));
388 if (tpb
[NDTPA_IFINDEX
]) {
389 __u32 ifindex
= rta_getattr_u32(tpb
[NDTPA_IFINDEX
]);
391 if (filter
.index
&& filter
.index
!= ifindex
)
394 if (filter
.index
&& filter
.index
!= NONE_DEV
)
399 if (ndtm
->ndtm_family
== AF_INET
)
400 fprintf(fp
, "inet ");
401 else if (ndtm
->ndtm_family
== AF_INET6
)
402 fprintf(fp
, "inet6 ");
403 else if (ndtm
->ndtm_family
== AF_DECnet
)
404 fprintf(fp
, "dnet ");
406 fprintf(fp
, "(%d) ", ndtm
->ndtm_family
);
409 const char *name
= rta_getattr_str(tb
[NDTA_NAME
]);
410 fprintf(fp
, "%s ", name
);
413 fprintf(fp
, "%s", _SL_
);
415 ret
= (tb
[NDTA_THRESH1
] || tb
[NDTA_THRESH2
] || tb
[NDTA_THRESH3
] ||
416 tb
[NDTA_GC_INTERVAL
]);
420 if (tb
[NDTA_THRESH1
]) {
421 __u32 thresh1
= rta_getattr_u32(tb
[NDTA_THRESH1
]);
422 fprintf(fp
, "thresh1 %u ", thresh1
);
424 if (tb
[NDTA_THRESH2
]) {
425 __u32 thresh2
= rta_getattr_u32(tb
[NDTA_THRESH2
]);
426 fprintf(fp
, "thresh2 %u ", thresh2
);
428 if (tb
[NDTA_THRESH3
]) {
429 __u32 thresh3
= rta_getattr_u32(tb
[NDTA_THRESH3
]);
430 fprintf(fp
, "thresh3 %u ", thresh3
);
432 if (tb
[NDTA_GC_INTERVAL
]) {
433 unsigned long long gc_int
= rta_getattr_u64(tb
[NDTA_GC_INTERVAL
]);
434 fprintf(fp
, "gc_int %llu ", gc_int
);
438 fprintf(fp
, "%s", _SL_
);
440 if (tb
[NDTA_CONFIG
] && show_stats
) {
441 struct ndt_config
*ndtc
= RTA_DATA(tb
[NDTA_CONFIG
]);
444 fprintf(fp
, "config ");
446 fprintf(fp
, "key_len %u ", ndtc
->ndtc_key_len
);
447 fprintf(fp
, "entry_size %u ", ndtc
->ndtc_entry_size
);
448 fprintf(fp
, "entries %u ", ndtc
->ndtc_entries
);
450 fprintf(fp
, "%s", _SL_
);
453 fprintf(fp
, "last_flush %s ",
454 ntable_strtime_delta(ndtc
->ndtc_last_flush
));
455 fprintf(fp
, "last_rand %s ",
456 ntable_strtime_delta(ndtc
->ndtc_last_rand
));
458 fprintf(fp
, "%s", _SL_
);
461 fprintf(fp
, "hash_rnd %u ", ndtc
->ndtc_hash_rnd
);
462 fprintf(fp
, "hash_mask %08x ", ndtc
->ndtc_hash_mask
);
464 fprintf(fp
, "hash_chain_gc %u ", ndtc
->ndtc_hash_chain_gc
);
465 fprintf(fp
, "proxy_qlen %u ", ndtc
->ndtc_proxy_qlen
);
467 fprintf(fp
, "%s", _SL_
);
470 if (tb
[NDTA_PARMS
]) {
471 if (tpb
[NDTPA_IFINDEX
]) {
472 __u32 ifindex
= rta_getattr_u32(tpb
[NDTPA_IFINDEX
]);
475 fprintf(fp
, "dev %s ", ll_index_to_name(ifindex
));
476 fprintf(fp
, "%s", _SL_
);
481 if (tpb
[NDTPA_REFCNT
]) {
482 __u32 refcnt
= rta_getattr_u32(tpb
[NDTPA_REFCNT
]);
483 fprintf(fp
, "refcnt %u ", refcnt
);
485 if (tpb
[NDTPA_REACHABLE_TIME
]) {
486 unsigned long long reachable
= rta_getattr_u64(tpb
[NDTPA_REACHABLE_TIME
]);
487 fprintf(fp
, "reachable %llu ", reachable
);
489 if (tpb
[NDTPA_BASE_REACHABLE_TIME
]) {
490 unsigned long long breachable
= rta_getattr_u64(tpb
[NDTPA_BASE_REACHABLE_TIME
]);
491 fprintf(fp
, "base_reachable %llu ", breachable
);
493 if (tpb
[NDTPA_RETRANS_TIME
]) {
494 unsigned long long retrans
= rta_getattr_u64(tpb
[NDTPA_RETRANS_TIME
]);
495 fprintf(fp
, "retrans %llu ", retrans
);
498 fprintf(fp
, "%s", _SL_
);
502 if (tpb
[NDTPA_GC_STALETIME
]) {
503 unsigned long long gc_stale
= rta_getattr_u64(tpb
[NDTPA_GC_STALETIME
]);
504 fprintf(fp
, "gc_stale %llu ", gc_stale
);
506 if (tpb
[NDTPA_DELAY_PROBE_TIME
]) {
507 unsigned long long delay_probe
= rta_getattr_u64(tpb
[NDTPA_DELAY_PROBE_TIME
]);
508 fprintf(fp
, "delay_probe %llu ", delay_probe
);
510 if (tpb
[NDTPA_QUEUE_LEN
]) {
511 __u32 queue
= rta_getattr_u32(tpb
[NDTPA_QUEUE_LEN
]);
512 fprintf(fp
, "queue %u ", queue
);
515 fprintf(fp
, "%s", _SL_
);
519 if (tpb
[NDTPA_APP_PROBES
]) {
520 __u32 aprobe
= rta_getattr_u32(tpb
[NDTPA_APP_PROBES
]);
521 fprintf(fp
, "app_probes %u ", aprobe
);
523 if (tpb
[NDTPA_UCAST_PROBES
]) {
524 __u32 uprobe
= rta_getattr_u32(tpb
[NDTPA_UCAST_PROBES
]);
525 fprintf(fp
, "ucast_probes %u ", uprobe
);
527 if (tpb
[NDTPA_MCAST_PROBES
]) {
528 __u32 mprobe
= rta_getattr_u32(tpb
[NDTPA_MCAST_PROBES
]);
529 fprintf(fp
, "mcast_probes %u ", mprobe
);
532 fprintf(fp
, "%s", _SL_
);
536 if (tpb
[NDTPA_ANYCAST_DELAY
]) {
537 unsigned long long anycast_delay
= rta_getattr_u64(tpb
[NDTPA_ANYCAST_DELAY
]);
538 fprintf(fp
, "anycast_delay %llu ", anycast_delay
);
540 if (tpb
[NDTPA_PROXY_DELAY
]) {
541 unsigned long long proxy_delay
= rta_getattr_u64(tpb
[NDTPA_PROXY_DELAY
]);
542 fprintf(fp
, "proxy_delay %llu ", proxy_delay
);
544 if (tpb
[NDTPA_PROXY_QLEN
]) {
545 __u32 pqueue
= rta_getattr_u32(tpb
[NDTPA_PROXY_QLEN
]);
546 fprintf(fp
, "proxy_queue %u ", pqueue
);
548 if (tpb
[NDTPA_LOCKTIME
]) {
549 unsigned long long locktime
= rta_getattr_u64(tpb
[NDTPA_LOCKTIME
]);
550 fprintf(fp
, "locktime %llu ", locktime
);
553 fprintf(fp
, "%s", _SL_
);
556 if (tb
[NDTA_STATS
] && show_stats
) {
557 struct ndt_stats
*ndts
= RTA_DATA(tb
[NDTA_STATS
]);
560 fprintf(fp
, "stats ");
562 fprintf(fp
, "allocs %llu ",
563 (unsigned long long) ndts
->ndts_allocs
);
564 fprintf(fp
, "destroys %llu ",
565 (unsigned long long) ndts
->ndts_destroys
);
566 fprintf(fp
, "hash_grows %llu ",
567 (unsigned long long) ndts
->ndts_hash_grows
);
569 fprintf(fp
, "%s", _SL_
);
572 fprintf(fp
, "res_failed %llu ",
573 (unsigned long long) ndts
->ndts_res_failed
);
574 fprintf(fp
, "lookups %llu ",
575 (unsigned long long) ndts
->ndts_lookups
);
576 fprintf(fp
, "hits %llu ",
577 (unsigned long long) ndts
->ndts_hits
);
579 fprintf(fp
, "%s", _SL_
);
582 fprintf(fp
, "rcv_probes_mcast %llu ",
583 (unsigned long long) ndts
->ndts_rcv_probes_mcast
);
584 fprintf(fp
, "rcv_probes_ucast %llu ",
585 (unsigned long long) ndts
->ndts_rcv_probes_ucast
);
587 fprintf(fp
, "%s", _SL_
);
590 fprintf(fp
, "periodic_gc_runs %llu ",
591 (unsigned long long) ndts
->ndts_periodic_gc_runs
);
592 fprintf(fp
, "forced_gc_runs %llu ",
593 (unsigned long long) ndts
->ndts_forced_gc_runs
);
595 fprintf(fp
, "%s", _SL_
);
604 void ipntable_reset_filter(void)
606 memset(&filter
, 0, sizeof(filter
));
609 static int ipntable_show(int argc
, char **argv
)
611 ipntable_reset_filter();
613 filter
.family
= preferred_family
;
616 if (strcmp(*argv
, "dev") == 0) {
619 if (strcmp("none", *argv
) == 0)
620 filter
.index
= NONE_DEV
;
621 else if ((filter
.index
= ll_name_to_index(*argv
)) == 0)
622 invarg("\"DEV\" is invalid", *argv
);
623 } else if (strcmp(*argv
, "name") == 0) {
626 strncpy(filter
.name
, *argv
, sizeof(filter
.name
));
628 invarg("unknown", *argv
);
633 if (rtnl_wilddump_request(&rth
, preferred_family
, RTM_GETNEIGHTBL
) < 0) {
634 perror("Cannot send dump request");
638 if (rtnl_dump_filter(&rth
, print_ntable
, stdout
) < 0) {
639 fprintf(stderr
, "Dump terminated\n");
646 int do_ipntable(int argc
, char **argv
)
651 if (matches(*argv
, "change") == 0 ||
652 matches(*argv
, "chg") == 0)
653 return ipntable_modify(RTM_SETNEIGHTBL
,
656 if (matches(*argv
, "show") == 0 ||
657 matches(*argv
, "lst") == 0 ||
658 matches(*argv
, "list") == 0)
659 return ipntable_show(argc
-1, argv
+1);
660 if (matches(*argv
, "help") == 0)
663 return ipntable_show(0, NULL
);
665 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip ntable help\".\n", *argv
);