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, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * Masahide NAKAMURA @USAGI
30 #include <sys/socket.h>
34 #include "ip_common.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_probs 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
)
72 char *threshsp
= NULL
;
75 struct rtattr
*parms_rta
= (struct rtattr
*)parms_buf
;
78 memset(&req
, 0, sizeof(req
));
80 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndtmsg
));
81 req
.n
.nlmsg_flags
= NLM_F_REQUEST
|flags
;
82 req
.n
.nlmsg_type
= cmd
;
84 req
.ndtm
.ndtm_family
= preferred_family
;
85 req
.ndtm
.ndtm_pad1
= 0;
86 req
.ndtm
.ndtm_pad2
= 0;
88 memset(&parms_buf
, 0, sizeof(parms_buf
));
90 parms_rta
->rta_type
= NDTA_PARMS
;
91 parms_rta
->rta_len
= RTA_LENGTH(0);
94 if (strcmp(*argv
, "name") == 0) {
99 duparg("NAME", *argv
);
102 len
= strlen(namep
) + 1;
103 addattr_l(&req
.n
, sizeof(req
), NDTA_NAME
, namep
, len
);
104 } else if (strcmp(*argv
, "thresh1") == 0) {
110 if (get_u32(&thresh1
, *argv
, 0))
111 invarg("\"thresh1\" value is invalid", *argv
);
113 addattr32(&req
.n
, sizeof(req
), NDTA_THRESH1
, thresh1
);
114 } else if (strcmp(*argv
, "thresh2") == 0) {
120 if (get_u32(&thresh2
, *argv
, 0))
121 invarg("\"thresh2\" value is invalid", *argv
);
123 addattr32(&req
.n
, sizeof(req
), NDTA_THRESH2
, thresh2
);
124 } else if (strcmp(*argv
, "thresh3") == 0) {
130 if (get_u32(&thresh3
, *argv
, 0))
131 invarg("\"thresh3\" value is invalid", *argv
);
133 addattr32(&req
.n
, sizeof(req
), NDTA_THRESH3
, thresh3
);
134 } else if (strcmp(*argv
, "gc_int") == 0) {
140 if (get_u64(&gc_int
, *argv
, 0))
141 invarg("\"gc_int\" value is invalid", *argv
);
143 addattr_l(&req
.n
, sizeof(req
), NDTA_GC_INTERVAL
,
144 &gc_int
, sizeof(gc_int
));
145 } else if (strcmp(*argv
, "dev") == 0) {
149 ifindex
= ll_name_to_index(*argv
);
151 fprintf(stderr
, "Cannot find device \"%s\"\n", *argv
);
155 rta_addattr32(parms_rta
, sizeof(parms_buf
),
156 NDTPA_IFINDEX
, ifindex
);
157 } else if (strcmp(*argv
, "base_reachable") == 0) {
162 if (get_u64(&breachable
, *argv
, 0))
163 invarg("\"base_reachable\" value is invalid", *argv
);
165 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
166 NDTPA_BASE_REACHABLE_TIME
,
167 &breachable
, sizeof(breachable
));
169 } else if (strcmp(*argv
, "retrans") == 0) {
174 if (get_u64(&retrans
, *argv
, 0))
175 invarg("\"retrans\" value is invalid", *argv
);
177 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
179 &retrans
, sizeof(retrans
));
181 } else if (strcmp(*argv
, "gc_stale") == 0) {
186 if (get_u64(&gc_stale
, *argv
, 0))
187 invarg("\"gc_stale\" value is invalid", *argv
);
189 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
191 &gc_stale
, sizeof(gc_stale
));
193 } else if (strcmp(*argv
, "delay_probe") == 0) {
198 if (get_u64(&delay_probe
, *argv
, 0))
199 invarg("\"delay_probe\" value is invalid", *argv
);
201 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
202 NDTPA_DELAY_PROBE_TIME
,
203 &delay_probe
, sizeof(delay_probe
));
205 } else if (strcmp(*argv
, "queue") == 0) {
210 if (get_u32(&queue
, *argv
, 0))
211 invarg("\"queue\" value is invalid", *argv
);
214 parms_rta
= (struct rtattr
*)&parms_buf
;
215 rta_addattr32(parms_rta
, sizeof(parms_buf
),
216 NDTPA_QUEUE_LEN
, queue
);
218 } else if (strcmp(*argv
, "app_probes") == 0) {
223 if (get_u32(&aprobe
, *argv
, 0))
224 invarg("\"app_probes\" value is invalid", *argv
);
226 rta_addattr32(parms_rta
, sizeof(parms_buf
),
227 NDTPA_APP_PROBES
, aprobe
);
229 } else if (strcmp(*argv
, "ucast_probes") == 0) {
234 if (get_u32(&uprobe
, *argv
, 0))
235 invarg("\"ucast_probes\" value is invalid", *argv
);
237 rta_addattr32(parms_rta
, sizeof(parms_buf
),
238 NDTPA_UCAST_PROBES
, uprobe
);
240 } else if (strcmp(*argv
, "mcast_probes") == 0) {
245 if (get_u32(&mprobe
, *argv
, 0))
246 invarg("\"mcast_probes\" value is invalid", *argv
);
248 rta_addattr32(parms_rta
, sizeof(parms_buf
),
249 NDTPA_MCAST_PROBES
, mprobe
);
251 } else if (strcmp(*argv
, "anycast_delay") == 0) {
256 if (get_u64(&anycast_delay
, *argv
, 0))
257 invarg("\"anycast_delay\" value is invalid", *argv
);
259 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
261 &anycast_delay
, sizeof(anycast_delay
));
263 } else if (strcmp(*argv
, "proxy_delay") == 0) {
268 if (get_u64(&proxy_delay
, *argv
, 0))
269 invarg("\"proxy_delay\" value is invalid", *argv
);
271 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
273 &proxy_delay
, sizeof(proxy_delay
));
275 } else if (strcmp(*argv
, "proxy_queue") == 0) {
280 if (get_u32(&pqueue
, *argv
, 0))
281 invarg("\"proxy_queue\" value is invalid", *argv
);
283 rta_addattr32(parms_rta
, sizeof(parms_buf
),
284 NDTPA_PROXY_QLEN
, pqueue
);
286 } else if (strcmp(*argv
, "locktime") == 0) {
291 if (get_u64(&locktime
, *argv
, 0))
292 invarg("\"locktime\" value is invalid", *argv
);
294 rta_addattr_l(parms_rta
, sizeof(parms_buf
),
296 &locktime
, sizeof(locktime
));
299 invarg("unknown", *argv
);
307 if (!threshsp
&& !gc_intp
&& !parms_change
) {
308 fprintf(stderr
, "Not enough information: changable attributes required.\n");
312 if (parms_rta
->rta_len
> RTA_LENGTH(0)) {
313 addattr_l(&req
.n
, sizeof(req
), NDTA_PARMS
, RTA_DATA(parms_rta
),
314 RTA_PAYLOAD(parms_rta
));
317 if (rtnl_talk(&rth
, &req
.n
, 0, 0, NULL
) < 0)
323 static const char *ntable_strtime_delta(__u32 msec
)
333 memset(&now
, 0, sizeof(now
));
335 if (gettimeofday(&now
, NULL
) < 0) {
336 perror("gettimeofday");
340 t
= now
.tv_sec
- (msec
/ 1000);
345 strftime(str
, sizeof(str
), "%Y-%m-%d %T", tp
);
349 strcpy(str
, "(error)");
353 int print_ntable(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
, void *arg
)
355 FILE *fp
= (FILE*)arg
;
356 struct ndtmsg
*ndtm
= NLMSG_DATA(n
);
357 int len
= n
->nlmsg_len
;
358 struct rtattr
*tb
[NDTA_MAX
+1];
359 struct rtattr
*tpb
[NDTPA_MAX
+1];
362 if (n
->nlmsg_type
!= RTM_NEWNEIGHTBL
) {
363 fprintf(stderr
, "Not NEIGHTBL: %08x %08x %08x\n",
364 n
->nlmsg_len
, n
->nlmsg_type
, n
->nlmsg_flags
);
367 len
-= NLMSG_LENGTH(sizeof(*ndtm
));
369 fprintf(stderr
, "BUG: wrong nlmsg len %d\n", len
);
373 if (preferred_family
&& preferred_family
!= ndtm
->ndtm_family
)
376 parse_rtattr(tb
, NDTA_MAX
, NDTA_RTA(ndtm
),
377 n
->nlmsg_len
- NLMSG_LENGTH(sizeof(*ndtm
)));
380 const char *name
= rta_getattr_str(tb
[NDTA_NAME
]);
382 if (strlen(filter
.name
) > 0 && strcmp(filter
.name
, name
))
385 if (tb
[NDTA_PARMS
]) {
386 parse_rtattr(tpb
, NDTPA_MAX
, RTA_DATA(tb
[NDTA_PARMS
]),
387 RTA_PAYLOAD(tb
[NDTA_PARMS
]));
389 if (tpb
[NDTPA_IFINDEX
]) {
390 __u32 ifindex
= rta_getattr_u32(tpb
[NDTPA_IFINDEX
]);
392 if (filter
.index
&& filter
.index
!= ifindex
)
395 if (filter
.index
&& filter
.index
!= NONE_DEV
)
400 if (ndtm
->ndtm_family
== AF_INET
)
401 fprintf(fp
, "inet ");
402 else if (ndtm
->ndtm_family
== AF_INET6
)
403 fprintf(fp
, "inet6 ");
404 else if (ndtm
->ndtm_family
== AF_DECnet
)
405 fprintf(fp
, "dnet ");
407 fprintf(fp
, "(%d) ", ndtm
->ndtm_family
);
410 const char *name
= rta_getattr_str(tb
[NDTA_NAME
]);
411 fprintf(fp
, "%s ", name
);
414 fprintf(fp
, "%s", _SL_
);
416 ret
= (tb
[NDTA_THRESH1
] || tb
[NDTA_THRESH2
] || tb
[NDTA_THRESH3
] ||
417 tb
[NDTA_GC_INTERVAL
]);
421 if (tb
[NDTA_THRESH1
]) {
422 __u32 thresh1
= rta_getattr_u32(tb
[NDTA_THRESH1
]);
423 fprintf(fp
, "thresh1 %u ", thresh1
);
425 if (tb
[NDTA_THRESH2
]) {
426 __u32 thresh2
= rta_getattr_u32(tb
[NDTA_THRESH2
]);
427 fprintf(fp
, "thresh2 %u ", thresh2
);
429 if (tb
[NDTA_THRESH3
]) {
430 __u32 thresh3
= rta_getattr_u32(tb
[NDTA_THRESH3
]);
431 fprintf(fp
, "thresh3 %u ", thresh3
);
433 if (tb
[NDTA_GC_INTERVAL
]) {
434 __u64 gc_int
= rta_getattr_u64(tb
[NDTA_GC_INTERVAL
]);
435 fprintf(fp
, "gc_int %llu ", (unsigned long long) gc_int
);
439 fprintf(fp
, "%s", _SL_
);
441 if (tb
[NDTA_CONFIG
] && show_stats
) {
442 struct ndt_config
*ndtc
= RTA_DATA(tb
[NDTA_CONFIG
]);
445 fprintf(fp
, "config ");
447 fprintf(fp
, "key_len %u ", ndtc
->ndtc_key_len
);
448 fprintf(fp
, "entry_size %u ", ndtc
->ndtc_entry_size
);
449 fprintf(fp
, "entries %u ", ndtc
->ndtc_entries
);
451 fprintf(fp
, "%s", _SL_
);
454 fprintf(fp
, "last_flush %s ",
455 ntable_strtime_delta(ndtc
->ndtc_last_flush
));
456 fprintf(fp
, "last_rand %s ",
457 ntable_strtime_delta(ndtc
->ndtc_last_rand
));
459 fprintf(fp
, "%s", _SL_
);
462 fprintf(fp
, "hash_rnd %u ", ndtc
->ndtc_hash_rnd
);
463 fprintf(fp
, "hash_mask %08x ", ndtc
->ndtc_hash_mask
);
465 fprintf(fp
, "hash_chain_gc %u ", ndtc
->ndtc_hash_chain_gc
);
466 fprintf(fp
, "proxy_qlen %u ", ndtc
->ndtc_proxy_qlen
);
468 fprintf(fp
, "%s", _SL_
);
471 if (tb
[NDTA_PARMS
]) {
472 if (tpb
[NDTPA_IFINDEX
]) {
473 __u32 ifindex
= rta_getattr_u32(tpb
[NDTPA_IFINDEX
]);
476 fprintf(fp
, "dev %s ", ll_index_to_name(ifindex
));
477 fprintf(fp
, "%s", _SL_
);
482 if (tpb
[NDTPA_REFCNT
]) {
483 __u32 refcnt
= rta_getattr_u32(tpb
[NDTPA_REFCNT
]);
484 fprintf(fp
, "refcnt %u ", refcnt
);
486 if (tpb
[NDTPA_REACHABLE_TIME
]) {
487 __u64 reachable
= rta_getattr_u64(tpb
[NDTPA_REACHABLE_TIME
]);
488 fprintf(fp
, "reachable %llu ",
489 (unsigned long long) reachable
);
491 if (tpb
[NDTPA_BASE_REACHABLE_TIME
]) {
492 __u64 breachable
= rta_getattr_u64(tpb
[NDTPA_BASE_REACHABLE_TIME
]);
493 fprintf(fp
, "base_reachable %llu ",
494 (unsigned long long) breachable
);
496 if (tpb
[NDTPA_RETRANS_TIME
]) {
497 __u64 retrans
= rta_getattr_u64(tpb
[NDTPA_RETRANS_TIME
]);
498 fprintf(fp
, "retrans %llu ",
499 (unsigned long long) retrans
);
502 fprintf(fp
, "%s", _SL_
);
506 if (tpb
[NDTPA_GC_STALETIME
]) {
507 __u64 gc_stale
= rta_getattr_u64(tpb
[NDTPA_GC_STALETIME
]);
508 fprintf(fp
, "gc_stale %llu ",
509 (unsigned long long) gc_stale
);
511 if (tpb
[NDTPA_DELAY_PROBE_TIME
]) {
512 __u64 delay_probe
= rta_getattr_u64(tpb
[NDTPA_DELAY_PROBE_TIME
]);
513 fprintf(fp
, "delay_probe %llu ",
514 (unsigned long long) delay_probe
);
516 if (tpb
[NDTPA_QUEUE_LEN
]) {
517 __u32 queue
= rta_getattr_u32(tpb
[NDTPA_QUEUE_LEN
]);
518 fprintf(fp
, "queue %u ", queue
);
521 fprintf(fp
, "%s", _SL_
);
525 if (tpb
[NDTPA_APP_PROBES
]) {
526 __u32 aprobe
= rta_getattr_u32(tpb
[NDTPA_APP_PROBES
]);
527 fprintf(fp
, "app_probes %u ", aprobe
);
529 if (tpb
[NDTPA_UCAST_PROBES
]) {
530 __u32 uprobe
= rta_getattr_u32(tpb
[NDTPA_UCAST_PROBES
]);
531 fprintf(fp
, "ucast_probes %u ", uprobe
);
533 if (tpb
[NDTPA_MCAST_PROBES
]) {
534 __u32 mprobe
= rta_getattr_u32(tpb
[NDTPA_MCAST_PROBES
]);
535 fprintf(fp
, "mcast_probes %u ", mprobe
);
538 fprintf(fp
, "%s", _SL_
);
542 if (tpb
[NDTPA_ANYCAST_DELAY
]) {
543 __u64 anycast_delay
= rta_getattr_u64(tpb
[NDTPA_ANYCAST_DELAY
]);
544 fprintf(fp
, "anycast_delay %llu ",
545 (unsigned long long) anycast_delay
);
547 if (tpb
[NDTPA_PROXY_DELAY
]) {
548 __u64 proxy_delay
= rta_getattr_u64(tpb
[NDTPA_PROXY_DELAY
]);
549 fprintf(fp
, "proxy_delay %llu ",
550 (unsigned long long) proxy_delay
);
552 if (tpb
[NDTPA_PROXY_QLEN
]) {
553 __u32 pqueue
= rta_getattr_u32(tpb
[NDTPA_PROXY_QLEN
]);
554 fprintf(fp
, "proxy_queue %u ", pqueue
);
556 if (tpb
[NDTPA_LOCKTIME
]) {
557 __u64 locktime
= rta_getattr_u64(tpb
[NDTPA_LOCKTIME
]);
558 fprintf(fp
, "locktime %llu ",
559 (unsigned long long) locktime
);
562 fprintf(fp
, "%s", _SL_
);
565 if (tb
[NDTA_STATS
] && show_stats
) {
566 struct ndt_stats
*ndts
= RTA_DATA(tb
[NDTA_STATS
]);
569 fprintf(fp
, "stats ");
571 fprintf(fp
, "allocs %llu ",
572 (unsigned long long) ndts
->ndts_allocs
);
573 fprintf(fp
, "destroys %llu ",
574 (unsigned long long) ndts
->ndts_destroys
);
575 fprintf(fp
, "hash_grows %llu ",
576 (unsigned long long) ndts
->ndts_hash_grows
);
578 fprintf(fp
, "%s", _SL_
);
581 fprintf(fp
, "res_failed %llu ",
582 (unsigned long long) ndts
->ndts_res_failed
);
583 fprintf(fp
, "lookups %llu ",
584 (unsigned long long) ndts
->ndts_lookups
);
585 fprintf(fp
, "hits %llu ",
586 (unsigned long long) ndts
->ndts_hits
);
588 fprintf(fp
, "%s", _SL_
);
591 fprintf(fp
, "rcv_probes_mcast %llu ",
592 (unsigned long long) ndts
->ndts_rcv_probes_mcast
);
593 fprintf(fp
, "rcv_probes_ucast %llu ",
594 (unsigned long long) ndts
->ndts_rcv_probes_ucast
);
596 fprintf(fp
, "%s", _SL_
);
599 fprintf(fp
, "periodic_gc_runs %llu ",
600 (unsigned long long) ndts
->ndts_periodic_gc_runs
);
601 fprintf(fp
, "forced_gc_runs %llu ",
602 (unsigned long long) ndts
->ndts_forced_gc_runs
);
604 fprintf(fp
, "%s", _SL_
);
613 void ipntable_reset_filter(void)
615 memset(&filter
, 0, sizeof(filter
));
618 static int ipntable_show(int argc
, char **argv
)
620 ipntable_reset_filter();
622 filter
.family
= preferred_family
;
625 if (strcmp(*argv
, "dev") == 0) {
628 if (strcmp("none", *argv
) == 0)
629 filter
.index
= NONE_DEV
;
630 else if ((filter
.index
= ll_name_to_index(*argv
)) == 0)
631 invarg("\"DEV\" is invalid", *argv
);
632 } else if (strcmp(*argv
, "name") == 0) {
635 strncpy(filter
.name
, *argv
, sizeof(filter
.name
));
637 invarg("unknown", *argv
);
642 if (rtnl_wilddump_request(&rth
, preferred_family
, RTM_GETNEIGHTBL
) < 0) {
643 perror("Cannot send dump request");
647 if (rtnl_dump_filter(&rth
, print_ntable
, stdout
) < 0) {
648 fprintf(stderr
, "Dump terminated\n");
655 int do_ipntable(int argc
, char **argv
)
660 if (matches(*argv
, "change") == 0 ||
661 matches(*argv
, "chg") == 0)
662 return ipntable_modify(RTM_SETNEIGHTBL
,
665 if (matches(*argv
, "show") == 0 ||
666 matches(*argv
, "lst") == 0 ||
667 matches(*argv
, "list") == 0)
668 return ipntable_show(argc
-1, argv
+1);
669 if (matches(*argv
, "help") == 0)
672 return ipntable_show(0, NULL
);
674 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip ntable help\".\n", *argv
);