2 * iproute.c "ip route".
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <netinet/ip.h>
24 #include <arpa/inet.h>
25 #include <linux/in_route.h>
26 #include <linux/icmpv6.h>
31 #include "ip_common.h"
34 #define RTAX_RTTVAR RTAX_HOPS
42 static const char *mx_names
[RTAX_MAX
+1] = {
44 [RTAX_WINDOW
] = "window",
46 [RTAX_RTTVAR
] = "rttvar",
47 [RTAX_SSTHRESH
] = "ssthresh",
49 [RTAX_ADVMSS
] = "advmss",
50 [RTAX_REORDERING
]="reordering",
51 [RTAX_HOPLIMIT
] = "hoplimit",
52 [RTAX_INITCWND
] = "initcwnd",
53 [RTAX_FEATURES
] = "features",
54 [RTAX_RTO_MIN
] = "rto_min",
55 [RTAX_INITRWND
] = "initrwnd",
56 [RTAX_QUICKACK
] = "quickack",
57 [RTAX_CC_ALGO
] = "congctl",
59 static void usage(void) __attribute__((noreturn
));
61 static void usage(void)
63 fprintf(stderr
, "Usage: ip route { list | flush } SELECTOR\n");
64 fprintf(stderr
, " ip route save SELECTOR\n");
65 fprintf(stderr
, " ip route restore\n");
66 fprintf(stderr
, " ip route showdump\n");
67 fprintf(stderr
, " ip route get ADDRESS [ from ADDRESS iif STRING ]\n");
68 fprintf(stderr
, " [ oif STRING ] [ tos TOS ]\n");
69 fprintf(stderr
, " [ mark NUMBER ]\n");
70 fprintf(stderr
, " ip route { add | del | change | append | replace } ROUTE\n");
71 fprintf(stderr
, "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n");
72 fprintf(stderr
, " [ table TABLE_ID ] [ proto RTPROTO ]\n");
73 fprintf(stderr
, " [ type TYPE ] [ scope SCOPE ]\n");
74 fprintf(stderr
, "ROUTE := NODE_SPEC [ INFO_SPEC ]\n");
75 fprintf(stderr
, "NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n");
76 fprintf(stderr
, " [ table TABLE_ID ] [ proto RTPROTO ]\n");
77 fprintf(stderr
, " [ scope SCOPE ] [ metric METRIC ]\n");
78 fprintf(stderr
, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n");
79 fprintf(stderr
, "NH := [ via [ FAMILY ] ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
80 fprintf(stderr
, "FAMILY := [ inet | inet6 | ipx | dnet | mpls | bridge | link ]\n");
81 fprintf(stderr
, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n");
82 fprintf(stderr
, " [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n");
83 fprintf(stderr
, " [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n");
84 fprintf(stderr
, " [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n");
85 fprintf(stderr
, " [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n");
86 fprintf(stderr
, " [ features FEATURES ] [ quickack BOOL ] [ congctl NAME ]\n");
87 fprintf(stderr
, " [ pref PREF ]\n");
88 fprintf(stderr
, "TYPE := [ unicast | local | broadcast | multicast | throw |\n");
89 fprintf(stderr
, " unreachable | prohibit | blackhole | nat ]\n");
90 fprintf(stderr
, "TABLE_ID := [ local | main | default | all | NUMBER ]\n");
91 fprintf(stderr
, "SCOPE := [ host | link | global | NUMBER ]\n");
92 fprintf(stderr
, "NHFLAGS := [ onlink | pervasive ]\n");
93 fprintf(stderr
, "RTPROTO := [ kernel | boot | static | NUMBER ]\n");
94 fprintf(stderr
, "PREF := [ low | medium | high ]\n");
95 fprintf(stderr
, "TIME := NUMBER[s|ms]\n");
96 fprintf(stderr
, "BOOL := [1|0]\n");
97 fprintf(stderr
, "FEATURES := ecn\n");
110 int protocol
, protocolmask
;
111 int scope
, scopemask
;
117 int realm
, realmmask
;
118 inet_prefix rprefsrc
;
126 static int flush_update(void)
128 if (rtnl_send_check(&rth
, filter
.flushb
, filter
.flushp
) < 0) {
129 perror("Failed to send flush request");
136 static int filter_nlmsg(struct nlmsghdr
*n
, struct rtattr
**tb
, int host_len
)
138 struct rtmsg
*r
= NLMSG_DATA(n
);
144 static int ip6_multiple_tables
;
146 table
= rtm_get_table(r
, tb
);
148 if (r
->rtm_family
== AF_INET6
&& table
!= RT_TABLE_MAIN
)
149 ip6_multiple_tables
= 1;
151 if (filter
.cloned
== !(r
->rtm_flags
&RTM_F_CLONED
))
154 if (r
->rtm_family
== AF_INET6
&& !ip6_multiple_tables
) {
156 if (filter
.tb
== RT_TABLE_LOCAL
) {
157 if (r
->rtm_type
!= RTN_LOCAL
)
159 } else if (filter
.tb
== RT_TABLE_MAIN
) {
160 if (r
->rtm_type
== RTN_LOCAL
)
167 if (filter
.tb
> 0 && filter
.tb
!= table
)
170 if ((filter
.protocol
^r
->rtm_protocol
)&filter
.protocolmask
)
172 if ((filter
.scope
^r
->rtm_scope
)&filter
.scopemask
)
174 if ((filter
.type
^r
->rtm_type
)&filter
.typemask
)
176 if ((filter
.tos
^r
->rtm_tos
)&filter
.tosmask
)
178 if (filter
.rdst
.family
&&
179 (r
->rtm_family
!= filter
.rdst
.family
|| filter
.rdst
.bitlen
> r
->rtm_dst_len
))
181 if (filter
.mdst
.family
&&
182 (r
->rtm_family
!= filter
.mdst
.family
||
183 (filter
.mdst
.bitlen
>= 0 && filter
.mdst
.bitlen
< r
->rtm_dst_len
)))
185 if (filter
.rsrc
.family
&&
186 (r
->rtm_family
!= filter
.rsrc
.family
|| filter
.rsrc
.bitlen
> r
->rtm_src_len
))
188 if (filter
.msrc
.family
&&
189 (r
->rtm_family
!= filter
.msrc
.family
||
190 (filter
.msrc
.bitlen
>= 0 && filter
.msrc
.bitlen
< r
->rtm_src_len
)))
192 if (filter
.rvia
.family
) {
193 int family
= r
->rtm_family
;
195 struct rtvia
*via
= RTA_DATA(tb
[RTA_VIA
]);
196 family
= via
->rtvia_family
;
198 if (family
!= filter
.rvia
.family
)
201 if (filter
.rprefsrc
.family
&& r
->rtm_family
!= filter
.rprefsrc
.family
)
204 memset(&dst
, 0, sizeof(dst
));
205 dst
.family
= r
->rtm_family
;
207 memcpy(&dst
.data
, RTA_DATA(tb
[RTA_DST
]), (r
->rtm_dst_len
+7)/8);
208 if (filter
.rsrc
.family
|| filter
.msrc
.family
) {
209 memset(&src
, 0, sizeof(src
));
210 src
.family
= r
->rtm_family
;
212 memcpy(&src
.data
, RTA_DATA(tb
[RTA_SRC
]), (r
->rtm_src_len
+7)/8);
214 if (filter
.rvia
.bitlen
>0) {
215 memset(&via
, 0, sizeof(via
));
216 via
.family
= r
->rtm_family
;
218 memcpy(&via
.data
, RTA_DATA(tb
[RTA_GATEWAY
]), host_len
/8);
220 size_t len
= RTA_PAYLOAD(tb
[RTA_VIA
]) - 2;
221 struct rtvia
*rtvia
= RTA_DATA(tb
[RTA_VIA
]);
222 via
.family
= rtvia
->rtvia_family
;
223 memcpy(&via
.data
, rtvia
->rtvia_addr
, len
);
226 if (filter
.rprefsrc
.bitlen
>0) {
227 memset(&prefsrc
, 0, sizeof(prefsrc
));
228 prefsrc
.family
= r
->rtm_family
;
230 memcpy(&prefsrc
.data
, RTA_DATA(tb
[RTA_PREFSRC
]), host_len
/8);
233 if (filter
.rdst
.family
&& inet_addr_match(&dst
, &filter
.rdst
, filter
.rdst
.bitlen
))
235 if (filter
.mdst
.family
&& filter
.mdst
.bitlen
>= 0 &&
236 inet_addr_match(&dst
, &filter
.mdst
, r
->rtm_dst_len
))
239 if (filter
.rsrc
.family
&& inet_addr_match(&src
, &filter
.rsrc
, filter
.rsrc
.bitlen
))
241 if (filter
.msrc
.family
&& filter
.msrc
.bitlen
>= 0 &&
242 inet_addr_match(&src
, &filter
.msrc
, r
->rtm_src_len
))
245 if (filter
.rvia
.family
&& inet_addr_match(&via
, &filter
.rvia
, filter
.rvia
.bitlen
))
247 if (filter
.rprefsrc
.family
&& inet_addr_match(&prefsrc
, &filter
.rprefsrc
, filter
.rprefsrc
.bitlen
))
249 if (filter
.realmmask
) {
252 realms
= rta_getattr_u32(tb
[RTA_FLOW
]);
253 if ((realms
^filter
.realm
)&filter
.realmmask
)
256 if (filter
.iifmask
) {
259 iif
= *(int*)RTA_DATA(tb
[RTA_IIF
]);
260 if ((iif
^filter
.iif
)&filter
.iifmask
)
263 if (filter
.oifmask
) {
266 oif
= *(int*)RTA_DATA(tb
[RTA_OIF
]);
267 if ((oif
^filter
.oif
)&filter
.oifmask
)
270 if (filter
.markmask
) {
273 mark
= *(int *)RTA_DATA(tb
[RTA_MARK
]);
274 if ((mark
^ filter
.mark
) & filter
.markmask
)
278 r
->rtm_family
== AF_INET6
&&
279 r
->rtm_dst_len
== 0 &&
280 r
->rtm_type
== RTN_UNREACHABLE
&&
282 *(int*)RTA_DATA(tb
[RTA_PRIORITY
]) == -1)
288 static void print_rtax_features(FILE *fp
, unsigned int features
)
290 unsigned int of
= features
;
292 if (features
& RTAX_FEATURE_ECN
) {
294 features
&= ~RTAX_FEATURE_ECN
;
298 fprintf(fp
, " 0x%x", of
);
301 int print_route(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
, void *arg
)
303 FILE *fp
= (FILE*)arg
;
304 struct rtmsg
*r
= NLMSG_DATA(n
);
305 int len
= n
->nlmsg_len
;
306 struct rtattr
* tb
[RTA_MAX
+1];
313 if (n
->nlmsg_type
!= RTM_NEWROUTE
&& n
->nlmsg_type
!= RTM_DELROUTE
) {
314 fprintf(stderr
, "Not a route: %08x %08x %08x\n",
315 n
->nlmsg_len
, n
->nlmsg_type
, n
->nlmsg_flags
);
318 if (filter
.flushb
&& n
->nlmsg_type
!= RTM_NEWROUTE
)
320 len
-= NLMSG_LENGTH(sizeof(*r
));
322 fprintf(stderr
, "BUG: wrong nlmsg len %d\n", len
);
326 host_len
= af_bit_len(r
->rtm_family
);
328 parse_rtattr(tb
, RTA_MAX
, RTM_RTA(r
), len
);
329 table
= rtm_get_table(r
, tb
);
331 if (!filter_nlmsg(n
, tb
, host_len
))
336 if (NLMSG_ALIGN(filter
.flushp
) + n
->nlmsg_len
> filter
.flushe
) {
340 fn
= (struct nlmsghdr
*)(filter
.flushb
+ NLMSG_ALIGN(filter
.flushp
));
341 memcpy(fn
, n
, n
->nlmsg_len
);
342 fn
->nlmsg_type
= RTM_DELROUTE
;
343 fn
->nlmsg_flags
= NLM_F_REQUEST
;
344 fn
->nlmsg_seq
= ++rth
.seq
;
345 filter
.flushp
= (((char*)fn
) + n
->nlmsg_len
) - filter
.flushb
;
351 if (n
->nlmsg_type
== RTM_DELROUTE
)
352 fprintf(fp
, "Deleted ");
353 if ((r
->rtm_type
!= RTN_UNICAST
|| show_details
> 0) && !filter
.type
)
354 fprintf(fp
, "%s ", rtnl_rtntype_n2a(r
->rtm_type
, b1
, sizeof(b1
)));
357 if (r
->rtm_dst_len
!= host_len
) {
358 fprintf(fp
, "%s/%u ", rt_addr_n2a(r
->rtm_family
,
359 RTA_PAYLOAD(tb
[RTA_DST
]),
360 RTA_DATA(tb
[RTA_DST
]),
365 fprintf(fp
, "%s ", format_host(r
->rtm_family
,
366 RTA_PAYLOAD(tb
[RTA_DST
]),
367 RTA_DATA(tb
[RTA_DST
]),
371 } else if (r
->rtm_dst_len
) {
372 fprintf(fp
, "0/%d ", r
->rtm_dst_len
);
374 fprintf(fp
, "default ");
377 if (r
->rtm_src_len
!= host_len
) {
378 fprintf(fp
, "from %s/%u ", rt_addr_n2a(r
->rtm_family
,
379 RTA_PAYLOAD(tb
[RTA_SRC
]),
380 RTA_DATA(tb
[RTA_SRC
]),
385 fprintf(fp
, "from %s ", format_host(r
->rtm_family
,
386 RTA_PAYLOAD(tb
[RTA_SRC
]),
387 RTA_DATA(tb
[RTA_SRC
]),
391 } else if (r
->rtm_src_len
) {
392 fprintf(fp
, "from 0/%u ", r
->rtm_src_len
);
394 if (tb
[RTA_NEWDST
]) {
395 fprintf(fp
, "as to %s ", format_host(r
->rtm_family
,
396 RTA_PAYLOAD(tb
[RTA_NEWDST
]),
397 RTA_DATA(tb
[RTA_NEWDST
]),
401 if (r
->rtm_tos
&& filter
.tosmask
!= -1) {
403 fprintf(fp
, "tos %s ", rtnl_dsfield_n2a(r
->rtm_tos
, b1
, sizeof(b1
)));
406 if (tb
[RTA_GATEWAY
] && filter
.rvia
.bitlen
!= host_len
) {
407 fprintf(fp
, "via %s ",
408 format_host(r
->rtm_family
,
409 RTA_PAYLOAD(tb
[RTA_GATEWAY
]),
410 RTA_DATA(tb
[RTA_GATEWAY
]),
411 abuf
, sizeof(abuf
)));
414 size_t len
= RTA_PAYLOAD(tb
[RTA_VIA
]) - 2;
415 struct rtvia
*via
= RTA_DATA(tb
[RTA_VIA
]);
416 fprintf(fp
, "via %s %s ",
417 family_name(via
->rtvia_family
),
418 format_host(via
->rtvia_family
, len
, via
->rtvia_addr
,
419 abuf
, sizeof(abuf
)));
421 if (tb
[RTA_OIF
] && filter
.oifmask
!= -1)
422 fprintf(fp
, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb
[RTA_OIF
])));
424 if (!(r
->rtm_flags
&RTM_F_CLONED
)) {
425 if ((table
!= RT_TABLE_MAIN
|| show_details
> 0) && !filter
.tb
)
426 fprintf(fp
, " table %s ", rtnl_rttable_n2a(table
, b1
, sizeof(b1
)));
427 if ((r
->rtm_protocol
!= RTPROT_BOOT
|| show_details
> 0) && filter
.protocolmask
!= -1)
428 fprintf(fp
, " proto %s ", rtnl_rtprot_n2a(r
->rtm_protocol
, b1
, sizeof(b1
)));
429 if ((r
->rtm_scope
!= RT_SCOPE_UNIVERSE
|| show_details
> 0) && filter
.scopemask
!= -1)
430 fprintf(fp
, " scope %s ", rtnl_rtscope_n2a(r
->rtm_scope
, b1
, sizeof(b1
)));
432 if (tb
[RTA_PREFSRC
] && filter
.rprefsrc
.bitlen
!= host_len
) {
433 /* Do not use format_host(). It is our local addr
434 and symbolic name will not be useful.
436 fprintf(fp
, " src %s ",
437 rt_addr_n2a(r
->rtm_family
,
438 RTA_PAYLOAD(tb
[RTA_PREFSRC
]),
439 RTA_DATA(tb
[RTA_PREFSRC
]),
440 abuf
, sizeof(abuf
)));
442 if (tb
[RTA_PRIORITY
])
443 fprintf(fp
, " metric %u ", rta_getattr_u32(tb
[RTA_PRIORITY
]));
444 if (r
->rtm_flags
& RTNH_F_DEAD
)
445 fprintf(fp
, "dead ");
446 if (r
->rtm_flags
& RTNH_F_ONLINK
)
447 fprintf(fp
, "onlink ");
448 if (r
->rtm_flags
& RTNH_F_PERVASIVE
)
449 fprintf(fp
, "pervasive ");
450 if (r
->rtm_flags
& RTNH_F_EXTERNAL
)
451 fprintf(fp
, "offload ");
452 if (r
->rtm_flags
& RTM_F_NOTIFY
)
453 fprintf(fp
, "notify ");
455 unsigned int mark
= *(unsigned int*)RTA_DATA(tb
[RTA_MARK
]);
458 fprintf(fp
, " mark 0x%x", mark
);
460 fprintf(fp
, " mark %u", mark
);
464 if (tb
[RTA_FLOW
] && filter
.realmmask
!= ~0U) {
465 __u32 to
= rta_getattr_u32(tb
[RTA_FLOW
]);
468 fprintf(fp
, "realm%s ", from
? "s" : "");
471 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
474 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
476 if ((r
->rtm_flags
&RTM_F_CLONED
) && r
->rtm_family
== AF_INET
) {
477 __u32 flags
= r
->rtm_flags
&~0xFFFF;
480 fprintf(fp
, "%s cache ", _SL_
);
482 #define PRTFL(fl,flname) if (flags&RTCF_##fl) { \
483 flags &= ~RTCF_##fl; \
484 fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \
486 PRTFL(LOCAL
, "local");
487 PRTFL(REJECT
, "reject");
488 PRTFL(MULTICAST
, "mc");
489 PRTFL(BROADCAST
, "brd");
490 PRTFL(DNAT
, "dst-nat");
491 PRTFL(SNAT
, "src-nat");
493 PRTFL(DIRECTDST
, "dst-direct");
494 PRTFL(DIRECTSRC
, "src-direct");
495 PRTFL(REDIRECTED
, "redirected");
496 PRTFL(DOREDIRECT
, "redirect");
497 PRTFL(FAST
, "fastroute");
498 PRTFL(NOTIFY
, "notify");
499 PRTFL(TPROXY
, "proxy");
502 fprintf(fp
, "%s%x> ", first
? "<" : "", flags
);
503 if (tb
[RTA_CACHEINFO
]) {
504 struct rta_cacheinfo
*ci
= RTA_DATA(tb
[RTA_CACHEINFO
]);
507 if (ci
->rta_expires
!= 0)
508 fprintf(fp
, " expires %dsec", ci
->rta_expires
/hz
);
509 if (ci
->rta_error
!= 0)
510 fprintf(fp
, " error %d", ci
->rta_error
);
513 fprintf(fp
, " users %d", ci
->rta_clntref
);
514 if (ci
->rta_used
!= 0)
515 fprintf(fp
, " used %d", ci
->rta_used
);
516 if (ci
->rta_lastuse
!= 0)
517 fprintf(fp
, " age %dsec", ci
->rta_lastuse
/hz
);
520 fprintf(fp
, " ipid 0x%04x", ci
->rta_id
);
521 if (ci
->rta_ts
|| ci
->rta_tsage
)
522 fprintf(fp
, " ts 0x%x tsage %dsec",
523 ci
->rta_ts
, ci
->rta_tsage
);
525 } else if (r
->rtm_family
== AF_INET6
) {
526 struct rta_cacheinfo
*ci
= NULL
;
527 if (tb
[RTA_CACHEINFO
])
528 ci
= RTA_DATA(tb
[RTA_CACHEINFO
]);
529 if ((r
->rtm_flags
& RTM_F_CLONED
) || (ci
&& ci
->rta_expires
)) {
532 if (r
->rtm_flags
& RTM_F_CLONED
)
533 fprintf(fp
, "%s cache ", _SL_
);
535 fprintf(fp
, " expires %dsec", ci
->rta_expires
/hz
);
536 if (ci
->rta_error
!= 0)
537 fprintf(fp
, " error %d", ci
->rta_error
);
540 fprintf(fp
, " users %d", ci
->rta_clntref
);
541 if (ci
->rta_used
!= 0)
542 fprintf(fp
, " used %d", ci
->rta_used
);
543 if (ci
->rta_lastuse
!= 0)
544 fprintf(fp
, " age %dsec", ci
->rta_lastuse
/hz
);
547 if (ci
->rta_error
!= 0)
548 fprintf(fp
, " error %d", ci
->rta_error
);
551 if (tb
[RTA_METRICS
]) {
554 struct rtattr
*mxrta
[RTAX_MAX
+1];
556 parse_rtattr(mxrta
, RTAX_MAX
, RTA_DATA(tb
[RTA_METRICS
]),
557 RTA_PAYLOAD(tb
[RTA_METRICS
]));
558 if (mxrta
[RTAX_LOCK
])
559 mxlock
= *(unsigned*)RTA_DATA(mxrta
[RTAX_LOCK
]);
561 for (i
=2; i
<= RTAX_MAX
; i
++) {
564 if (mxrta
[i
] == NULL
)
567 if (i
< sizeof(mx_names
)/sizeof(char*) && mx_names
[i
])
568 fprintf(fp
, " %s", mx_names
[i
]);
570 fprintf(fp
, " metric %d", i
);
573 fprintf(fp
, " lock");
574 if (i
!= RTAX_CC_ALGO
)
575 val
= rta_getattr_u32(mxrta
[i
]);
579 print_rtax_features(fp
, val
);
586 fprintf(fp
, " %u", val
);
594 else if (i
== RTAX_RTTVAR
)
598 fprintf(fp
, " %gs", val
/1e3
);
600 fprintf(fp
, " %ums", val
);
603 fprintf(fp
, " %s", rta_getattr_str(mxrta
[i
]));
608 if (tb
[RTA_IIF
] && filter
.iifmask
!= -1) {
609 fprintf(fp
, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb
[RTA_IIF
])));
611 if (tb
[RTA_MULTIPATH
]) {
612 struct rtnexthop
*nh
= RTA_DATA(tb
[RTA_MULTIPATH
]);
615 len
= RTA_PAYLOAD(tb
[RTA_MULTIPATH
]);
618 if (len
< sizeof(*nh
))
620 if (nh
->rtnh_len
> len
)
622 if (r
->rtm_flags
&RTM_F_CLONED
&& r
->rtm_type
== RTN_MULTICAST
) {
624 fprintf(fp
, " Oifs:");
628 fprintf(fp
, "%s\tnexthop", _SL_
);
629 if (nh
->rtnh_len
> sizeof(*nh
)) {
630 parse_rtattr(tb
, RTA_MAX
, RTNH_DATA(nh
), nh
->rtnh_len
- sizeof(*nh
));
631 if (tb
[RTA_GATEWAY
]) {
632 fprintf(fp
, " via %s ",
633 format_host(r
->rtm_family
,
634 RTA_PAYLOAD(tb
[RTA_GATEWAY
]),
635 RTA_DATA(tb
[RTA_GATEWAY
]),
636 abuf
, sizeof(abuf
)));
639 size_t len
= RTA_PAYLOAD(tb
[RTA_VIA
]) - 2;
640 struct rtvia
*via
= RTA_DATA(tb
[RTA_VIA
]);
641 fprintf(fp
, "via %s %s ",
642 family_name(via
->rtvia_family
),
643 format_host(via
->rtvia_family
, len
, via
->rtvia_addr
,
644 abuf
, sizeof(abuf
)));
647 __u32 to
= rta_getattr_u32(tb
[RTA_FLOW
]);
650 fprintf(fp
, " realm%s ", from
? "s" : "");
653 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
656 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
659 if (r
->rtm_flags
&RTM_F_CLONED
&& r
->rtm_type
== RTN_MULTICAST
) {
660 fprintf(fp
, " %s", ll_index_to_name(nh
->rtnh_ifindex
));
661 if (nh
->rtnh_hops
!= 1)
662 fprintf(fp
, "(ttl>%d)", nh
->rtnh_hops
);
664 fprintf(fp
, " dev %s", ll_index_to_name(nh
->rtnh_ifindex
));
665 fprintf(fp
, " weight %d", nh
->rtnh_hops
+1);
667 if (nh
->rtnh_flags
& RTNH_F_DEAD
)
668 fprintf(fp
, " dead");
669 if (nh
->rtnh_flags
& RTNH_F_ONLINK
)
670 fprintf(fp
, " onlink");
671 if (nh
->rtnh_flags
& RTNH_F_PERVASIVE
)
672 fprintf(fp
, " pervasive");
673 len
-= NLMSG_ALIGN(nh
->rtnh_len
);
678 unsigned int pref
= rta_getattr_u8(tb
[RTA_PREF
]);
679 fprintf(fp
, " pref ");
682 case ICMPV6_ROUTER_PREF_LOW
:
685 case ICMPV6_ROUTER_PREF_MEDIUM
:
686 fprintf(fp
, "medium");
688 case ICMPV6_ROUTER_PREF_HIGH
:
692 fprintf(fp
, "%u", pref
);
701 static int parse_one_nh(struct rtmsg
*r
, struct rtattr
*rta
,
702 struct rtnexthop
*rtnh
,
703 int *argcp
, char ***argvp
)
706 char **argv
= *argvp
;
708 while (++argv
, --argc
> 0) {
709 if (strcmp(*argv
, "via") == 0) {
713 family
= read_family(*argv
);
714 if (family
== AF_UNSPEC
)
715 family
= r
->rtm_family
;
718 get_addr(&addr
, *argv
, family
);
719 if (r
->rtm_family
== AF_UNSPEC
)
720 r
->rtm_family
= addr
.family
;
721 if (addr
.family
== r
->rtm_family
) {
722 rta_addattr_l(rta
, 4096, RTA_GATEWAY
, &addr
.data
, addr
.bytelen
);
723 rtnh
->rtnh_len
+= sizeof(struct rtattr
) + addr
.bytelen
;
725 rta_addattr_l(rta
, 4096, RTA_VIA
, &addr
.family
, addr
.bytelen
+2);
726 rtnh
->rtnh_len
+= sizeof(struct rtattr
) + addr
.bytelen
+2;
728 } else if (strcmp(*argv
, "dev") == 0) {
730 if ((rtnh
->rtnh_ifindex
= ll_name_to_index(*argv
)) == 0) {
731 fprintf(stderr
, "Cannot find device \"%s\"\n", *argv
);
734 } else if (strcmp(*argv
, "weight") == 0) {
737 if (get_unsigned(&w
, *argv
, 0) || w
== 0 || w
> 256)
738 invarg("\"weight\" is invalid\n", *argv
);
739 rtnh
->rtnh_hops
= w
- 1;
740 } else if (strcmp(*argv
, "onlink") == 0) {
741 rtnh
->rtnh_flags
|= RTNH_F_ONLINK
;
742 } else if (matches(*argv
, "realms") == 0) {
745 if (get_rt_realms(&realm
, *argv
))
746 invarg("\"realm\" value is invalid\n", *argv
);
747 rta_addattr32(rta
, 4096, RTA_FLOW
, realm
);
748 rtnh
->rtnh_len
+= sizeof(struct rtattr
) + 4;
757 static int parse_nexthops(struct nlmsghdr
*n
, struct rtmsg
*r
,
758 int argc
, char **argv
)
761 struct rtattr
*rta
= (void*)buf
;
762 struct rtnexthop
*rtnh
;
764 rta
->rta_type
= RTA_MULTIPATH
;
765 rta
->rta_len
= RTA_LENGTH(0);
766 rtnh
= RTA_DATA(rta
);
769 if (strcmp(*argv
, "nexthop") != 0) {
770 fprintf(stderr
, "Error: \"nexthop\" or end of line is expected instead of \"%s\"\n", *argv
);
774 fprintf(stderr
, "Error: unexpected end of line after \"nexthop\"\n");
777 memset(rtnh
, 0, sizeof(*rtnh
));
778 rtnh
->rtnh_len
= sizeof(*rtnh
);
779 rta
->rta_len
+= rtnh
->rtnh_len
;
780 parse_one_nh(r
, rta
, rtnh
, &argc
, &argv
);
781 rtnh
= RTNH_NEXT(rtnh
);
784 if (rta
->rta_len
> RTA_LENGTH(0))
785 addattr_l(n
, 1024, RTA_MULTIPATH
, RTA_DATA(rta
), RTA_PAYLOAD(rta
));
789 static int iproute_modify(int cmd
, unsigned flags
, int argc
, char **argv
)
797 struct rtattr
* mxrta
= (void*)mxbuf
;
807 memset(&req
, 0, sizeof(req
));
809 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
810 req
.n
.nlmsg_flags
= NLM_F_REQUEST
|flags
;
811 req
.n
.nlmsg_type
= cmd
;
812 req
.r
.rtm_family
= preferred_family
;
813 req
.r
.rtm_table
= RT_TABLE_MAIN
;
814 req
.r
.rtm_scope
= RT_SCOPE_NOWHERE
;
816 if (cmd
!= RTM_DELROUTE
) {
817 req
.r
.rtm_protocol
= RTPROT_BOOT
;
818 req
.r
.rtm_scope
= RT_SCOPE_UNIVERSE
;
819 req
.r
.rtm_type
= RTN_UNICAST
;
822 mxrta
->rta_type
= RTA_METRICS
;
823 mxrta
->rta_len
= RTA_LENGTH(0);
826 if (strcmp(*argv
, "src") == 0) {
829 get_addr(&addr
, *argv
, req
.r
.rtm_family
);
830 if (req
.r
.rtm_family
== AF_UNSPEC
)
831 req
.r
.rtm_family
= addr
.family
;
832 addattr_l(&req
.n
, sizeof(req
), RTA_PREFSRC
, &addr
.data
, addr
.bytelen
);
833 } else if (strcmp(*argv
, "as") == 0) {
836 if (strcmp(*argv
, "to") == 0) {
839 get_addr(&addr
, *argv
, req
.r
.rtm_family
);
840 if (req
.r
.rtm_family
== AF_UNSPEC
)
841 req
.r
.rtm_family
= addr
.family
;
842 addattr_l(&req
.n
, sizeof(req
), RTA_NEWDST
, &addr
.data
, addr
.bytelen
);
843 } else if (strcmp(*argv
, "via") == 0) {
848 family
= read_family(*argv
);
849 if (family
== AF_UNSPEC
)
850 family
= req
.r
.rtm_family
;
853 get_addr(&addr
, *argv
, family
);
854 if (req
.r
.rtm_family
== AF_UNSPEC
)
855 req
.r
.rtm_family
= addr
.family
;
856 if (addr
.family
== req
.r
.rtm_family
)
857 addattr_l(&req
.n
, sizeof(req
), RTA_GATEWAY
, &addr
.data
, addr
.bytelen
);
859 addattr_l(&req
.n
, sizeof(req
), RTA_VIA
, &addr
.family
, addr
.bytelen
+2);
860 } else if (strcmp(*argv
, "from") == 0) {
863 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
864 if (req
.r
.rtm_family
== AF_UNSPEC
)
865 req
.r
.rtm_family
= addr
.family
;
867 addattr_l(&req
.n
, sizeof(req
), RTA_SRC
, &addr
.data
, addr
.bytelen
);
868 req
.r
.rtm_src_len
= addr
.bitlen
;
869 } else if (strcmp(*argv
, "tos") == 0 ||
870 matches(*argv
, "dsfield") == 0) {
873 if (rtnl_dsfield_a2n(&tos
, *argv
))
874 invarg("\"tos\" value is invalid\n", *argv
);
876 } else if (matches(*argv
, "metric") == 0 ||
877 matches(*argv
, "priority") == 0 ||
878 strcmp(*argv
, "preference") == 0) {
881 if (get_u32(&metric
, *argv
, 0))
882 invarg("\"metric\" value is invalid\n", *argv
);
883 addattr32(&req
.n
, sizeof(req
), RTA_PRIORITY
, metric
);
884 } else if (strcmp(*argv
, "scope") == 0) {
887 if (rtnl_rtscope_a2n(&scope
, *argv
))
888 invarg("invalid \"scope\" value\n", *argv
);
889 req
.r
.rtm_scope
= scope
;
891 } else if (strcmp(*argv
, "mtu") == 0) {
894 if (strcmp(*argv
, "lock") == 0) {
895 mxlock
|= (1<<RTAX_MTU
);
898 if (get_unsigned(&mtu
, *argv
, 0))
899 invarg("\"mtu\" value is invalid\n", *argv
);
900 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_MTU
, mtu
);
901 } else if (strcmp(*argv
, "hoplimit") == 0) {
904 if (strcmp(*argv
, "lock") == 0) {
905 mxlock
|= (1<<RTAX_HOPLIMIT
);
908 if (get_unsigned(&hoplimit
, *argv
, 0))
909 invarg("\"hoplimit\" value is invalid\n", *argv
);
910 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_HOPLIMIT
, hoplimit
);
911 } else if (strcmp(*argv
, "advmss") == 0) {
914 if (strcmp(*argv
, "lock") == 0) {
915 mxlock
|= (1<<RTAX_ADVMSS
);
918 if (get_unsigned(&mss
, *argv
, 0))
919 invarg("\"mss\" value is invalid\n", *argv
);
920 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_ADVMSS
, mss
);
921 } else if (matches(*argv
, "reordering") == 0) {
924 if (strcmp(*argv
, "lock") == 0) {
925 mxlock
|= (1<<RTAX_REORDERING
);
928 if (get_unsigned(&reord
, *argv
, 0))
929 invarg("\"reordering\" value is invalid\n", *argv
);
930 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_REORDERING
, reord
);
931 } else if (strcmp(*argv
, "rtt") == 0) {
934 if (strcmp(*argv
, "lock") == 0) {
935 mxlock
|= (1<<RTAX_RTT
);
938 if (get_time_rtt(&rtt
, *argv
, &raw
))
939 invarg("\"rtt\" value is invalid\n", *argv
);
940 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_RTT
,
941 (raw
) ? rtt
: rtt
* 8);
942 } else if (strcmp(*argv
, "rto_min") == 0) {
945 mxlock
|= (1<<RTAX_RTO_MIN
);
946 if (get_time_rtt(&rto_min
, *argv
, &raw
))
947 invarg("\"rto_min\" value is invalid\n",
949 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_RTO_MIN
,
951 } else if (matches(*argv
, "window") == 0) {
954 if (strcmp(*argv
, "lock") == 0) {
955 mxlock
|= (1<<RTAX_WINDOW
);
958 if (get_unsigned(&win
, *argv
, 0))
959 invarg("\"window\" value is invalid\n", *argv
);
960 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_WINDOW
, win
);
961 } else if (matches(*argv
, "cwnd") == 0) {
964 if (strcmp(*argv
, "lock") == 0) {
965 mxlock
|= (1<<RTAX_CWND
);
968 if (get_unsigned(&win
, *argv
, 0))
969 invarg("\"cwnd\" value is invalid\n", *argv
);
970 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_CWND
, win
);
971 } else if (matches(*argv
, "initcwnd") == 0) {
974 if (strcmp(*argv
, "lock") == 0) {
975 mxlock
|= (1<<RTAX_INITCWND
);
978 if (get_unsigned(&win
, *argv
, 0))
979 invarg("\"initcwnd\" value is invalid\n", *argv
);
980 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_INITCWND
, win
);
981 } else if (matches(*argv
, "initrwnd") == 0) {
984 if (strcmp(*argv
, "lock") == 0) {
985 mxlock
|= (1<<RTAX_INITRWND
);
988 if (get_unsigned(&win
, *argv
, 0))
989 invarg("\"initrwnd\" value is invalid\n", *argv
);
990 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_INITRWND
, win
);
991 } else if (matches(*argv
, "features") == 0) {
992 unsigned int features
= 0;
997 if (strcmp(*argv
, "ecn") == 0)
998 features
|= RTAX_FEATURE_ECN
;
1000 invarg("\"features\" value not valid\n", *argv
);
1004 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_FEATURES
, features
);
1005 } else if (matches(*argv
, "quickack") == 0) {
1008 if (get_unsigned(&quickack
, *argv
, 0))
1009 invarg("\"quickack\" value is invalid\n", *argv
);
1010 if (quickack
!= 1 && quickack
!= 0)
1011 invarg("\"quickack\" value should be 0 or 1\n", *argv
);
1012 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_QUICKACK
, quickack
);
1013 } else if (matches(*argv
, "congctl") == 0) {
1015 if (strcmp(*argv
, "lock") == 0) {
1016 mxlock
|= 1 << RTAX_CC_ALGO
;
1019 rta_addattr_l(mxrta
, sizeof(mxbuf
), RTAX_CC_ALGO
, *argv
,
1021 } else if (matches(*argv
, "rttvar") == 0) {
1024 if (strcmp(*argv
, "lock") == 0) {
1025 mxlock
|= (1<<RTAX_RTTVAR
);
1028 if (get_time_rtt(&win
, *argv
, &raw
))
1029 invarg("\"rttvar\" value is invalid\n", *argv
);
1030 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_RTTVAR
,
1031 (raw
) ? win
: win
* 4);
1032 } else if (matches(*argv
, "ssthresh") == 0) {
1035 if (strcmp(*argv
, "lock") == 0) {
1036 mxlock
|= (1<<RTAX_SSTHRESH
);
1039 if (get_unsigned(&win
, *argv
, 0))
1040 invarg("\"ssthresh\" value is invalid\n", *argv
);
1041 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_SSTHRESH
, win
);
1042 } else if (matches(*argv
, "realms") == 0) {
1045 if (get_rt_realms(&realm
, *argv
))
1046 invarg("\"realm\" value is invalid\n", *argv
);
1047 addattr32(&req
.n
, sizeof(req
), RTA_FLOW
, realm
);
1048 } else if (strcmp(*argv
, "onlink") == 0) {
1049 req
.r
.rtm_flags
|= RTNH_F_ONLINK
;
1050 } else if (strcmp(*argv
, "nexthop") == 0) {
1053 } else if (matches(*argv
, "protocol") == 0) {
1056 if (rtnl_rtprot_a2n(&prot
, *argv
))
1057 invarg("\"protocol\" value is invalid\n", *argv
);
1058 req
.r
.rtm_protocol
= prot
;
1059 } else if (matches(*argv
, "table") == 0) {
1062 if (rtnl_rttable_a2n(&tid
, *argv
))
1063 invarg("\"table\" value is invalid\n", *argv
);
1065 req
.r
.rtm_table
= tid
;
1067 req
.r
.rtm_table
= RT_TABLE_UNSPEC
;
1068 addattr32(&req
.n
, sizeof(req
), RTA_TABLE
, tid
);
1071 } else if (strcmp(*argv
, "dev") == 0 ||
1072 strcmp(*argv
, "oif") == 0) {
1075 } else if (matches(*argv
, "pref") == 0) {
1078 if (strcmp(*argv
, "low") == 0)
1079 pref
= ICMPV6_ROUTER_PREF_LOW
;
1080 else if (strcmp(*argv
, "medium") == 0)
1081 pref
= ICMPV6_ROUTER_PREF_MEDIUM
;
1082 else if (strcmp(*argv
, "high") == 0)
1083 pref
= ICMPV6_ROUTER_PREF_HIGH
;
1084 else if (get_u8(&pref
, *argv
, 0))
1085 invarg("\"pref\" value is invalid\n", *argv
);
1086 addattr8(&req
.n
, sizeof(req
), RTA_PREF
, pref
);
1091 if (strcmp(*argv
, "to") == 0) {
1094 if ((**argv
< '0' || **argv
> '9') &&
1095 rtnl_rtntype_a2n(&type
, *argv
) == 0) {
1097 req
.r
.rtm_type
= type
;
1100 if (matches(*argv
, "help") == 0)
1103 duparg2("to", *argv
);
1104 get_prefix(&dst
, *argv
, req
.r
.rtm_family
);
1105 if (req
.r
.rtm_family
== AF_UNSPEC
)
1106 req
.r
.rtm_family
= dst
.family
;
1107 req
.r
.rtm_dst_len
= dst
.bitlen
;
1110 addattr_l(&req
.n
, sizeof(req
), RTA_DST
, &dst
.data
, dst
.bytelen
);
1122 if ((idx
= ll_name_to_index(d
)) == 0) {
1123 fprintf(stderr
, "Cannot find device \"%s\"\n", d
);
1126 addattr32(&req
.n
, sizeof(req
), RTA_OIF
, idx
);
1130 if (mxrta
->rta_len
> RTA_LENGTH(0)) {
1132 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_LOCK
, mxlock
);
1133 addattr_l(&req
.n
, sizeof(req
), RTA_METRICS
, RTA_DATA(mxrta
), RTA_PAYLOAD(mxrta
));
1137 parse_nexthops(&req
.n
, &req
.r
, argc
, argv
);
1140 if (req
.r
.rtm_type
== RTN_LOCAL
||
1141 req
.r
.rtm_type
== RTN_BROADCAST
||
1142 req
.r
.rtm_type
== RTN_NAT
||
1143 req
.r
.rtm_type
== RTN_ANYCAST
)
1144 req
.r
.rtm_table
= RT_TABLE_LOCAL
;
1147 if (req
.r
.rtm_type
== RTN_LOCAL
||
1148 req
.r
.rtm_type
== RTN_NAT
)
1149 req
.r
.rtm_scope
= RT_SCOPE_HOST
;
1150 else if (req
.r
.rtm_type
== RTN_BROADCAST
||
1151 req
.r
.rtm_type
== RTN_MULTICAST
||
1152 req
.r
.rtm_type
== RTN_ANYCAST
)
1153 req
.r
.rtm_scope
= RT_SCOPE_LINK
;
1154 else if (req
.r
.rtm_type
== RTN_UNICAST
||
1155 req
.r
.rtm_type
== RTN_UNSPEC
) {
1156 if (cmd
== RTM_DELROUTE
)
1157 req
.r
.rtm_scope
= RT_SCOPE_NOWHERE
;
1158 else if (!gw_ok
&& !nhs_ok
)
1159 req
.r
.rtm_scope
= RT_SCOPE_LINK
;
1163 if (req
.r
.rtm_family
== AF_UNSPEC
)
1164 req
.r
.rtm_family
= AF_INET
;
1166 if (rtnl_talk(&rth
, &req
.n
, NULL
, 0) < 0)
1172 static int rtnl_rtcache_request(struct rtnl_handle
*rth
, int family
)
1175 struct nlmsghdr nlh
;
1178 struct sockaddr_nl nladdr
;
1180 memset(&nladdr
, 0, sizeof(nladdr
));
1181 memset(&req
, 0, sizeof(req
));
1182 nladdr
.nl_family
= AF_NETLINK
;
1184 req
.nlh
.nlmsg_len
= sizeof(req
);
1185 req
.nlh
.nlmsg_type
= RTM_GETROUTE
;
1186 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
|NLM_F_REQUEST
;
1187 req
.nlh
.nlmsg_pid
= 0;
1188 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
1189 req
.rtm
.rtm_family
= family
;
1190 req
.rtm
.rtm_flags
|= RTM_F_CLONED
;
1192 return sendto(rth
->fd
, (void*)&req
, sizeof(req
), 0, (struct sockaddr
*)&nladdr
, sizeof(nladdr
));
1195 static int iproute_flush_cache(void)
1197 #define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
1200 int flush_fd
= open (ROUTE_FLUSH_PATH
, O_WRONLY
);
1201 char *buffer
= "-1";
1204 fprintf (stderr
, "Cannot open \"%s\"\n", ROUTE_FLUSH_PATH
);
1208 len
= strlen (buffer
);
1210 if ((write (flush_fd
, (void *)buffer
, len
)) < len
) {
1211 fprintf (stderr
, "Cannot flush routing cache\n");
1219 static __u32 route_dump_magic
= 0x45311224;
1221 static int save_route(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
,
1225 int len
= n
->nlmsg_len
;
1226 struct rtmsg
*r
= NLMSG_DATA(n
);
1227 struct rtattr
*tb
[RTA_MAX
+1];
1230 host_len
= af_bit_len(r
->rtm_family
);
1231 len
-= NLMSG_LENGTH(sizeof(*r
));
1232 parse_rtattr(tb
, RTA_MAX
, RTM_RTA(r
), len
);
1234 if (!filter_nlmsg(n
, tb
, host_len
))
1237 ret
= write(STDOUT_FILENO
, n
, n
->nlmsg_len
);
1238 if ((ret
> 0) && (ret
!= n
->nlmsg_len
)) {
1239 fprintf(stderr
, "Short write while saving nlmsg\n");
1243 return ret
== n
->nlmsg_len
? 0 : ret
;
1246 static int save_route_prep(void)
1250 if (isatty(STDOUT_FILENO
)) {
1251 fprintf(stderr
, "Not sending a binary stream to stdout\n");
1255 ret
= write(STDOUT_FILENO
, &route_dump_magic
, sizeof(route_dump_magic
));
1256 if (ret
!= sizeof(route_dump_magic
)) {
1257 fprintf(stderr
, "Can't write magic to dump file\n");
1264 static int iproute_list_flush_or_save(int argc
, char **argv
, int action
)
1266 int do_ipv6
= preferred_family
;
1269 unsigned int mark
= 0;
1270 rtnl_filter_t filter_fn
;
1272 if (action
== IPROUTE_SAVE
) {
1273 if (save_route_prep())
1276 filter_fn
= save_route
;
1278 filter_fn
= print_route
;
1280 iproute_reset_filter(0);
1281 filter
.tb
= RT_TABLE_MAIN
;
1283 if ((action
== IPROUTE_FLUSH
) && argc
<= 0) {
1284 fprintf(stderr
, "\"ip route flush\" requires arguments.\n");
1289 if (matches(*argv
, "table") == 0) {
1292 if (rtnl_rttable_a2n(&tid
, *argv
)) {
1293 if (strcmp(*argv
, "all") == 0) {
1295 } else if (strcmp(*argv
, "cache") == 0) {
1297 } else if (strcmp(*argv
, "help") == 0) {
1300 invarg("table id value is invalid\n", *argv
);
1304 } else if (matches(*argv
, "cached") == 0 ||
1305 matches(*argv
, "cloned") == 0) {
1307 } else if (strcmp(*argv
, "tos") == 0 ||
1308 matches(*argv
, "dsfield") == 0) {
1311 if (rtnl_dsfield_a2n(&tos
, *argv
))
1312 invarg("TOS value is invalid\n", *argv
);
1314 filter
.tosmask
= -1;
1315 } else if (matches(*argv
, "protocol") == 0) {
1318 filter
.protocolmask
= -1;
1319 if (rtnl_rtprot_a2n(&prot
, *argv
)) {
1320 if (strcmp(*argv
, "all") != 0)
1321 invarg("invalid \"protocol\"\n", *argv
);
1323 filter
.protocolmask
= 0;
1325 filter
.protocol
= prot
;
1326 } else if (matches(*argv
, "scope") == 0) {
1329 filter
.scopemask
= -1;
1330 if (rtnl_rtscope_a2n(&scope
, *argv
)) {
1331 if (strcmp(*argv
, "all") != 0)
1332 invarg("invalid \"scope\"\n", *argv
);
1333 scope
= RT_SCOPE_NOWHERE
;
1334 filter
.scopemask
= 0;
1336 filter
.scope
= scope
;
1337 } else if (matches(*argv
, "type") == 0) {
1340 filter
.typemask
= -1;
1341 if (rtnl_rtntype_a2n(&type
, *argv
))
1342 invarg("node type value is invalid\n", *argv
);
1344 } else if (strcmp(*argv
, "dev") == 0 ||
1345 strcmp(*argv
, "oif") == 0) {
1348 } else if (strcmp(*argv
, "iif") == 0) {
1351 } else if (strcmp(*argv
, "mark") == 0) {
1353 get_unsigned(&mark
, *argv
, 0);
1354 filter
.markmask
= -1;
1355 } else if (strcmp(*argv
, "via") == 0) {
1358 family
= read_family(*argv
);
1359 if (family
== AF_UNSPEC
)
1363 get_prefix(&filter
.rvia
, *argv
, family
);
1364 } else if (strcmp(*argv
, "src") == 0) {
1366 get_prefix(&filter
.rprefsrc
, *argv
, do_ipv6
);
1367 } else if (matches(*argv
, "realms") == 0) {
1370 if (get_rt_realms(&realm
, *argv
))
1371 invarg("invalid realms\n", *argv
);
1372 filter
.realm
= realm
;
1373 filter
.realmmask
= ~0U;
1374 if ((filter
.realm
&0xFFFF) == 0 &&
1375 (*argv
)[strlen(*argv
) - 1] == '/')
1376 filter
.realmmask
&= ~0xFFFF;
1377 if ((filter
.realm
&0xFFFF0000U
) == 0 &&
1378 (strchr(*argv
, '/') == NULL
||
1380 filter
.realmmask
&= ~0xFFFF0000U
;
1381 } else if (matches(*argv
, "from") == 0) {
1383 if (matches(*argv
, "root") == 0) {
1385 get_prefix(&filter
.rsrc
, *argv
, do_ipv6
);
1386 } else if (matches(*argv
, "match") == 0) {
1388 get_prefix(&filter
.msrc
, *argv
, do_ipv6
);
1390 if (matches(*argv
, "exact") == 0) {
1393 get_prefix(&filter
.msrc
, *argv
, do_ipv6
);
1394 filter
.rsrc
= filter
.msrc
;
1397 if (matches(*argv
, "to") == 0) {
1400 if (matches(*argv
, "root") == 0) {
1402 get_prefix(&filter
.rdst
, *argv
, do_ipv6
);
1403 } else if (matches(*argv
, "match") == 0) {
1405 get_prefix(&filter
.mdst
, *argv
, do_ipv6
);
1407 if (matches(*argv
, "exact") == 0) {
1410 get_prefix(&filter
.mdst
, *argv
, do_ipv6
);
1411 filter
.rdst
= filter
.mdst
;
1417 if (do_ipv6
== AF_UNSPEC
&& filter
.tb
)
1424 if ((idx
= ll_name_to_index(id
)) == 0) {
1425 fprintf(stderr
, "Cannot find device \"%s\"\n", id
);
1429 filter
.iifmask
= -1;
1432 if ((idx
= ll_name_to_index(od
)) == 0) {
1433 fprintf(stderr
, "Cannot find device \"%s\"\n", od
);
1437 filter
.oifmask
= -1;
1442 if (action
== IPROUTE_FLUSH
) {
1444 char flushb
[4096-512];
1445 time_t start
= time(0);
1447 if (filter
.cloned
) {
1448 if (do_ipv6
!= AF_INET6
) {
1449 iproute_flush_cache();
1451 printf("*** IPv4 routing cache is flushed.\n");
1453 if (do_ipv6
== AF_INET
)
1457 filter
.flushb
= flushb
;
1459 filter
.flushe
= sizeof(flushb
);
1462 if (rtnl_wilddump_request(&rth
, do_ipv6
, RTM_GETROUTE
) < 0) {
1463 perror("Cannot send dump request");
1467 if (rtnl_dump_filter(&rth
, filter_fn
, stdout
) < 0) {
1468 fprintf(stderr
, "Flush terminated\n");
1471 if (filter
.flushed
== 0) {
1473 if (round
== 0 && (!filter
.cloned
|| do_ipv6
== AF_INET6
))
1474 printf("Nothing to flush.\n");
1476 printf("*** Flush is complete after %d round%s ***\n", round
, round
>1?"s":"");
1482 if (flush_update() < 0)
1485 if (time(0) - start
> 30) {
1486 printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
1487 (long)(time(0) - start
), filter
.flushed
);
1492 printf("\n*** Round %d, deleting %d entries ***\n", round
, filter
.flushed
);
1498 if (!filter
.cloned
) {
1499 if (rtnl_wilddump_request(&rth
, do_ipv6
, RTM_GETROUTE
) < 0) {
1500 perror("Cannot send dump request");
1504 if (rtnl_rtcache_request(&rth
, do_ipv6
) < 0) {
1505 perror("Cannot send dump request");
1510 if (rtnl_dump_filter(&rth
, filter_fn
, stdout
) < 0) {
1511 fprintf(stderr
, "Dump terminated\n");
1519 static int iproute_get(int argc
, char **argv
)
1530 unsigned int mark
= 0;
1532 memset(&req
, 0, sizeof(req
));
1534 iproute_reset_filter(0);
1537 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
1538 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
1539 req
.n
.nlmsg_type
= RTM_GETROUTE
;
1540 req
.r
.rtm_family
= preferred_family
;
1541 req
.r
.rtm_table
= 0;
1542 req
.r
.rtm_protocol
= 0;
1543 req
.r
.rtm_scope
= 0;
1545 req
.r
.rtm_src_len
= 0;
1546 req
.r
.rtm_dst_len
= 0;
1550 if (strcmp(*argv
, "tos") == 0 ||
1551 matches(*argv
, "dsfield") == 0) {
1554 if (rtnl_dsfield_a2n(&tos
, *argv
))
1555 invarg("TOS value is invalid\n", *argv
);
1556 req
.r
.rtm_tos
= tos
;
1557 } else if (matches(*argv
, "from") == 0) {
1560 if (matches(*argv
, "help") == 0)
1563 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
1564 if (req
.r
.rtm_family
== AF_UNSPEC
)
1565 req
.r
.rtm_family
= addr
.family
;
1567 addattr_l(&req
.n
, sizeof(req
), RTA_SRC
, &addr
.data
, addr
.bytelen
);
1568 req
.r
.rtm_src_len
= addr
.bitlen
;
1569 } else if (matches(*argv
, "iif") == 0) {
1572 } else if (matches(*argv
, "mark") == 0) {
1574 get_unsigned(&mark
, *argv
, 0);
1575 } else if (matches(*argv
, "oif") == 0 ||
1576 strcmp(*argv
, "dev") == 0) {
1579 } else if (matches(*argv
, "notify") == 0) {
1580 req
.r
.rtm_flags
|= RTM_F_NOTIFY
;
1581 } else if (matches(*argv
, "connected") == 0) {
1585 if (strcmp(*argv
, "to") == 0) {
1588 if (matches(*argv
, "help") == 0)
1590 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
1591 if (req
.r
.rtm_family
== AF_UNSPEC
)
1592 req
.r
.rtm_family
= addr
.family
;
1594 addattr_l(&req
.n
, sizeof(req
), RTA_DST
, &addr
.data
, addr
.bytelen
);
1595 req
.r
.rtm_dst_len
= addr
.bitlen
;
1600 if (req
.r
.rtm_dst_len
== 0) {
1601 fprintf(stderr
, "need at least a destination address\n");
1609 if ((idx
= ll_name_to_index(idev
)) == 0) {
1610 fprintf(stderr
, "Cannot find device \"%s\"\n", idev
);
1613 addattr32(&req
.n
, sizeof(req
), RTA_IIF
, idx
);
1616 if ((idx
= ll_name_to_index(odev
)) == 0) {
1617 fprintf(stderr
, "Cannot find device \"%s\"\n", odev
);
1620 addattr32(&req
.n
, sizeof(req
), RTA_OIF
, idx
);
1624 addattr32(&req
.n
, sizeof(req
), RTA_MARK
, mark
);
1626 if (req
.r
.rtm_family
== AF_UNSPEC
)
1627 req
.r
.rtm_family
= AF_INET
;
1629 if (rtnl_talk(&rth
, &req
.n
, &req
.n
, sizeof(req
)) < 0)
1632 if (connected
&& !from_ok
) {
1633 struct rtmsg
*r
= NLMSG_DATA(&req
.n
);
1634 int len
= req
.n
.nlmsg_len
;
1635 struct rtattr
* tb
[RTA_MAX
+1];
1637 if (print_route(NULL
, &req
.n
, (void*)stdout
) < 0) {
1638 fprintf(stderr
, "An error :-)\n");
1642 if (req
.n
.nlmsg_type
!= RTM_NEWROUTE
) {
1643 fprintf(stderr
, "Not a route?\n");
1646 len
-= NLMSG_LENGTH(sizeof(*r
));
1648 fprintf(stderr
, "Wrong len %d\n", len
);
1652 parse_rtattr(tb
, RTA_MAX
, RTM_RTA(r
), len
);
1654 if (tb
[RTA_PREFSRC
]) {
1655 tb
[RTA_PREFSRC
]->rta_type
= RTA_SRC
;
1656 r
->rtm_src_len
= 8*RTA_PAYLOAD(tb
[RTA_PREFSRC
]);
1657 } else if (!tb
[RTA_SRC
]) {
1658 fprintf(stderr
, "Failed to connect the route\n");
1661 if (!odev
&& tb
[RTA_OIF
])
1662 tb
[RTA_OIF
]->rta_type
= 0;
1663 if (tb
[RTA_GATEWAY
])
1664 tb
[RTA_GATEWAY
]->rta_type
= 0;
1666 tb
[RTA_VIA
]->rta_type
= 0;
1667 if (!idev
&& tb
[RTA_IIF
])
1668 tb
[RTA_IIF
]->rta_type
= 0;
1669 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
1670 req
.n
.nlmsg_type
= RTM_GETROUTE
;
1672 if (rtnl_talk(&rth
, &req
.n
, &req
.n
, sizeof(req
)) < 0)
1676 if (print_route(NULL
, &req
.n
, (void*)stdout
) < 0) {
1677 fprintf(stderr
, "An error :-)\n");
1684 static int restore_handler(const struct sockaddr_nl
*nl
, struct nlmsghdr
*n
,
1689 n
->nlmsg_flags
|= NLM_F_REQUEST
| NLM_F_CREATE
| NLM_F_ACK
;
1693 ret
= rtnl_talk(&rth
, n
, n
, sizeof(*n
));
1694 if ((ret
< 0) && (errno
== EEXIST
))
1700 static int route_dump_check_magic(void)
1705 if (isatty(STDIN_FILENO
)) {
1706 fprintf(stderr
, "Can't restore route dump from a terminal\n");
1710 ret
= fread(&magic
, sizeof(magic
), 1, stdin
);
1711 if (magic
!= route_dump_magic
) {
1712 fprintf(stderr
, "Magic mismatch (%d elems, %x magic)\n", ret
, magic
);
1719 static int iproute_restore(void)
1721 if (route_dump_check_magic())
1724 exit(rtnl_from_file(stdin
, &restore_handler
, NULL
));
1727 static int show_handler(const struct sockaddr_nl
*nl
, struct nlmsghdr
*n
, void *arg
)
1729 print_route(nl
, n
, stdout
);
1733 static int iproute_showdump(void)
1735 if (route_dump_check_magic())
1738 exit(rtnl_from_file(stdin
, &show_handler
, NULL
));
1741 void iproute_reset_filter(int ifindex
)
1743 memset(&filter
, 0, sizeof(filter
));
1744 filter
.mdst
.bitlen
= -1;
1745 filter
.msrc
.bitlen
= -1;
1746 filter
.oif
= ifindex
;
1748 filter
.oifmask
= -1;
1751 int do_iproute(int argc
, char **argv
)
1754 return iproute_list_flush_or_save(0, NULL
, IPROUTE_LIST
);
1756 if (matches(*argv
, "add") == 0)
1757 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_EXCL
,
1759 if (matches(*argv
, "change") == 0 || strcmp(*argv
, "chg") == 0)
1760 return iproute_modify(RTM_NEWROUTE
, NLM_F_REPLACE
,
1762 if (matches(*argv
, "replace") == 0)
1763 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_REPLACE
,
1765 if (matches(*argv
, "prepend") == 0)
1766 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
,
1768 if (matches(*argv
, "append") == 0)
1769 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_APPEND
,
1771 if (matches(*argv
, "test") == 0)
1772 return iproute_modify(RTM_NEWROUTE
, NLM_F_EXCL
,
1774 if (matches(*argv
, "delete") == 0)
1775 return iproute_modify(RTM_DELROUTE
, 0,
1777 if (matches(*argv
, "list") == 0 || matches(*argv
, "show") == 0
1778 || matches(*argv
, "lst") == 0)
1779 return iproute_list_flush_or_save(argc
-1, argv
+1, IPROUTE_LIST
);
1780 if (matches(*argv
, "get") == 0)
1781 return iproute_get(argc
-1, argv
+1);
1782 if (matches(*argv
, "flush") == 0)
1783 return iproute_list_flush_or_save(argc
-1, argv
+1, IPROUTE_FLUSH
);
1784 if (matches(*argv
, "save") == 0)
1785 return iproute_list_flush_or_save(argc
-1, argv
+1, IPROUTE_SAVE
);
1786 if (matches(*argv
, "restore") == 0)
1787 return iproute_restore();
1788 if (matches(*argv
, "showdump") == 0)
1789 return iproute_showdump();
1790 if (matches(*argv
, "help") == 0)
1792 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv
);