]>
git.proxmox.com Git - mirror_iproute2.git/blob - ip/iproute.c
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>
14 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
15 * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <netinet/ip.h>
29 #include <arpa/inet.h>
30 #include <linux/in_route.h>
34 #include "ip_common.h"
37 #define RTAX_RTTVAR RTAX_HOPS
41 static void usage(void) __attribute__((noreturn
));
43 static void usage(void)
45 fprintf(stderr
, "Usage: ip route { list | flush } SELECTOR\n");
46 fprintf(stderr
, " ip route get ADDRESS [ from ADDRESS iif STRING ]\n");
47 fprintf(stderr
, " [ oif STRING ] [ tos TOS ]\n");
48 fprintf(stderr
, " ip route { add | del | change | append | replace | monitor } ROUTE\n");
49 fprintf(stderr
, "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n");
50 fprintf(stderr
, " [ table TABLE_ID ] [ proto RTPROTO ]\n");
51 fprintf(stderr
, " [ type TYPE ] [ scope SCOPE ]\n");
52 fprintf(stderr
, "ROUTE := NODE_SPEC [ INFO_SPEC ]\n");
53 fprintf(stderr
, "NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n");
54 fprintf(stderr
, " [ table TABLE_ID ] [ proto RTPROTO ]\n");
55 fprintf(stderr
, " [ scope SCOPE ] [ metric METRIC ]\n");
56 fprintf(stderr
, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n");
57 fprintf(stderr
, "NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
58 fprintf(stderr
, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]\n");
59 fprintf(stderr
, " [ rtt NUMBER ] [ rttvar NUMBER ]\n");
60 fprintf(stderr
, " [ window NUMBER] [ cwnd NUMBER ] [ ssthresh REALM ]\n");
61 fprintf(stderr
, " [ realms REALM ]\n");
62 fprintf(stderr
, "TYPE := [ unicast | local | broadcast | multicast | throw |\n");
63 fprintf(stderr
, " unreachable | prohibit | blackhole | nat ]\n");
64 fprintf(stderr
, "TABLE_ID := [ local | main | default | all | NUMBER ]\n");
65 fprintf(stderr
, "SCOPE := [ host | link | global | NUMBER ]\n");
66 fprintf(stderr
, "FLAGS := [ equalize ]\n");
67 fprintf(stderr
, "NHFLAGS := [ onlink | pervasive ]\n");
68 fprintf(stderr
, "RTPROTO := [ kernel | boot | static | NUMBER ]\n");
80 struct rtnl_handle
*rth
;
81 int protocol
, protocolmask
;
96 static int flush_update(void)
98 if (rtnl_send(filter
.rth
, filter
.flushb
, filter
.flushp
) < 0) {
99 perror("Failed to send flush request\n");
106 int print_route(const struct sockaddr_nl
*who
, const struct nlmsghdr
*n
, void *arg
)
108 FILE *fp
= (FILE*)arg
;
109 struct rtmsg
*r
= NLMSG_DATA(n
);
110 int len
= n
->nlmsg_len
;
111 struct rtattr
* tb
[RTA_MAX
+1];
121 if (n
->nlmsg_type
!= RTM_NEWROUTE
&& n
->nlmsg_type
!= RTM_DELROUTE
) {
122 fprintf(stderr
, "Not a route: %08x %08x %08x\n",
123 n
->nlmsg_len
, n
->nlmsg_type
, n
->nlmsg_flags
);
126 if (filter
.flushb
&& n
->nlmsg_type
!= RTM_NEWROUTE
)
128 len
-= NLMSG_LENGTH(sizeof(*r
));
130 fprintf(stderr
, "BUG: wrong nlmsg len %d\n", len
);
134 if (r
->rtm_family
== AF_INET6
)
136 else if (r
->rtm_family
== AF_INET
)
138 else if (r
->rtm_family
== AF_DECnet
)
140 else if (r
->rtm_family
== AF_IPX
)
143 if (r
->rtm_family
== AF_INET6
) {
146 if (!(r
->rtm_flags
&RTM_F_CLONED
))
149 if (r
->rtm_flags
&RTM_F_CLONED
)
151 if (filter
.tb
== RT_TABLE_LOCAL
) {
152 if (r
->rtm_type
!= RTN_LOCAL
)
154 } else if (filter
.tb
== RT_TABLE_MAIN
) {
155 if (r
->rtm_type
== RTN_LOCAL
)
163 if (filter
.tb
> 0 && filter
.tb
!= r
->rtm_table
)
166 if ((filter
.protocol
^r
->rtm_protocol
)&filter
.protocolmask
)
168 if ((filter
.scope
^r
->rtm_scope
)&filter
.scopemask
)
170 if ((filter
.type
^r
->rtm_type
)&filter
.typemask
)
172 if ((filter
.tos
^r
->rtm_tos
)&filter
.tosmask
)
174 if (filter
.rdst
.family
&&
175 (r
->rtm_family
!= filter
.rdst
.family
|| filter
.rdst
.bitlen
> r
->rtm_dst_len
))
177 if (filter
.mdst
.family
&&
178 (r
->rtm_family
!= filter
.mdst
.family
||
179 (filter
.mdst
.bitlen
>= 0 && filter
.mdst
.bitlen
< r
->rtm_dst_len
)))
181 if (filter
.rsrc
.family
&&
182 (r
->rtm_family
!= filter
.rsrc
.family
|| filter
.rsrc
.bitlen
> r
->rtm_src_len
))
184 if (filter
.msrc
.family
&&
185 (r
->rtm_family
!= filter
.msrc
.family
||
186 (filter
.msrc
.bitlen
>= 0 && filter
.msrc
.bitlen
< r
->rtm_src_len
)))
188 if (filter
.rvia
.family
&& r
->rtm_family
!= filter
.rvia
.family
)
190 if (filter
.rprefsrc
.family
&& r
->rtm_family
!= filter
.rprefsrc
.family
)
194 memset(tb
, 0, sizeof(tb
));
195 parse_rtattr(tb
, RTA_MAX
, RTM_RTA(r
), len
);
197 memset(&dst
, 0, sizeof(dst
));
198 dst
.family
= r
->rtm_family
;
200 memcpy(&dst
.data
, RTA_DATA(tb
[RTA_DST
]), (r
->rtm_dst_len
+7)/8);
201 if (filter
.rsrc
.family
|| filter
.msrc
.family
) {
202 memset(&src
, 0, sizeof(src
));
203 src
.family
= r
->rtm_family
;
205 memcpy(&src
.data
, RTA_DATA(tb
[RTA_SRC
]), (r
->rtm_src_len
+7)/8);
207 if (filter
.rvia
.bitlen
>0) {
208 memset(&via
, 0, sizeof(via
));
209 via
.family
= r
->rtm_family
;
211 memcpy(&via
.data
, RTA_DATA(tb
[RTA_GATEWAY
]), host_len
);
213 if (filter
.rprefsrc
.bitlen
>0) {
214 memset(&prefsrc
, 0, sizeof(prefsrc
));
215 prefsrc
.family
= r
->rtm_family
;
217 memcpy(&prefsrc
.data
, RTA_DATA(tb
[RTA_PREFSRC
]), host_len
);
220 if (filter
.rdst
.family
&& inet_addr_match(&dst
, &filter
.rdst
, filter
.rdst
.bitlen
))
222 if (filter
.mdst
.family
&& filter
.mdst
.bitlen
>= 0 &&
223 inet_addr_match(&dst
, &filter
.mdst
, r
->rtm_dst_len
))
226 if (filter
.rsrc
.family
&& inet_addr_match(&src
, &filter
.rsrc
, filter
.rsrc
.bitlen
))
228 if (filter
.msrc
.family
&& filter
.msrc
.bitlen
>= 0 &&
229 inet_addr_match(&src
, &filter
.msrc
, r
->rtm_src_len
))
232 if (filter
.rvia
.family
&& inet_addr_match(&via
, &filter
.rvia
, filter
.rvia
.bitlen
))
234 if (filter
.rprefsrc
.family
&& inet_addr_match(&prefsrc
, &filter
.rprefsrc
, filter
.rprefsrc
.bitlen
))
236 if (filter
.realmmask
) {
239 realms
= *(__u32
*)RTA_DATA(tb
[RTA_FLOW
]);
240 if ((realms
^filter
.realm
)&filter
.realmmask
)
243 if (filter
.iifmask
) {
246 iif
= *(int*)RTA_DATA(tb
[RTA_IIF
]);
247 if ((iif
^filter
.iif
)&filter
.iifmask
)
250 if (filter
.oifmask
) {
253 oif
= *(int*)RTA_DATA(tb
[RTA_OIF
]);
254 if ((oif
^filter
.oif
)&filter
.oifmask
)
258 r
->rtm_family
== AF_INET6
&&
259 r
->rtm_dst_len
== 0 &&
260 r
->rtm_type
== RTN_UNREACHABLE
&&
262 *(int*)RTA_DATA(tb
[RTA_PRIORITY
]) == -1)
267 if (NLMSG_ALIGN(filter
.flushp
) + n
->nlmsg_len
> filter
.flushe
) {
271 fn
= (struct nlmsghdr
*)(filter
.flushb
+ NLMSG_ALIGN(filter
.flushp
));
272 memcpy(fn
, n
, n
->nlmsg_len
);
273 fn
->nlmsg_type
= RTM_DELROUTE
;
274 fn
->nlmsg_flags
= NLM_F_REQUEST
;
275 fn
->nlmsg_seq
= ++filter
.rth
->seq
;
276 filter
.flushp
= (((char*)fn
) + n
->nlmsg_len
) - filter
.flushb
;
282 if (n
->nlmsg_type
== RTM_DELROUTE
)
283 fprintf(fp
, "Deleted ");
284 if (r
->rtm_type
!= RTN_UNICAST
&& !filter
.type
)
285 fprintf(fp
, "%s ", rtnl_rtntype_n2a(r
->rtm_type
, b1
, sizeof(b1
)));
288 if (r
->rtm_dst_len
!= host_len
) {
289 fprintf(fp
, "%s/%u ", rt_addr_n2a(r
->rtm_family
,
290 RTA_PAYLOAD(tb
[RTA_DST
]),
291 RTA_DATA(tb
[RTA_DST
]),
296 fprintf(fp
, "%s ", format_host(r
->rtm_family
,
297 RTA_PAYLOAD(tb
[RTA_DST
]),
298 RTA_DATA(tb
[RTA_DST
]),
302 } else if (r
->rtm_dst_len
) {
303 fprintf(fp
, "0/%d ", r
->rtm_dst_len
);
305 fprintf(fp
, "default ");
308 if (r
->rtm_src_len
!= host_len
) {
309 fprintf(fp
, "from %s/%u ", rt_addr_n2a(r
->rtm_family
,
310 RTA_PAYLOAD(tb
[RTA_SRC
]),
311 RTA_DATA(tb
[RTA_SRC
]),
316 fprintf(fp
, "from %s ", format_host(r
->rtm_family
,
317 RTA_PAYLOAD(tb
[RTA_SRC
]),
318 RTA_DATA(tb
[RTA_SRC
]),
322 } else if (r
->rtm_src_len
) {
323 fprintf(fp
, "from 0/%u ", r
->rtm_src_len
);
325 if (r
->rtm_tos
&& filter
.tosmask
!= -1) {
327 fprintf(fp
, "tos %s ", rtnl_dsfield_n2a(r
->rtm_tos
, b1
, sizeof(b1
)));
329 if (tb
[RTA_GATEWAY
] && filter
.rvia
.bitlen
!= host_len
) {
330 fprintf(fp
, "via %s ",
331 format_host(r
->rtm_family
,
332 RTA_PAYLOAD(tb
[RTA_GATEWAY
]),
333 RTA_DATA(tb
[RTA_GATEWAY
]),
334 abuf
, sizeof(abuf
)));
336 if (tb
[RTA_OIF
] && filter
.oifmask
!= -1)
337 fprintf(fp
, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb
[RTA_OIF
])));
339 if (!(r
->rtm_flags
&RTM_F_CLONED
)) {
340 if (r
->rtm_table
!= RT_TABLE_MAIN
&& !filter
.tb
)
341 fprintf(fp
, " table %s ", rtnl_rttable_n2a(r
->rtm_table
, b1
, sizeof(b1
)));
342 if (r
->rtm_protocol
!= RTPROT_BOOT
&& filter
.protocolmask
!= -1)
343 fprintf(fp
, " proto %s ", rtnl_rtprot_n2a(r
->rtm_protocol
, b1
, sizeof(b1
)));
344 if (r
->rtm_scope
!= RT_SCOPE_UNIVERSE
&& filter
.scopemask
!= -1)
345 fprintf(fp
, " scope %s ", rtnl_rtscope_n2a(r
->rtm_scope
, b1
, sizeof(b1
)));
347 if (tb
[RTA_PREFSRC
] && filter
.rprefsrc
.bitlen
!= host_len
) {
348 /* Do not use format_host(). It is our local addr
349 and symbolic name will not be useful.
351 fprintf(fp
, " src %s ",
352 rt_addr_n2a(r
->rtm_family
,
353 RTA_PAYLOAD(tb
[RTA_PREFSRC
]),
354 RTA_DATA(tb
[RTA_PREFSRC
]),
355 abuf
, sizeof(abuf
)));
357 if (tb
[RTA_PRIORITY
])
358 fprintf(fp
, " metric %d ", *(__u32
*)RTA_DATA(tb
[RTA_PRIORITY
]));
359 if (r
->rtm_flags
& RTNH_F_DEAD
)
360 fprintf(fp
, "dead ");
361 if (r
->rtm_flags
& RTNH_F_ONLINK
)
362 fprintf(fp
, "onlink ");
363 if (r
->rtm_flags
& RTNH_F_PERVASIVE
)
364 fprintf(fp
, "pervasive ");
365 if (r
->rtm_flags
& RTM_F_EQUALIZE
)
366 fprintf(fp
, "equalize ");
367 if (r
->rtm_flags
& RTM_F_NOTIFY
)
368 fprintf(fp
, "notify ");
370 if (tb
[RTA_FLOW
] && filter
.realmmask
!= ~0U) {
371 __u32 to
= *(__u32
*)RTA_DATA(tb
[RTA_FLOW
]);
374 fprintf(fp
, "realm%s ", from
? "s" : "");
377 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
380 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
382 if ((r
->rtm_flags
&RTM_F_CLONED
) && r
->rtm_family
== AF_INET
) {
383 __u32 flags
= r
->rtm_flags
&~0xFFFF;
386 fprintf(fp
, "%s cache ", _SL_
);
388 #define PRTFL(fl,flname) if (flags&RTCF_##fl) { \
389 flags &= ~RTCF_##fl; \
390 fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \
392 PRTFL(LOCAL
, "local");
393 PRTFL(REJECT
, "reject");
394 PRTFL(MULTICAST
, "mc");
395 PRTFL(BROADCAST
, "brd");
396 PRTFL(DNAT
, "dst-nat");
397 PRTFL(SNAT
, "src-nat");
399 PRTFL(DIRECTDST
, "dst-direct");
400 PRTFL(DIRECTSRC
, "src-direct");
401 PRTFL(REDIRECTED
, "redirected");
402 PRTFL(DOREDIRECT
, "redirect");
403 PRTFL(FAST
, "fastroute");
404 PRTFL(NOTIFY
, "notify");
405 PRTFL(TPROXY
, "proxy");
407 PRTFL(EQUALIZE
, "equalize");
410 fprintf(fp
, "%s%x> ", first
? "<" : "", flags
);
411 if (tb
[RTA_CACHEINFO
]) {
412 struct rta_cacheinfo
*ci
= RTA_DATA(tb
[RTA_CACHEINFO
]);
416 if (ci
->rta_expires
!= 0)
417 fprintf(fp
, " expires %dsec", ci
->rta_expires
/hz
);
418 if (ci
->rta_error
!= 0)
419 fprintf(fp
, " error %d", ci
->rta_error
);
422 fprintf(fp
, " users %d", ci
->rta_clntref
);
423 if (ci
->rta_used
!= 0)
424 fprintf(fp
, " used %d", ci
->rta_used
);
425 if (ci
->rta_lastuse
!= 0)
426 fprintf(fp
, " age %dsec", ci
->rta_lastuse
/hz
);
428 #ifdef RTNETLINK_HAVE_PEERINFO
430 fprintf(fp
, " ipid 0x%04x", ci
->rta_id
);
431 if (ci
->rta_ts
|| ci
->rta_tsage
)
432 fprintf(fp
, " ts 0x%x tsage %dsec", ci
->rta_ts
, ci
->rta_tsage
);
435 } else if (r
->rtm_family
== AF_INET6
) {
436 struct rta_cacheinfo
*ci
= NULL
;
437 if (tb
[RTA_CACHEINFO
])
438 ci
= RTA_DATA(tb
[RTA_CACHEINFO
]);
439 if ((r
->rtm_flags
& RTM_F_CLONED
) || (ci
&& ci
->rta_expires
)) {
443 if (r
->rtm_flags
& RTM_F_CLONED
)
444 fprintf(fp
, "%s cache ", _SL_
);
446 fprintf(fp
, " expires %dsec", ci
->rta_expires
/hz
);
447 if (ci
->rta_error
!= 0)
448 fprintf(fp
, " error %d", ci
->rta_error
);
451 fprintf(fp
, " users %d", ci
->rta_clntref
);
452 if (ci
->rta_used
!= 0)
453 fprintf(fp
, " used %d", ci
->rta_used
);
454 if (ci
->rta_lastuse
!= 0)
455 fprintf(fp
, " age %dsec", ci
->rta_lastuse
/hz
);
458 if (ci
->rta_error
!= 0)
459 fprintf(fp
, " error %d", ci
->rta_error
);
462 if (tb
[RTA_METRICS
]) {
465 struct rtattr
*mxrta
[RTAX_MAX
+1];
467 memset(mxrta
, 0, sizeof(mxrta
));
469 parse_rtattr(mxrta
, RTAX_MAX
, RTA_DATA(tb
[RTA_METRICS
]),
470 RTA_PAYLOAD(tb
[RTA_METRICS
]));
471 if (mxrta
[RTAX_LOCK
])
472 mxlock
= *(unsigned*)RTA_DATA(mxrta
[RTAX_LOCK
]);
474 for (i
=2; i
<=RTAX_MAX
; i
++) {
475 static char *mx_names
[] =
487 if (mxrta
[i
] == NULL
)
491 if (i
-2 < sizeof(mx_names
)/sizeof(char*))
492 fprintf(fp
, " %s", mx_names
[i
-2]);
494 fprintf(fp
, " metric%d", i
);
496 fprintf(fp
, " lock");
498 if (i
!= RTAX_RTT
&& i
!= RTAX_RTTVAR
)
499 fprintf(fp
, " %u", *(unsigned*)RTA_DATA(mxrta
[i
]));
501 unsigned val
= *(unsigned*)RTA_DATA(mxrta
[i
]);
509 fprintf(fp
, " %ums", val
/hz
);
511 fprintf(fp
, " %.2fms", (float)val
/hz
);
515 if (tb
[RTA_IIF
] && filter
.iifmask
!= -1) {
516 fprintf(fp
, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb
[RTA_IIF
])));
518 if (tb
[RTA_MULTIPATH
]) {
519 struct rtnexthop
*nh
= RTA_DATA(tb
[RTA_MULTIPATH
]);
522 len
= RTA_PAYLOAD(tb
[RTA_MULTIPATH
]);
525 if (len
< sizeof(*nh
))
527 if (nh
->rtnh_len
> len
)
529 if (r
->rtm_flags
&RTM_F_CLONED
&& r
->rtm_type
== RTN_MULTICAST
) {
531 fprintf(fp
, " Oifs:");
535 fprintf(fp
, "%s\tnexthop", _SL_
);
536 if (nh
->rtnh_len
> sizeof(*nh
)) {
537 memset(tb
, 0, sizeof(tb
));
538 parse_rtattr(tb
, RTA_MAX
, RTNH_DATA(nh
), nh
->rtnh_len
- sizeof(*nh
));
539 if (tb
[RTA_GATEWAY
]) {
540 fprintf(fp
, " via %s ",
541 format_host(r
->rtm_family
,
542 RTA_PAYLOAD(tb
[RTA_GATEWAY
]),
543 RTA_DATA(tb
[RTA_GATEWAY
]),
544 abuf
, sizeof(abuf
)));
547 if (r
->rtm_flags
&RTM_F_CLONED
&& r
->rtm_type
== RTN_MULTICAST
) {
548 fprintf(fp
, " %s", ll_index_to_name(nh
->rtnh_ifindex
));
549 if (nh
->rtnh_hops
!= 1)
550 fprintf(fp
, "(ttl>%d)", nh
->rtnh_hops
);
552 fprintf(fp
, " dev %s", ll_index_to_name(nh
->rtnh_ifindex
));
553 fprintf(fp
, " weight %d", nh
->rtnh_hops
+1);
555 if (nh
->rtnh_flags
& RTNH_F_DEAD
)
556 fprintf(fp
, " dead");
557 if (nh
->rtnh_flags
& RTNH_F_ONLINK
)
558 fprintf(fp
, " onlink");
559 if (nh
->rtnh_flags
& RTNH_F_PERVASIVE
)
560 fprintf(fp
, " pervasive");
561 len
-= NLMSG_ALIGN(nh
->rtnh_len
);
571 int parse_one_nh(struct rtattr
*rta
, struct rtnexthop
*rtnh
, int *argcp
, char ***argvp
)
574 char **argv
= *argvp
;
576 while (++argv
, --argc
> 0) {
577 if (strcmp(*argv
, "via") == 0) {
579 rta_addattr32(rta
, 4096, RTA_GATEWAY
, get_addr32(*argv
));
580 rtnh
->rtnh_len
+= sizeof(struct rtattr
) + 4;
581 } else if (strcmp(*argv
, "dev") == 0) {
583 if ((rtnh
->rtnh_ifindex
= ll_name_to_index(*argv
)) == 0) {
584 fprintf(stderr
, "Cannot find device \"%s\"\n", *argv
);
587 } else if (strcmp(*argv
, "weight") == 0) {
590 if (get_unsigned(&w
, *argv
, 0) || w
== 0 || w
> 256)
591 invarg("\"weight\" is invalid\n", *argv
);
592 rtnh
->rtnh_hops
= w
- 1;
593 } else if (strcmp(*argv
, "onlink") == 0) {
594 rtnh
->rtnh_flags
|= RTNH_F_ONLINK
;
603 int parse_nexthops(struct nlmsghdr
*n
, struct rtmsg
*r
, int argc
, char **argv
)
606 struct rtattr
*rta
= (void*)buf
;
607 struct rtnexthop
*rtnh
;
609 rta
->rta_type
= RTA_MULTIPATH
;
610 rta
->rta_len
= RTA_LENGTH(0);
611 rtnh
= RTA_DATA(rta
);
614 if (strcmp(*argv
, "nexthop") != 0) {
615 fprintf(stderr
, "Error: \"nexthop\" or end of line is expected instead of \"%s\"\n", *argv
);
619 fprintf(stderr
, "Error: unexpected end of line after \"nexthop\"\n");
622 memset(rtnh
, 0, sizeof(*rtnh
));
623 rtnh
->rtnh_len
= sizeof(*rtnh
);
624 rta
->rta_len
+= rtnh
->rtnh_len
;
625 parse_one_nh(rta
, rtnh
, &argc
, &argv
);
626 rtnh
= RTNH_NEXT(rtnh
);
629 if (rta
->rta_len
> RTA_LENGTH(0))
630 addattr_l(n
, 1024, RTA_MULTIPATH
, RTA_DATA(rta
), RTA_PAYLOAD(rta
));
635 int iproute_modify(int cmd
, unsigned flags
, int argc
, char **argv
)
637 struct rtnl_handle rth
;
644 struct rtattr
* mxrta
= (void*)mxbuf
;
655 memset(&req
, 0, sizeof(req
));
657 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
658 req
.n
.nlmsg_flags
= NLM_F_REQUEST
|flags
;
659 req
.n
.nlmsg_type
= cmd
;
660 req
.r
.rtm_family
= preferred_family
;
661 req
.r
.rtm_table
= RT_TABLE_MAIN
;
662 req
.r
.rtm_scope
= RT_SCOPE_NOWHERE
;
664 if (cmd
!= RTM_DELROUTE
) {
665 req
.r
.rtm_protocol
= RTPROT_BOOT
;
666 req
.r
.rtm_scope
= RT_SCOPE_UNIVERSE
;
667 req
.r
.rtm_type
= RTN_UNICAST
;
670 mxrta
->rta_type
= RTA_METRICS
;
671 mxrta
->rta_len
= RTA_LENGTH(0);
674 if (strcmp(*argv
, "src") == 0) {
677 get_addr(&addr
, *argv
, req
.r
.rtm_family
);
678 if (req
.r
.rtm_family
== AF_UNSPEC
)
679 req
.r
.rtm_family
= addr
.family
;
680 addattr_l(&req
.n
, sizeof(req
), RTA_PREFSRC
, &addr
.data
, addr
.bytelen
);
681 } else if (strcmp(*argv
, "via") == 0) {
685 get_addr(&addr
, *argv
, req
.r
.rtm_family
);
686 if (req
.r
.rtm_family
== AF_UNSPEC
)
687 req
.r
.rtm_family
= addr
.family
;
688 addattr_l(&req
.n
, sizeof(req
), RTA_GATEWAY
, &addr
.data
, addr
.bytelen
);
689 } else if (strcmp(*argv
, "from") == 0) {
692 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
693 if (req
.r
.rtm_family
== AF_UNSPEC
)
694 req
.r
.rtm_family
= addr
.family
;
696 addattr_l(&req
.n
, sizeof(req
), RTA_SRC
, &addr
.data
, addr
.bytelen
);
697 req
.r
.rtm_src_len
= addr
.bitlen
;
698 } else if (strcmp(*argv
, "tos") == 0 ||
699 matches(*argv
, "dsfield") == 0) {
702 if (rtnl_dsfield_a2n(&tos
, *argv
))
703 invarg("\"tos\" value is invalid\n", *argv
);
705 } else if (matches(*argv
, "metric") == 0 ||
706 matches(*argv
, "priority") == 0 ||
707 matches(*argv
, "preference") == 0) {
710 if (get_u32(&metric
, *argv
, 0))
711 invarg("\"metric\" value is invalid\n", *argv
);
712 addattr32(&req
.n
, sizeof(req
), RTA_PRIORITY
, metric
);
713 } else if (strcmp(*argv
, "scope") == 0) {
716 if (rtnl_rtscope_a2n(&scope
, *argv
))
717 invarg("invalid \"scope\" value\n", *argv
);
718 req
.r
.rtm_scope
= scope
;
720 } else if (strcmp(*argv
, "mtu") == 0) {
723 if (strcmp(*argv
, "lock") == 0) {
724 mxlock
|= (1<<RTAX_MTU
);
727 if (get_unsigned(&mtu
, *argv
, 0))
728 invarg("\"mtu\" value is invalid\n", *argv
);
729 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_MTU
, mtu
);
731 } else if (strcmp(*argv
, "advmss") == 0) {
734 if (strcmp(*argv
, "lock") == 0) {
735 mxlock
|= (1<<RTAX_ADVMSS
);
738 if (get_unsigned(&mss
, *argv
, 0))
739 invarg("\"mss\" value is invalid\n", *argv
);
740 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_ADVMSS
, mss
);
742 #ifdef RTAX_REORDERING
743 } else if (matches(*argv
, "reordering") == 0) {
746 if (strcmp(*argv
, "lock") == 0) {
747 mxlock
|= (1<<RTAX_REORDERING
);
750 if (get_unsigned(&reord
, *argv
, 0))
751 invarg("\"reordering\" value is invalid\n", *argv
);
752 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_REORDERING
, reord
);
754 } else if (strcmp(*argv
, "rtt") == 0) {
757 if (strcmp(*argv
, "lock") == 0) {
758 mxlock
|= (1<<RTAX_RTT
);
761 if (get_unsigned(&rtt
, *argv
, 0))
762 invarg("\"rtt\" value is invalid\n", *argv
);
763 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_RTT
, rtt
);
764 } else if (matches(*argv
, "window") == 0) {
767 if (strcmp(*argv
, "lock") == 0) {
768 mxlock
|= (1<<RTAX_WINDOW
);
771 if (get_unsigned(&win
, *argv
, 0))
772 invarg("\"window\" value is invalid\n", *argv
);
773 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_WINDOW
, win
);
774 } else if (matches(*argv
, "cwnd") == 0) {
777 if (strcmp(*argv
, "lock") == 0) {
778 mxlock
|= (1<<RTAX_CWND
);
781 if (get_unsigned(&win
, *argv
, 0))
782 invarg("\"cwnd\" value is invalid\n", *argv
);
783 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_CWND
, win
);
784 } else if (matches(*argv
, "rttvar") == 0) {
787 if (strcmp(*argv
, "lock") == 0) {
788 mxlock
|= (1<<RTAX_RTTVAR
);
791 if (get_unsigned(&win
, *argv
, 0))
792 invarg("\"rttvar\" value is invalid\n", *argv
);
793 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_RTTVAR
, win
);
794 } else if (matches(*argv
, "ssthresh") == 0) {
797 if (strcmp(*argv
, "lock") == 0) {
798 mxlock
|= (1<<RTAX_SSTHRESH
);
801 if (get_unsigned(&win
, *argv
, 0))
802 invarg("\"ssthresh\" value is invalid\n", *argv
);
803 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_SSTHRESH
, win
);
804 } else if (matches(*argv
, "realms") == 0) {
807 if (get_rt_realms(&realm
, *argv
))
808 invarg("\"realm\" value is invalid\n", *argv
);
809 addattr32(&req
.n
, sizeof(req
), RTA_FLOW
, realm
);
810 } else if (strcmp(*argv
, "onlink") == 0) {
811 req
.r
.rtm_flags
|= RTNH_F_ONLINK
;
812 } else if (matches(*argv
, "equalize") == 0 ||
813 strcmp(*argv
, "eql") == 0) {
814 req
.r
.rtm_flags
|= RTM_F_EQUALIZE
;
815 } else if (strcmp(*argv
, "nexthop") == 0) {
818 } else if (matches(*argv
, "protocol") == 0) {
821 if (rtnl_rtprot_a2n(&prot
, *argv
))
822 invarg("\"protocol\" value is invalid\n", *argv
);
823 req
.r
.rtm_protocol
= prot
;
825 } else if (matches(*argv
, "table") == 0) {
828 if (rtnl_rttable_a2n(&tid
, *argv
))
829 invarg("\"table\" value is invalid\n", *argv
);
830 req
.r
.rtm_table
= tid
;
832 } else if (strcmp(*argv
, "dev") == 0 ||
833 strcmp(*argv
, "oif") == 0) {
840 if (strcmp(*argv
, "to") == 0) {
843 if ((**argv
< '0' || **argv
> '9') &&
844 rtnl_rtntype_a2n(&type
, *argv
) == 0) {
846 req
.r
.rtm_type
= type
;
850 if (matches(*argv
, "help") == 0)
853 duparg2("to", *argv
);
854 get_prefix(&dst
, *argv
, req
.r
.rtm_family
);
855 if (req
.r
.rtm_family
== AF_UNSPEC
)
856 req
.r
.rtm_family
= dst
.family
;
857 req
.r
.rtm_dst_len
= dst
.bitlen
;
860 addattr_l(&req
.n
, sizeof(req
), RTA_DST
, &dst
.data
, dst
.bytelen
);
865 if (rtnl_open(&rth
, 0) < 0)
874 if ((idx
= ll_name_to_index(d
)) == 0) {
875 fprintf(stderr
, "Cannot find device \"%s\"\n", d
);
878 addattr32(&req
.n
, sizeof(req
), RTA_OIF
, idx
);
882 if (mxrta
->rta_len
> RTA_LENGTH(0)) {
884 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_LOCK
, mxlock
);
885 addattr_l(&req
.n
, sizeof(req
), RTA_METRICS
, RTA_DATA(mxrta
), RTA_PAYLOAD(mxrta
));
889 parse_nexthops(&req
.n
, &req
.r
, argc
, argv
);
892 if (req
.r
.rtm_type
== RTN_LOCAL
||
893 req
.r
.rtm_type
== RTN_BROADCAST
||
894 req
.r
.rtm_type
== RTN_NAT
||
895 req
.r
.rtm_type
== RTN_ANYCAST
)
896 req
.r
.rtm_table
= RT_TABLE_LOCAL
;
899 if (req
.r
.rtm_type
== RTN_LOCAL
||
900 req
.r
.rtm_type
== RTN_NAT
)
901 req
.r
.rtm_scope
= RT_SCOPE_HOST
;
902 else if (req
.r
.rtm_type
== RTN_BROADCAST
||
903 req
.r
.rtm_type
== RTN_MULTICAST
||
904 req
.r
.rtm_type
== RTN_ANYCAST
)
905 req
.r
.rtm_scope
= RT_SCOPE_LINK
;
906 else if (req
.r
.rtm_type
== RTN_UNICAST
||
907 req
.r
.rtm_type
== RTN_UNSPEC
) {
908 if (cmd
== RTM_DELROUTE
)
909 req
.r
.rtm_scope
= RT_SCOPE_NOWHERE
;
910 else if (!gw_ok
&& !nhs_ok
)
911 req
.r
.rtm_scope
= RT_SCOPE_LINK
;
915 if (req
.r
.rtm_family
== AF_UNSPEC
)
916 req
.r
.rtm_family
= AF_INET
;
918 if (rtnl_talk(&rth
, &req
.n
, 0, 0, NULL
, NULL
, NULL
) < 0)
924 static int rtnl_rtcache_request(struct rtnl_handle
*rth
, int family
)
930 struct sockaddr_nl nladdr
;
932 memset(&nladdr
, 0, sizeof(nladdr
));
933 memset(&req
, 0, sizeof(req
));
934 nladdr
.nl_family
= AF_NETLINK
;
936 req
.nlh
.nlmsg_len
= sizeof(req
);
937 req
.nlh
.nlmsg_type
= RTM_GETROUTE
;
938 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
|NLM_F_REQUEST
;
939 req
.nlh
.nlmsg_pid
= 0;
940 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
941 req
.rtm
.rtm_family
= family
;
942 req
.rtm
.rtm_flags
|= RTM_F_CLONED
;
944 return sendto(rth
->fd
, (void*)&req
, sizeof(req
), 0, (struct sockaddr
*)&nladdr
, sizeof(nladdr
));
947 static int iproute_flush_cache(void)
949 #define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
952 int flush_fd
= open (ROUTE_FLUSH_PATH
, O_WRONLY
);
956 fprintf (stderr
, "Cannot open \"%s\"\n", ROUTE_FLUSH_PATH
);
960 len
= strlen (buffer
);
962 if ((write (flush_fd
, (void *)buffer
, len
)) < len
) {
963 fprintf (stderr
, "Cannot flush routing cache\n");
971 static int iproute_list_or_flush(int argc
, char **argv
, int flush
)
973 int do_ipv6
= preferred_family
;
974 struct rtnl_handle rth
;
978 iproute_reset_filter();
979 filter
.tb
= RT_TABLE_MAIN
;
981 if (flush
&& argc
<= 0) {
982 fprintf(stderr
, "\"ip route flush\" requires arguments.\n");
987 if (matches(*argv
, "table") == 0) {
990 if (rtnl_rttable_a2n(&tid
, *argv
)) {
991 if (strcmp(*argv
, "all") == 0) {
993 } else if (strcmp(*argv
, "cache") == 0) {
995 } else if (strcmp(*argv
, "help") == 0) {
998 invarg("table id value is invalid\n", *argv
);
1002 } else if (matches(*argv
, "cached") == 0 ||
1003 matches(*argv
, "cloned") == 0) {
1005 } else if (strcmp(*argv
, "tos") == 0 ||
1006 matches(*argv
, "dsfield") == 0) {
1009 if (rtnl_dsfield_a2n(&tos
, *argv
))
1010 invarg("TOS value is invalid\n", *argv
);
1012 filter
.tosmask
= -1;
1013 } else if (matches(*argv
, "protocol") == 0) {
1016 filter
.protocolmask
= -1;
1017 if (rtnl_rtprot_a2n(&prot
, *argv
)) {
1018 if (strcmp(*argv
, "all") != 0)
1019 invarg("invalid \"protocol\"\n", *argv
);
1021 filter
.protocolmask
= 0;
1023 filter
.protocol
= prot
;
1024 } else if (matches(*argv
, "scope") == 0) {
1027 filter
.scopemask
= -1;
1028 if (rtnl_rtscope_a2n(&scope
, *argv
)) {
1029 if (strcmp(*argv
, "all") != 0)
1030 invarg("invalid \"scope\"\n", *argv
);
1031 scope
= RT_SCOPE_NOWHERE
;
1032 filter
.scopemask
= 0;
1034 filter
.scope
= scope
;
1035 } else if (matches(*argv
, "type") == 0) {
1038 filter
.typemask
= -1;
1039 if (rtnl_rtntype_a2n(&type
, *argv
))
1040 invarg("node type value is invalid\n", *argv
);
1042 } else if (strcmp(*argv
, "dev") == 0 ||
1043 strcmp(*argv
, "oif") == 0) {
1046 } else if (strcmp(*argv
, "iif") == 0) {
1049 } else if (strcmp(*argv
, "via") == 0) {
1051 get_prefix(&filter
.rvia
, *argv
, do_ipv6
);
1052 } else if (strcmp(*argv
, "src") == 0) {
1054 get_prefix(&filter
.rprefsrc
, *argv
, do_ipv6
);
1055 } else if (matches(*argv
, "realms") == 0) {
1058 if (get_rt_realms(&realm
, *argv
))
1059 invarg("invalid realms\n", *argv
);
1060 filter
.realm
= realm
;
1061 filter
.realmmask
= ~0U;
1062 if ((filter
.realm
&0xFFFF) == 0 &&
1063 (*argv
)[strlen(*argv
) - 1] == '/')
1064 filter
.realmmask
&= ~0xFFFF;
1065 if ((filter
.realm
&0xFFFF0000U
) == 0 &&
1066 (strchr(*argv
, '/') == NULL
||
1068 filter
.realmmask
&= ~0xFFFF0000U
;
1069 } else if (matches(*argv
, "from") == 0) {
1071 if (matches(*argv
, "root") == 0) {
1073 get_prefix(&filter
.rsrc
, *argv
, do_ipv6
);
1074 } else if (matches(*argv
, "match") == 0) {
1076 get_prefix(&filter
.msrc
, *argv
, do_ipv6
);
1078 if (matches(*argv
, "exact") == 0) {
1081 get_prefix(&filter
.msrc
, *argv
, do_ipv6
);
1082 filter
.rsrc
= filter
.msrc
;
1085 if (matches(*argv
, "to") == 0) {
1088 if (matches(*argv
, "root") == 0) {
1090 get_prefix(&filter
.rdst
, *argv
, do_ipv6
);
1091 } else if (matches(*argv
, "match") == 0) {
1093 get_prefix(&filter
.mdst
, *argv
, do_ipv6
);
1095 if (matches(*argv
, "exact") == 0) {
1098 get_prefix(&filter
.mdst
, *argv
, do_ipv6
);
1099 filter
.rdst
= filter
.mdst
;
1105 if (do_ipv6
== AF_UNSPEC
&& filter
.tb
)
1108 if (rtnl_open(&rth
, 0) < 0)
1117 if ((idx
= ll_name_to_index(id
)) == 0) {
1118 fprintf(stderr
, "Cannot find device \"%s\"\n", id
);
1122 filter
.iifmask
= -1;
1125 if ((idx
= ll_name_to_index(od
)) == 0) {
1126 fprintf(stderr
, "Cannot find device \"%s\"\n", od
);
1130 filter
.oifmask
= -1;
1136 char flushb
[4096-512];
1137 time_t start
= time(0);
1139 if (filter
.tb
== -1) {
1140 if (do_ipv6
!= AF_INET6
) {
1141 iproute_flush_cache();
1143 printf("*** IPv4 routing cache is flushed.\n");
1145 if (do_ipv6
== AF_INET
)
1149 filter
.flushb
= flushb
;
1151 filter
.flushe
= sizeof(flushb
);
1155 if (rtnl_wilddump_request(&rth
, do_ipv6
, RTM_GETROUTE
) < 0) {
1156 perror("Cannot send dump request");
1160 if (rtnl_dump_filter(&rth
, print_route
, stdout
, NULL
, NULL
) < 0) {
1161 fprintf(stderr
, "Flush terminated\n");
1164 if (filter
.flushed
== 0) {
1166 if (filter
.tb
!= -1 || do_ipv6
== AF_INET6
)
1167 fprintf(stderr
, "Nothing to flush.\n");
1168 } else if (show_stats
)
1169 printf("*** Flush is complete after %d round%s ***\n", round
, round
>1?"s":"");
1174 if (flush_update() < 0)
1177 if (time(0) - start
> 30) {
1178 printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
1179 time(0) - start
, filter
.flushed
);
1184 printf("\n*** Round %d, deleting %d entries ***\n", round
, filter
.flushed
);
1190 if (filter
.tb
!= -1) {
1191 if (rtnl_wilddump_request(&rth
, do_ipv6
, RTM_GETROUTE
) < 0) {
1192 perror("Cannot send dump request");
1196 if (rtnl_rtcache_request(&rth
, do_ipv6
) < 0) {
1197 perror("Cannot send dump request");
1202 if (rtnl_dump_filter(&rth
, print_route
, stdout
, NULL
, NULL
) < 0) {
1203 fprintf(stderr
, "Dump terminated\n");
1211 int iproute_get(int argc
, char **argv
)
1213 struct rtnl_handle rth
;
1224 memset(&req
, 0, sizeof(req
));
1226 iproute_reset_filter();
1228 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
1229 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
1230 req
.n
.nlmsg_type
= RTM_GETROUTE
;
1231 req
.r
.rtm_family
= preferred_family
;
1232 req
.r
.rtm_table
= 0;
1233 req
.r
.rtm_protocol
= 0;
1234 req
.r
.rtm_scope
= 0;
1236 req
.r
.rtm_src_len
= 0;
1237 req
.r
.rtm_dst_len
= 0;
1241 if (strcmp(*argv
, "tos") == 0 ||
1242 matches(*argv
, "dsfield") == 0) {
1245 if (rtnl_dsfield_a2n(&tos
, *argv
))
1246 invarg("TOS value is invalid\n", *argv
);
1247 req
.r
.rtm_tos
= tos
;
1248 } else if (matches(*argv
, "from") == 0) {
1251 if (matches(*argv
, "help") == 0)
1254 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
1255 if (req
.r
.rtm_family
== AF_UNSPEC
)
1256 req
.r
.rtm_family
= addr
.family
;
1258 addattr_l(&req
.n
, sizeof(req
), RTA_SRC
, &addr
.data
, addr
.bytelen
);
1259 req
.r
.rtm_src_len
= addr
.bitlen
;
1260 } else if (matches(*argv
, "iif") == 0) {
1263 } else if (matches(*argv
, "oif") == 0 ||
1264 strcmp(*argv
, "dev") == 0) {
1267 } else if (matches(*argv
, "notify") == 0) {
1268 req
.r
.rtm_flags
|= RTM_F_NOTIFY
;
1269 } else if (matches(*argv
, "connected") == 0) {
1273 if (strcmp(*argv
, "to") == 0) {
1276 if (matches(*argv
, "help") == 0)
1278 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
1279 if (req
.r
.rtm_family
== AF_UNSPEC
)
1280 req
.r
.rtm_family
= addr
.family
;
1282 addattr_l(&req
.n
, sizeof(req
), RTA_DST
, &addr
.data
, addr
.bytelen
);
1283 req
.r
.rtm_dst_len
= addr
.bitlen
;
1288 if (req
.r
.rtm_dst_len
== 0) {
1289 fprintf(stderr
, "need at least destination address\n");
1293 if (rtnl_open(&rth
, 0) < 0)
1302 if ((idx
= ll_name_to_index(idev
)) == 0) {
1303 fprintf(stderr
, "Cannot find device \"%s\"\n", idev
);
1306 addattr32(&req
.n
, sizeof(req
), RTA_IIF
, idx
);
1309 if ((idx
= ll_name_to_index(odev
)) == 0) {
1310 fprintf(stderr
, "Cannot find device \"%s\"\n", odev
);
1313 addattr32(&req
.n
, sizeof(req
), RTA_OIF
, idx
);
1317 if (req
.r
.rtm_family
== AF_UNSPEC
)
1318 req
.r
.rtm_family
= AF_INET
;
1320 if (rtnl_talk(&rth
, &req
.n
, 0, 0, &req
.n
, NULL
, NULL
) < 0)
1323 if (connected
&& !from_ok
) {
1324 struct rtmsg
*r
= NLMSG_DATA(&req
.n
);
1325 int len
= req
.n
.nlmsg_len
;
1326 struct rtattr
* tb
[RTA_MAX
+1];
1328 if (print_route(NULL
, &req
.n
, (void*)stdout
) < 0) {
1329 fprintf(stderr
, "An error :-)\n");
1333 if (req
.n
.nlmsg_type
!= RTM_NEWROUTE
) {
1334 fprintf(stderr
, "Not a route?\n");
1337 len
-= NLMSG_LENGTH(sizeof(*r
));
1339 fprintf(stderr
, "Wrong len %d\n", len
);
1343 memset(tb
, 0, sizeof(tb
));
1344 parse_rtattr(tb
, RTA_MAX
, RTM_RTA(r
), len
);
1346 if (tb
[RTA_PREFSRC
]) {
1347 tb
[RTA_PREFSRC
]->rta_type
= RTA_SRC
;
1348 r
->rtm_src_len
= 8*RTA_PAYLOAD(tb
[RTA_PREFSRC
]);
1349 } else if (!tb
[RTA_SRC
]) {
1350 fprintf(stderr
, "Failed to connect the route\n");
1353 if (!odev
&& tb
[RTA_OIF
])
1354 tb
[RTA_OIF
]->rta_type
= 0;
1355 if (tb
[RTA_GATEWAY
])
1356 tb
[RTA_GATEWAY
]->rta_type
= 0;
1357 if (!idev
&& tb
[RTA_IIF
])
1358 tb
[RTA_IIF
]->rta_type
= 0;
1359 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
1360 req
.n
.nlmsg_type
= RTM_GETROUTE
;
1362 if (rtnl_talk(&rth
, &req
.n
, 0, 0, &req
.n
, NULL
, NULL
) < 0)
1366 if (print_route(NULL
, &req
.n
, (void*)stdout
) < 0) {
1367 fprintf(stderr
, "An error :-)\n");
1374 void iproute_reset_filter()
1376 memset(&filter
, 0, sizeof(filter
));
1377 filter
.mdst
.bitlen
= -1;
1378 filter
.msrc
.bitlen
= -1;
1381 int do_iproute(int argc
, char **argv
)
1384 return iproute_list_or_flush(0, NULL
, 0);
1386 if (matches(*argv
, "add") == 0)
1387 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_EXCL
,
1389 if (matches(*argv
, "change") == 0 || strcmp(*argv
, "chg") == 0)
1390 return iproute_modify(RTM_NEWROUTE
, NLM_F_REPLACE
,
1392 if (matches(*argv
, "replace") == 0)
1393 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_REPLACE
,
1395 if (matches(*argv
, "prepend") == 0)
1396 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
,
1398 if (matches(*argv
, "append") == 0)
1399 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_APPEND
,
1401 if (matches(*argv
, "test") == 0)
1402 return iproute_modify(RTM_NEWROUTE
, NLM_F_EXCL
,
1404 if (matches(*argv
, "delete") == 0)
1405 return iproute_modify(RTM_DELROUTE
, 0,
1407 if (matches(*argv
, "list") == 0 || matches(*argv
, "show") == 0
1408 || matches(*argv
, "lst") == 0)
1409 return iproute_list_or_flush(argc
-1, argv
+1, 0);
1410 if (matches(*argv
, "get") == 0)
1411 return iproute_get(argc
-1, argv
+1);
1412 if (matches(*argv
, "flush") == 0)
1413 return iproute_list_or_flush(argc
-1, argv
+1, 1);
1414 if (matches(*argv
, "help") == 0)
1416 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv
);