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"
34 #include "json_print.h"
44 static void usage(void) __attribute__((noreturn
));
46 static void usage(void)
49 "Usage: ip ntable change name NAME [ dev DEV ]\n"
50 " [ thresh1 VAL ] [ thresh2 VAL ] [ thresh3 VAL ] [ gc_int MSEC ]\n"
52 "Usage: ip ntable show [ dev DEV ] [ name NAME ]\n"
54 "PARMS := [ base_reachable MSEC ] [ retrans MSEC ] [ gc_stale MSEC ]\n"
55 " [ delay_probe MSEC ] [ queue LEN ]\n"
56 " [ app_probes VAL ] [ ucast_probes VAL ] [ mcast_probes VAL ]\n"
57 " [ anycast_delay MSEC ] [ proxy_delay MSEC ] [ proxy_queue LEN ]\n"
58 " [ locktime MSEC ]\n"
64 static int ipntable_modify(int cmd
, int flags
, int argc
, char **argv
)
71 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndtmsg
)),
72 .n
.nlmsg_flags
= NLM_F_REQUEST
| flags
,
74 .ndtm
.ndtm_family
= preferred_family
,
77 char *threshsp
= NULL
;
79 char parms_buf
[1024] = {};
80 struct rtattr
*parms_rta
= (struct rtattr
*)parms_buf
;
83 parms_rta
->rta_type
= NDTA_PARMS
;
84 parms_rta
->rta_len
= RTA_LENGTH(0);
87 if (strcmp(*argv
, "name") == 0) {
92 duparg("NAME", *argv
);
95 len
= strlen(namep
) + 1;
96 addattr_l(&req
.n
, sizeof(req
), NDTA_NAME
, namep
, len
);
97 } else if (strcmp(*argv
, "thresh1") == 0) {
103 if (get_u32(&thresh1
, *argv
, 0))
104 invarg("\"thresh1\" value is invalid", *argv
);
106 addattr32(&req
.n
, sizeof(req
), NDTA_THRESH1
, thresh1
);
107 } else if (strcmp(*argv
, "thresh2") == 0) {
113 if (get_u32(&thresh2
, *argv
, 0))
114 invarg("\"thresh2\" value is invalid", *argv
);
116 addattr32(&req
.n
, sizeof(req
), NDTA_THRESH2
, thresh2
);
117 } else if (strcmp(*argv
, "thresh3") == 0) {
123 if (get_u32(&thresh3
, *argv
, 0))
124 invarg("\"thresh3\" value is invalid", *argv
);
126 addattr32(&req
.n
, sizeof(req
), NDTA_THRESH3
, thresh3
);
127 } else if (strcmp(*argv
, "gc_int") == 0) {
133 if (get_u64(&gc_int
, *argv
, 0))
134 invarg("\"gc_int\" value is invalid", *argv
);
136 addattr_l(&req
.n
, sizeof(req
), NDTA_GC_INTERVAL
,
137 &gc_int
, sizeof(gc_int
));
138 } else if (strcmp(*argv
, "dev") == 0) {
142 ifindex
= ll_name_to_index(*argv
);
146 rta_addattr32(parms_rta
, sizeof(parms_buf
),
147 NDTPA_IFINDEX
, ifindex
);
148 } else if (strcmp(*argv
, "base_reachable") == 0) {
153 if (get_u64(&breachable
, *argv
, 0))
154 invarg("\"base_reachable\" value is invalid", *argv
);
156 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
157 NDTPA_BASE_REACHABLE_TIME
,
158 &breachable
, sizeof(breachable
));
160 } else if (strcmp(*argv
, "retrans") == 0) {
165 if (get_u64(&retrans
, *argv
, 0))
166 invarg("\"retrans\" value is invalid", *argv
);
168 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
170 &retrans
, sizeof(retrans
));
172 } else if (strcmp(*argv
, "gc_stale") == 0) {
177 if (get_u64(&gc_stale
, *argv
, 0))
178 invarg("\"gc_stale\" value is invalid", *argv
);
180 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
182 &gc_stale
, sizeof(gc_stale
));
184 } else if (strcmp(*argv
, "delay_probe") == 0) {
189 if (get_u64(&delay_probe
, *argv
, 0))
190 invarg("\"delay_probe\" value is invalid", *argv
);
192 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
193 NDTPA_DELAY_PROBE_TIME
,
194 &delay_probe
, sizeof(delay_probe
));
196 } else if (strcmp(*argv
, "queue") == 0) {
201 if (get_u32(&queue
, *argv
, 0))
202 invarg("\"queue\" value is invalid", *argv
);
204 rta_addattr32(parms_rta
, sizeof(parms_buf
),
205 NDTPA_QUEUE_LEN
, queue
);
207 } else if (strcmp(*argv
, "app_probes") == 0) {
212 if (get_u32(&aprobe
, *argv
, 0))
213 invarg("\"app_probes\" value is invalid", *argv
);
215 rta_addattr32(parms_rta
, sizeof(parms_buf
),
216 NDTPA_APP_PROBES
, aprobe
);
218 } else if (strcmp(*argv
, "ucast_probes") == 0) {
223 if (get_u32(&uprobe
, *argv
, 0))
224 invarg("\"ucast_probes\" value is invalid", *argv
);
226 rta_addattr32(parms_rta
, sizeof(parms_buf
),
227 NDTPA_UCAST_PROBES
, uprobe
);
229 } else if (strcmp(*argv
, "mcast_probes") == 0) {
234 if (get_u32(&mprobe
, *argv
, 0))
235 invarg("\"mcast_probes\" value is invalid", *argv
);
237 rta_addattr32(parms_rta
, sizeof(parms_buf
),
238 NDTPA_MCAST_PROBES
, mprobe
);
240 } else if (strcmp(*argv
, "anycast_delay") == 0) {
245 if (get_u64(&anycast_delay
, *argv
, 0))
246 invarg("\"anycast_delay\" value is invalid", *argv
);
248 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
250 &anycast_delay
, sizeof(anycast_delay
));
252 } else if (strcmp(*argv
, "proxy_delay") == 0) {
257 if (get_u64(&proxy_delay
, *argv
, 0))
258 invarg("\"proxy_delay\" value is invalid", *argv
);
260 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
262 &proxy_delay
, sizeof(proxy_delay
));
264 } else if (strcmp(*argv
, "proxy_queue") == 0) {
269 if (get_u32(&pqueue
, *argv
, 0))
270 invarg("\"proxy_queue\" value is invalid", *argv
);
272 rta_addattr32(parms_rta
, sizeof(parms_buf
),
273 NDTPA_PROXY_QLEN
, pqueue
);
275 } else if (strcmp(*argv
, "locktime") == 0) {
280 if (get_u64(&locktime
, *argv
, 0))
281 invarg("\"locktime\" value is invalid", *argv
);
283 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
285 &locktime
, sizeof(locktime
));
288 invarg("unknown", *argv
);
296 if (!threshsp
&& !gc_intp
&& !parms_change
) {
297 fprintf(stderr
, "Not enough information: changeable attributes required.\n");
301 if (parms_rta
->rta_len
> RTA_LENGTH(0)) {
302 addattr_l(&req
.n
, sizeof(req
), NDTA_PARMS
, RTA_DATA(parms_rta
),
303 RTA_PAYLOAD(parms_rta
));
306 if (rtnl_talk(&rth
, &req
.n
, NULL
) < 0)
312 static const char *ntable_strtime_delta(__u32 msec
)
315 struct timeval now
= {};
322 if (gettimeofday(&now
, NULL
) < 0) {
323 perror("gettimeofday");
327 t
= now
.tv_sec
- (msec
/ 1000);
332 strftime(str
, sizeof(str
), "%Y-%m-%d %T", tp
);
336 strcpy(str
, "(error)");
340 static void print_ndtconfig(const struct ndt_config
*ndtc
)
343 print_uint(PRINT_ANY
, "key_length",
344 " config key_len %u ", ndtc
->ndtc_key_len
);
345 print_uint(PRINT_ANY
, "entry_size",
346 "entry_size %u ", ndtc
->ndtc_entry_size
);
347 print_uint(PRINT_ANY
, "entries", "entries %u ", ndtc
->ndtc_entries
);
351 print_string(PRINT_ANY
, "last_flush",
353 ntable_strtime_delta(ndtc
->ndtc_last_flush
));
354 print_string(PRINT_ANY
, "last_rand",
356 ntable_strtime_delta(ndtc
->ndtc_last_rand
));
360 print_uint(PRINT_ANY
, "hash_rnd",
361 " hash_rnd %u ", ndtc
->ndtc_hash_rnd
);
362 print_0xhex(PRINT_ANY
, "hash_mask",
363 "hash_mask %08x ", ndtc
->ndtc_hash_mask
);
365 print_uint(PRINT_ANY
, "hash_chain_gc",
366 "hash_chain_gc %u ", ndtc
->ndtc_hash_chain_gc
);
367 print_uint(PRINT_ANY
, "proxy_qlen",
368 "proxy_qlen %u ", ndtc
->ndtc_proxy_qlen
);
373 static void print_ndtparams(struct rtattr
*tpb
[])
376 if (tpb
[NDTPA_IFINDEX
]) {
377 __u32 ifindex
= rta_getattr_u32(tpb
[NDTPA_IFINDEX
]);
379 print_string(PRINT_FP
, NULL
, " dev ", NULL
);
380 print_color_string(PRINT_ANY
, COLOR_IFNAME
,
381 "dev", "%s ", ll_index_to_name(ifindex
));
385 print_string(PRINT_FP
, NULL
, " ", NULL
);
386 if (tpb
[NDTPA_REFCNT
]) {
387 __u32 refcnt
= rta_getattr_u32(tpb
[NDTPA_REFCNT
]);
389 print_uint(PRINT_ANY
, "refcnt", "refcnt %u ", refcnt
);
392 if (tpb
[NDTPA_REACHABLE_TIME
]) {
393 __u64 reachable
= rta_getattr_u64(tpb
[NDTPA_REACHABLE_TIME
]);
395 print_u64(PRINT_ANY
, "reachable",
396 "reachable %llu ", reachable
);
399 if (tpb
[NDTPA_BASE_REACHABLE_TIME
]) {
401 = rta_getattr_u64(tpb
[NDTPA_BASE_REACHABLE_TIME
]);
403 print_u64(PRINT_ANY
, "base_reachable",
404 "base_reachable %llu ", breachable
);
407 if (tpb
[NDTPA_RETRANS_TIME
]) {
408 __u64 retrans
= rta_getattr_u64(tpb
[NDTPA_RETRANS_TIME
]);
410 print_u64(PRINT_ANY
, "retrans", "retrans %llu ", retrans
);
413 print_string(PRINT_FP
, NULL
, "%s ", _SL_
);
415 if (tpb
[NDTPA_GC_STALETIME
]) {
416 __u64 gc_stale
= rta_getattr_u64(tpb
[NDTPA_GC_STALETIME
]);
418 print_u64(PRINT_ANY
, "gc_stale", "gc_stale %llu ", gc_stale
);
421 if (tpb
[NDTPA_DELAY_PROBE_TIME
]) {
423 = rta_getattr_u64(tpb
[NDTPA_DELAY_PROBE_TIME
]);
425 print_u64(PRINT_ANY
, "delay_probe",
426 "delay_probe %llu ", delay_probe
);
429 if (tpb
[NDTPA_QUEUE_LEN
]) {
430 __u32 queue
= rta_getattr_u32(tpb
[NDTPA_QUEUE_LEN
]);
432 print_uint(PRINT_ANY
, "queue", "queue %u ", queue
);
435 print_string(PRINT_FP
, NULL
, "%s ", _SL_
);
437 if (tpb
[NDTPA_APP_PROBES
]) {
438 __u32 aprobe
= rta_getattr_u32(tpb
[NDTPA_APP_PROBES
]);
440 print_uint(PRINT_ANY
, "app_probes", "app_probes %u ", aprobe
);
443 if (tpb
[NDTPA_UCAST_PROBES
]) {
444 __u32 uprobe
= rta_getattr_u32(tpb
[NDTPA_UCAST_PROBES
]);
446 print_uint(PRINT_ANY
, "ucast_probes",
447 "ucast_probes %u ", uprobe
);
450 if (tpb
[NDTPA_MCAST_PROBES
]) {
451 __u32 mprobe
= rta_getattr_u32(tpb
[NDTPA_MCAST_PROBES
]);
453 print_uint(PRINT_ANY
, "mcast_probes",
454 "mcast_probes %u ", mprobe
);
457 print_string(PRINT_FP
, NULL
, "%s ", _SL_
);
459 if (tpb
[NDTPA_ANYCAST_DELAY
]) {
460 __u64 anycast_delay
= rta_getattr_u64(tpb
[NDTPA_ANYCAST_DELAY
]);
462 print_u64(PRINT_ANY
, "anycast_delay",
463 "anycast_delay %llu ", anycast_delay
);
466 if (tpb
[NDTPA_PROXY_DELAY
]) {
467 __u64 proxy_delay
= rta_getattr_u64(tpb
[NDTPA_PROXY_DELAY
]);
469 print_u64(PRINT_ANY
, "proxy_delay",
470 "proxy_delay %llu ", proxy_delay
);
473 if (tpb
[NDTPA_PROXY_QLEN
]) {
474 __u32 pqueue
= rta_getattr_u32(tpb
[NDTPA_PROXY_QLEN
]);
476 print_uint(PRINT_ANY
, "proxy_queue", "proxy_queue %u ", pqueue
);
479 if (tpb
[NDTPA_LOCKTIME
]) {
480 __u64 locktime
= rta_getattr_u64(tpb
[NDTPA_LOCKTIME
]);
482 print_u64(PRINT_ANY
, "locktime", "locktime %llu ", locktime
);
488 static void print_ndtstats(const struct ndt_stats
*ndts
)
491 print_string(PRINT_FP
, NULL
, " stats ", NULL
);
493 print_u64(PRINT_ANY
, "allocs", "allocs %llu ", ndts
->ndts_allocs
);
494 print_u64(PRINT_ANY
, "destroys", "destroys %llu ",
495 ndts
->ndts_destroys
);
496 print_u64(PRINT_ANY
, "hash_grows", "hash_grows %llu ",
497 ndts
->ndts_hash_grows
);
499 print_string(PRINT_FP
, NULL
, "%s ", _SL_
);
501 print_u64(PRINT_ANY
, "res_failed", "res_failed %llu ",
502 ndts
->ndts_res_failed
);
503 print_u64(PRINT_ANY
, "lookups", "lookups %llu ", ndts
->ndts_lookups
);
504 print_u64(PRINT_ANY
, "hits", "hits %llu ", ndts
->ndts_hits
);
506 print_string(PRINT_FP
, NULL
, "%s ", _SL_
);
508 print_u64(PRINT_ANY
, "rcv_probes_mcast", "rcv_probes_mcast %llu ",
509 ndts
->ndts_rcv_probes_mcast
);
510 print_u64(PRINT_ANY
, "rcv_probes_ucast", "rcv_probes_ucast %llu ",
511 ndts
->ndts_rcv_probes_ucast
);
513 print_string(PRINT_FP
, NULL
, "%s ", _SL_
);
515 print_u64(PRINT_ANY
, "periodic_gc_runs", "periodic_gc_runs %llu ",
516 ndts
->ndts_periodic_gc_runs
);
517 print_u64(PRINT_ANY
, "forced_gc_runs", "forced_gc_runs %llu ",
518 ndts
->ndts_forced_gc_runs
);
523 static int print_ntable(struct nlmsghdr
*n
, void *arg
)
525 FILE *fp
= (FILE *)arg
;
526 struct ndtmsg
*ndtm
= NLMSG_DATA(n
);
527 int len
= n
->nlmsg_len
;
528 struct rtattr
*tb
[NDTA_MAX
+1];
529 struct rtattr
*tpb
[NDTPA_MAX
+1];
532 if (n
->nlmsg_type
!= RTM_NEWNEIGHTBL
) {
533 fprintf(stderr
, "Not NEIGHTBL: %08x %08x %08x\n",
534 n
->nlmsg_len
, n
->nlmsg_type
, n
->nlmsg_flags
);
537 len
-= NLMSG_LENGTH(sizeof(*ndtm
));
539 fprintf(stderr
, "BUG: wrong nlmsg len %d\n", len
);
543 if (preferred_family
&& preferred_family
!= ndtm
->ndtm_family
)
546 parse_rtattr(tb
, NDTA_MAX
, NDTA_RTA(ndtm
),
547 n
->nlmsg_len
- NLMSG_LENGTH(sizeof(*ndtm
)));
550 const char *name
= rta_getattr_str(tb
[NDTA_NAME
]);
552 if (filter
.name
&& strcmp(filter
.name
, name
))
556 if (tb
[NDTA_PARMS
]) {
557 parse_rtattr(tpb
, NDTPA_MAX
, RTA_DATA(tb
[NDTA_PARMS
]),
558 RTA_PAYLOAD(tb
[NDTA_PARMS
]));
560 if (tpb
[NDTPA_IFINDEX
]) {
561 __u32 ifindex
= rta_getattr_u32(tpb
[NDTPA_IFINDEX
]);
563 if (filter
.index
&& filter
.index
!= ifindex
)
566 if (filter
.index
&& filter
.index
!= NONE_DEV
)
571 open_json_object(NULL
);
572 print_string(PRINT_ANY
, "family",
573 "%s ", family_name(ndtm
->ndtm_family
));
576 const char *name
= rta_getattr_str(tb
[NDTA_NAME
]);
578 print_string(PRINT_ANY
, "name", "%s ", name
);
583 ret
= (tb
[NDTA_THRESH1
] || tb
[NDTA_THRESH2
] || tb
[NDTA_THRESH3
] ||
584 tb
[NDTA_GC_INTERVAL
]);
586 print_string(PRINT_FP
, NULL
, " ", NULL
);
588 if (tb
[NDTA_THRESH1
]) {
589 __u32 thresh1
= rta_getattr_u32(tb
[NDTA_THRESH1
]);
591 print_uint(PRINT_ANY
, "thresh1", "thresh1 %u ", thresh1
);
594 if (tb
[NDTA_THRESH2
]) {
595 __u32 thresh2
= rta_getattr_u32(tb
[NDTA_THRESH2
]);
597 print_uint(PRINT_ANY
, "thresh2", "thresh2 %u ", thresh2
);
600 if (tb
[NDTA_THRESH3
]) {
601 __u32 thresh3
= rta_getattr_u32(tb
[NDTA_THRESH3
]);
603 print_uint(PRINT_ANY
, "thresh3", "thresh3 %u ", thresh3
);
606 if (tb
[NDTA_GC_INTERVAL
]) {
607 __u64 gc_int
= rta_getattr_u64(tb
[NDTA_GC_INTERVAL
]);
609 print_u64(PRINT_ANY
, "gc_interval", "gc_int %llu ", gc_int
);
615 if (tb
[NDTA_CONFIG
] && show_stats
)
616 print_ndtconfig(RTA_DATA(tb
[NDTA_CONFIG
]));
619 print_ndtparams(tpb
);
621 if (tb
[NDTA_STATS
] && show_stats
)
622 print_ndtstats(RTA_DATA(tb
[NDTA_STATS
]));
624 print_string(PRINT_FP
, NULL
, "\n", "");
631 static void ipntable_reset_filter(void)
633 memset(&filter
, 0, sizeof(filter
));
636 static int ipntable_show(int argc
, char **argv
)
638 ipntable_reset_filter();
640 filter
.family
= preferred_family
;
643 if (strcmp(*argv
, "dev") == 0) {
646 if (strcmp("none", *argv
) == 0)
647 filter
.index
= NONE_DEV
;
648 else if ((filter
.index
= ll_name_to_index(*argv
)) == 0)
649 invarg("\"DEV\" is invalid", *argv
);
650 } else if (strcmp(*argv
, "name") == 0) {
655 invarg("unknown", *argv
);
660 if (rtnl_neightbldump_req(&rth
, preferred_family
) < 0) {
661 perror("Cannot send dump request");
666 if (rtnl_dump_filter(&rth
, print_ntable
, stdout
) < 0) {
667 fprintf(stderr
, "Dump terminated\n");
675 int do_ipntable(int argc
, char **argv
)
680 if (matches(*argv
, "change") == 0 ||
681 matches(*argv
, "chg") == 0)
682 return ipntable_modify(RTM_SETNEIGHTBL
,
685 if (matches(*argv
, "show") == 0 ||
686 matches(*argv
, "lst") == 0 ||
687 matches(*argv
, "list") == 0)
688 return ipntable_show(argc
-1, argv
+1);
689 if (matches(*argv
, "help") == 0)
692 return ipntable_show(0, NULL
);
694 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip ntable help\".\n", *argv
);