]>
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 NUMBER ]\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
, 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
)
193 parse_rtattr(tb
, RTA_MAX
, RTM_RTA(r
), len
);
195 memset(&dst
, 0, sizeof(dst
));
196 dst
.family
= r
->rtm_family
;
198 memcpy(&dst
.data
, RTA_DATA(tb
[RTA_DST
]), (r
->rtm_dst_len
+7)/8);
199 if (filter
.rsrc
.family
|| filter
.msrc
.family
) {
200 memset(&src
, 0, sizeof(src
));
201 src
.family
= r
->rtm_family
;
203 memcpy(&src
.data
, RTA_DATA(tb
[RTA_SRC
]), (r
->rtm_src_len
+7)/8);
205 if (filter
.rvia
.bitlen
>0) {
206 memset(&via
, 0, sizeof(via
));
207 via
.family
= r
->rtm_family
;
209 memcpy(&via
.data
, RTA_DATA(tb
[RTA_GATEWAY
]), host_len
);
211 if (filter
.rprefsrc
.bitlen
>0) {
212 memset(&prefsrc
, 0, sizeof(prefsrc
));
213 prefsrc
.family
= r
->rtm_family
;
215 memcpy(&prefsrc
.data
, RTA_DATA(tb
[RTA_PREFSRC
]), host_len
);
218 if (filter
.rdst
.family
&& inet_addr_match(&dst
, &filter
.rdst
, filter
.rdst
.bitlen
))
220 if (filter
.mdst
.family
&& filter
.mdst
.bitlen
>= 0 &&
221 inet_addr_match(&dst
, &filter
.mdst
, r
->rtm_dst_len
))
224 if (filter
.rsrc
.family
&& inet_addr_match(&src
, &filter
.rsrc
, filter
.rsrc
.bitlen
))
226 if (filter
.msrc
.family
&& filter
.msrc
.bitlen
>= 0 &&
227 inet_addr_match(&src
, &filter
.msrc
, r
->rtm_src_len
))
230 if (filter
.rvia
.family
&& inet_addr_match(&via
, &filter
.rvia
, filter
.rvia
.bitlen
))
232 if (filter
.rprefsrc
.family
&& inet_addr_match(&prefsrc
, &filter
.rprefsrc
, filter
.rprefsrc
.bitlen
))
234 if (filter
.realmmask
) {
237 realms
= *(__u32
*)RTA_DATA(tb
[RTA_FLOW
]);
238 if ((realms
^filter
.realm
)&filter
.realmmask
)
241 if (filter
.iifmask
) {
244 iif
= *(int*)RTA_DATA(tb
[RTA_IIF
]);
245 if ((iif
^filter
.iif
)&filter
.iifmask
)
248 if (filter
.oifmask
) {
251 oif
= *(int*)RTA_DATA(tb
[RTA_OIF
]);
252 if ((oif
^filter
.oif
)&filter
.oifmask
)
256 r
->rtm_family
== AF_INET6
&&
257 r
->rtm_dst_len
== 0 &&
258 r
->rtm_type
== RTN_UNREACHABLE
&&
260 *(int*)RTA_DATA(tb
[RTA_PRIORITY
]) == -1)
265 if (NLMSG_ALIGN(filter
.flushp
) + n
->nlmsg_len
> filter
.flushe
) {
269 fn
= (struct nlmsghdr
*)(filter
.flushb
+ NLMSG_ALIGN(filter
.flushp
));
270 memcpy(fn
, n
, n
->nlmsg_len
);
271 fn
->nlmsg_type
= RTM_DELROUTE
;
272 fn
->nlmsg_flags
= NLM_F_REQUEST
;
273 fn
->nlmsg_seq
= ++filter
.rth
->seq
;
274 filter
.flushp
= (((char*)fn
) + n
->nlmsg_len
) - filter
.flushb
;
280 if (n
->nlmsg_type
== RTM_DELROUTE
)
281 fprintf(fp
, "Deleted ");
282 if (r
->rtm_type
!= RTN_UNICAST
&& !filter
.type
)
283 fprintf(fp
, "%s ", rtnl_rtntype_n2a(r
->rtm_type
, b1
, sizeof(b1
)));
286 if (r
->rtm_dst_len
!= host_len
) {
287 fprintf(fp
, "%s/%u ", rt_addr_n2a(r
->rtm_family
,
288 RTA_PAYLOAD(tb
[RTA_DST
]),
289 RTA_DATA(tb
[RTA_DST
]),
294 fprintf(fp
, "%s ", format_host(r
->rtm_family
,
295 RTA_PAYLOAD(tb
[RTA_DST
]),
296 RTA_DATA(tb
[RTA_DST
]),
300 } else if (r
->rtm_dst_len
) {
301 fprintf(fp
, "0/%d ", r
->rtm_dst_len
);
303 fprintf(fp
, "default ");
306 if (r
->rtm_src_len
!= host_len
) {
307 fprintf(fp
, "from %s/%u ", rt_addr_n2a(r
->rtm_family
,
308 RTA_PAYLOAD(tb
[RTA_SRC
]),
309 RTA_DATA(tb
[RTA_SRC
]),
314 fprintf(fp
, "from %s ", format_host(r
->rtm_family
,
315 RTA_PAYLOAD(tb
[RTA_SRC
]),
316 RTA_DATA(tb
[RTA_SRC
]),
320 } else if (r
->rtm_src_len
) {
321 fprintf(fp
, "from 0/%u ", r
->rtm_src_len
);
323 if (r
->rtm_tos
&& filter
.tosmask
!= -1) {
325 fprintf(fp
, "tos %s ", rtnl_dsfield_n2a(r
->rtm_tos
, b1
, sizeof(b1
)));
327 if (tb
[RTA_GATEWAY
] && filter
.rvia
.bitlen
!= host_len
) {
328 fprintf(fp
, "via %s ",
329 format_host(r
->rtm_family
,
330 RTA_PAYLOAD(tb
[RTA_GATEWAY
]),
331 RTA_DATA(tb
[RTA_GATEWAY
]),
332 abuf
, sizeof(abuf
)));
334 if (tb
[RTA_OIF
] && filter
.oifmask
!= -1)
335 fprintf(fp
, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb
[RTA_OIF
])));
337 if (!(r
->rtm_flags
&RTM_F_CLONED
)) {
338 if (r
->rtm_table
!= RT_TABLE_MAIN
&& !filter
.tb
)
339 fprintf(fp
, " table %s ", rtnl_rttable_n2a(r
->rtm_table
, b1
, sizeof(b1
)));
340 if (r
->rtm_protocol
!= RTPROT_BOOT
&& filter
.protocolmask
!= -1)
341 fprintf(fp
, " proto %s ", rtnl_rtprot_n2a(r
->rtm_protocol
, b1
, sizeof(b1
)));
342 if (r
->rtm_scope
!= RT_SCOPE_UNIVERSE
&& filter
.scopemask
!= -1)
343 fprintf(fp
, " scope %s ", rtnl_rtscope_n2a(r
->rtm_scope
, b1
, sizeof(b1
)));
345 if (tb
[RTA_PREFSRC
] && filter
.rprefsrc
.bitlen
!= host_len
) {
346 /* Do not use format_host(). It is our local addr
347 and symbolic name will not be useful.
349 fprintf(fp
, " src %s ",
350 rt_addr_n2a(r
->rtm_family
,
351 RTA_PAYLOAD(tb
[RTA_PREFSRC
]),
352 RTA_DATA(tb
[RTA_PREFSRC
]),
353 abuf
, sizeof(abuf
)));
355 if (tb
[RTA_PRIORITY
])
356 fprintf(fp
, " metric %d ", *(__u32
*)RTA_DATA(tb
[RTA_PRIORITY
]));
357 if (r
->rtm_flags
& RTNH_F_DEAD
)
358 fprintf(fp
, "dead ");
359 if (r
->rtm_flags
& RTNH_F_ONLINK
)
360 fprintf(fp
, "onlink ");
361 if (r
->rtm_flags
& RTNH_F_PERVASIVE
)
362 fprintf(fp
, "pervasive ");
363 if (r
->rtm_flags
& RTM_F_EQUALIZE
)
364 fprintf(fp
, "equalize ");
365 if (r
->rtm_flags
& RTM_F_NOTIFY
)
366 fprintf(fp
, "notify ");
368 if (tb
[RTA_FLOW
] && filter
.realmmask
!= ~0U) {
369 __u32 to
= *(__u32
*)RTA_DATA(tb
[RTA_FLOW
]);
372 fprintf(fp
, "realm%s ", from
? "s" : "");
375 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
378 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
380 if ((r
->rtm_flags
&RTM_F_CLONED
) && r
->rtm_family
== AF_INET
) {
381 __u32 flags
= r
->rtm_flags
&~0xFFFF;
384 fprintf(fp
, "%s cache ", _SL_
);
386 #define PRTFL(fl,flname) if (flags&RTCF_##fl) { \
387 flags &= ~RTCF_##fl; \
388 fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \
390 PRTFL(LOCAL
, "local");
391 PRTFL(REJECT
, "reject");
392 PRTFL(MULTICAST
, "mc");
393 PRTFL(BROADCAST
, "brd");
394 PRTFL(DNAT
, "dst-nat");
395 PRTFL(SNAT
, "src-nat");
397 PRTFL(DIRECTDST
, "dst-direct");
398 PRTFL(DIRECTSRC
, "src-direct");
399 PRTFL(REDIRECTED
, "redirected");
400 PRTFL(DOREDIRECT
, "redirect");
401 PRTFL(FAST
, "fastroute");
402 PRTFL(NOTIFY
, "notify");
403 PRTFL(TPROXY
, "proxy");
405 PRTFL(EQUALIZE
, "equalize");
408 fprintf(fp
, "%s%x> ", first
? "<" : "", flags
);
409 if (tb
[RTA_CACHEINFO
]) {
410 struct rta_cacheinfo
*ci
= RTA_DATA(tb
[RTA_CACHEINFO
]);
414 if (ci
->rta_expires
!= 0)
415 fprintf(fp
, " expires %dsec", ci
->rta_expires
/hz
);
416 if (ci
->rta_error
!= 0)
417 fprintf(fp
, " error %d", ci
->rta_error
);
420 fprintf(fp
, " users %d", ci
->rta_clntref
);
421 if (ci
->rta_used
!= 0)
422 fprintf(fp
, " used %d", ci
->rta_used
);
423 if (ci
->rta_lastuse
!= 0)
424 fprintf(fp
, " age %dsec", ci
->rta_lastuse
/hz
);
426 #ifdef RTNETLINK_HAVE_PEERINFO
428 fprintf(fp
, " ipid 0x%04x", ci
->rta_id
);
429 if (ci
->rta_ts
|| ci
->rta_tsage
)
430 fprintf(fp
, " ts 0x%x tsage %dsec", ci
->rta_ts
, ci
->rta_tsage
);
433 } else if (r
->rtm_family
== AF_INET6
) {
434 struct rta_cacheinfo
*ci
= NULL
;
435 if (tb
[RTA_CACHEINFO
])
436 ci
= RTA_DATA(tb
[RTA_CACHEINFO
]);
437 if ((r
->rtm_flags
& RTM_F_CLONED
) || (ci
&& ci
->rta_expires
)) {
441 if (r
->rtm_flags
& RTM_F_CLONED
)
442 fprintf(fp
, "%s cache ", _SL_
);
444 fprintf(fp
, " expires %dsec", ci
->rta_expires
/hz
);
445 if (ci
->rta_error
!= 0)
446 fprintf(fp
, " error %d", ci
->rta_error
);
449 fprintf(fp
, " users %d", ci
->rta_clntref
);
450 if (ci
->rta_used
!= 0)
451 fprintf(fp
, " used %d", ci
->rta_used
);
452 if (ci
->rta_lastuse
!= 0)
453 fprintf(fp
, " age %dsec", ci
->rta_lastuse
/hz
);
456 if (ci
->rta_error
!= 0)
457 fprintf(fp
, " error %d", ci
->rta_error
);
460 if (tb
[RTA_METRICS
]) {
463 struct rtattr
*mxrta
[RTAX_MAX
+1];
465 parse_rtattr(mxrta
, RTAX_MAX
, RTA_DATA(tb
[RTA_METRICS
]),
466 RTA_PAYLOAD(tb
[RTA_METRICS
]));
467 if (mxrta
[RTAX_LOCK
])
468 mxlock
= *(unsigned*)RTA_DATA(mxrta
[RTAX_LOCK
]);
470 for (i
=2; i
<=RTAX_MAX
; i
++) {
471 static char *mx_names
[] =
483 if (mxrta
[i
] == NULL
)
487 if (i
-2 < sizeof(mx_names
)/sizeof(char*))
488 fprintf(fp
, " %s", mx_names
[i
-2]);
490 fprintf(fp
, " metric %d", i
);
492 fprintf(fp
, " lock");
494 if (i
!= RTAX_RTT
&& i
!= RTAX_RTTVAR
)
495 fprintf(fp
, " %u", *(unsigned*)RTA_DATA(mxrta
[i
]));
497 unsigned val
= *(unsigned*)RTA_DATA(mxrta
[i
]);
505 fprintf(fp
, " %ums", val
/hz
);
507 fprintf(fp
, " %.2fms", (float)val
/hz
);
511 if (tb
[RTA_IIF
] && filter
.iifmask
!= -1) {
512 fprintf(fp
, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb
[RTA_IIF
])));
514 if (tb
[RTA_MULTIPATH
]) {
515 struct rtnexthop
*nh
= RTA_DATA(tb
[RTA_MULTIPATH
]);
518 len
= RTA_PAYLOAD(tb
[RTA_MULTIPATH
]);
521 if (len
< sizeof(*nh
))
523 if (nh
->rtnh_len
> len
)
525 if (r
->rtm_flags
&RTM_F_CLONED
&& r
->rtm_type
== RTN_MULTICAST
) {
527 fprintf(fp
, " Oifs:");
531 fprintf(fp
, "%s\tnexthop", _SL_
);
532 if (nh
->rtnh_len
> sizeof(*nh
)) {
533 parse_rtattr(tb
, RTA_MAX
, RTNH_DATA(nh
), nh
->rtnh_len
- sizeof(*nh
));
534 if (tb
[RTA_GATEWAY
]) {
535 fprintf(fp
, " via %s ",
536 format_host(r
->rtm_family
,
537 RTA_PAYLOAD(tb
[RTA_GATEWAY
]),
538 RTA_DATA(tb
[RTA_GATEWAY
]),
539 abuf
, sizeof(abuf
)));
542 if (r
->rtm_flags
&RTM_F_CLONED
&& r
->rtm_type
== RTN_MULTICAST
) {
543 fprintf(fp
, " %s", ll_index_to_name(nh
->rtnh_ifindex
));
544 if (nh
->rtnh_hops
!= 1)
545 fprintf(fp
, "(ttl>%d)", nh
->rtnh_hops
);
547 fprintf(fp
, " dev %s", ll_index_to_name(nh
->rtnh_ifindex
));
548 fprintf(fp
, " weight %d", nh
->rtnh_hops
+1);
550 if (nh
->rtnh_flags
& RTNH_F_DEAD
)
551 fprintf(fp
, " dead");
552 if (nh
->rtnh_flags
& RTNH_F_ONLINK
)
553 fprintf(fp
, " onlink");
554 if (nh
->rtnh_flags
& RTNH_F_PERVASIVE
)
555 fprintf(fp
, " pervasive");
556 len
-= NLMSG_ALIGN(nh
->rtnh_len
);
566 int parse_one_nh(struct rtattr
*rta
, struct rtnexthop
*rtnh
, int *argcp
, char ***argvp
)
569 char **argv
= *argvp
;
571 while (++argv
, --argc
> 0) {
572 if (strcmp(*argv
, "via") == 0) {
574 rta_addattr32(rta
, 4096, RTA_GATEWAY
, get_addr32(*argv
));
575 rtnh
->rtnh_len
+= sizeof(struct rtattr
) + 4;
576 } else if (strcmp(*argv
, "dev") == 0) {
578 if ((rtnh
->rtnh_ifindex
= ll_name_to_index(*argv
)) == 0) {
579 fprintf(stderr
, "Cannot find device \"%s\"\n", *argv
);
582 } else if (strcmp(*argv
, "weight") == 0) {
585 if (get_unsigned(&w
, *argv
, 0) || w
== 0 || w
> 256)
586 invarg("\"weight\" is invalid\n", *argv
);
587 rtnh
->rtnh_hops
= w
- 1;
588 } else if (strcmp(*argv
, "onlink") == 0) {
589 rtnh
->rtnh_flags
|= RTNH_F_ONLINK
;
598 int parse_nexthops(struct nlmsghdr
*n
, struct rtmsg
*r
, int argc
, char **argv
)
601 struct rtattr
*rta
= (void*)buf
;
602 struct rtnexthop
*rtnh
;
604 rta
->rta_type
= RTA_MULTIPATH
;
605 rta
->rta_len
= RTA_LENGTH(0);
606 rtnh
= RTA_DATA(rta
);
609 if (strcmp(*argv
, "nexthop") != 0) {
610 fprintf(stderr
, "Error: \"nexthop\" or end of line is expected instead of \"%s\"\n", *argv
);
614 fprintf(stderr
, "Error: unexpected end of line after \"nexthop\"\n");
617 memset(rtnh
, 0, sizeof(*rtnh
));
618 rtnh
->rtnh_len
= sizeof(*rtnh
);
619 rta
->rta_len
+= rtnh
->rtnh_len
;
620 parse_one_nh(rta
, rtnh
, &argc
, &argv
);
621 rtnh
= RTNH_NEXT(rtnh
);
624 if (rta
->rta_len
> RTA_LENGTH(0))
625 addattr_l(n
, 1024, RTA_MULTIPATH
, RTA_DATA(rta
), RTA_PAYLOAD(rta
));
630 int iproute_modify(int cmd
, unsigned flags
, int argc
, char **argv
)
632 struct rtnl_handle rth
;
639 struct rtattr
* mxrta
= (void*)mxbuf
;
650 memset(&req
, 0, sizeof(req
));
652 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
653 req
.n
.nlmsg_flags
= NLM_F_REQUEST
|flags
;
654 req
.n
.nlmsg_type
= cmd
;
655 req
.r
.rtm_family
= preferred_family
;
656 req
.r
.rtm_table
= RT_TABLE_MAIN
;
657 req
.r
.rtm_scope
= RT_SCOPE_NOWHERE
;
659 if (cmd
!= RTM_DELROUTE
) {
660 req
.r
.rtm_protocol
= RTPROT_BOOT
;
661 req
.r
.rtm_scope
= RT_SCOPE_UNIVERSE
;
662 req
.r
.rtm_type
= RTN_UNICAST
;
665 mxrta
->rta_type
= RTA_METRICS
;
666 mxrta
->rta_len
= RTA_LENGTH(0);
669 if (strcmp(*argv
, "src") == 0) {
672 get_addr(&addr
, *argv
, req
.r
.rtm_family
);
673 if (req
.r
.rtm_family
== AF_UNSPEC
)
674 req
.r
.rtm_family
= addr
.family
;
675 addattr_l(&req
.n
, sizeof(req
), RTA_PREFSRC
, &addr
.data
, addr
.bytelen
);
676 } else if (strcmp(*argv
, "via") == 0) {
680 get_addr(&addr
, *argv
, req
.r
.rtm_family
);
681 if (req
.r
.rtm_family
== AF_UNSPEC
)
682 req
.r
.rtm_family
= addr
.family
;
683 addattr_l(&req
.n
, sizeof(req
), RTA_GATEWAY
, &addr
.data
, addr
.bytelen
);
684 } else if (strcmp(*argv
, "from") == 0) {
687 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
688 if (req
.r
.rtm_family
== AF_UNSPEC
)
689 req
.r
.rtm_family
= addr
.family
;
691 addattr_l(&req
.n
, sizeof(req
), RTA_SRC
, &addr
.data
, addr
.bytelen
);
692 req
.r
.rtm_src_len
= addr
.bitlen
;
693 } else if (strcmp(*argv
, "tos") == 0 ||
694 matches(*argv
, "dsfield") == 0) {
697 if (rtnl_dsfield_a2n(&tos
, *argv
))
698 invarg("\"tos\" value is invalid\n", *argv
);
700 } else if (matches(*argv
, "metric") == 0 ||
701 matches(*argv
, "priority") == 0 ||
702 matches(*argv
, "preference") == 0) {
705 if (get_u32(&metric
, *argv
, 0))
706 invarg("\"metric\" value is invalid\n", *argv
);
707 addattr32(&req
.n
, sizeof(req
), RTA_PRIORITY
, metric
);
708 } else if (strcmp(*argv
, "scope") == 0) {
711 if (rtnl_rtscope_a2n(&scope
, *argv
))
712 invarg("invalid \"scope\" value\n", *argv
);
713 req
.r
.rtm_scope
= scope
;
715 } else if (strcmp(*argv
, "mtu") == 0) {
718 if (strcmp(*argv
, "lock") == 0) {
719 mxlock
|= (1<<RTAX_MTU
);
722 if (get_unsigned(&mtu
, *argv
, 0))
723 invarg("\"mtu\" value is invalid\n", *argv
);
724 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_MTU
, mtu
);
726 } else if (strcmp(*argv
, "advmss") == 0) {
729 if (strcmp(*argv
, "lock") == 0) {
730 mxlock
|= (1<<RTAX_ADVMSS
);
733 if (get_unsigned(&mss
, *argv
, 0))
734 invarg("\"mss\" value is invalid\n", *argv
);
735 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_ADVMSS
, mss
);
737 #ifdef RTAX_REORDERING
738 } else if (matches(*argv
, "reordering") == 0) {
741 if (strcmp(*argv
, "lock") == 0) {
742 mxlock
|= (1<<RTAX_REORDERING
);
745 if (get_unsigned(&reord
, *argv
, 0))
746 invarg("\"reordering\" value is invalid\n", *argv
);
747 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_REORDERING
, reord
);
749 } else if (strcmp(*argv
, "rtt") == 0) {
752 if (strcmp(*argv
, "lock") == 0) {
753 mxlock
|= (1<<RTAX_RTT
);
756 if (get_unsigned(&rtt
, *argv
, 0))
757 invarg("\"rtt\" value is invalid\n", *argv
);
758 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_RTT
, rtt
);
759 } else if (matches(*argv
, "window") == 0) {
762 if (strcmp(*argv
, "lock") == 0) {
763 mxlock
|= (1<<RTAX_WINDOW
);
766 if (get_unsigned(&win
, *argv
, 0))
767 invarg("\"window\" value is invalid\n", *argv
);
768 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_WINDOW
, win
);
769 } else if (matches(*argv
, "cwnd") == 0) {
772 if (strcmp(*argv
, "lock") == 0) {
773 mxlock
|= (1<<RTAX_CWND
);
776 if (get_unsigned(&win
, *argv
, 0))
777 invarg("\"cwnd\" value is invalid\n", *argv
);
778 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_CWND
, win
);
779 } else if (matches(*argv
, "rttvar") == 0) {
782 if (strcmp(*argv
, "lock") == 0) {
783 mxlock
|= (1<<RTAX_RTTVAR
);
786 if (get_unsigned(&win
, *argv
, 0))
787 invarg("\"rttvar\" value is invalid\n", *argv
);
788 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_RTTVAR
, win
);
789 } else if (matches(*argv
, "ssthresh") == 0) {
792 if (strcmp(*argv
, "lock") == 0) {
793 mxlock
|= (1<<RTAX_SSTHRESH
);
796 if (get_unsigned(&win
, *argv
, 0))
797 invarg("\"ssthresh\" value is invalid\n", *argv
);
798 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_SSTHRESH
, win
);
799 } else if (matches(*argv
, "realms") == 0) {
802 if (get_rt_realms(&realm
, *argv
))
803 invarg("\"realm\" value is invalid\n", *argv
);
804 addattr32(&req
.n
, sizeof(req
), RTA_FLOW
, realm
);
805 } else if (strcmp(*argv
, "onlink") == 0) {
806 req
.r
.rtm_flags
|= RTNH_F_ONLINK
;
807 } else if (matches(*argv
, "equalize") == 0 ||
808 strcmp(*argv
, "eql") == 0) {
809 req
.r
.rtm_flags
|= RTM_F_EQUALIZE
;
810 } else if (strcmp(*argv
, "nexthop") == 0) {
813 } else if (matches(*argv
, "protocol") == 0) {
816 if (rtnl_rtprot_a2n(&prot
, *argv
))
817 invarg("\"protocol\" value is invalid\n", *argv
);
818 req
.r
.rtm_protocol
= prot
;
820 } else if (matches(*argv
, "table") == 0) {
823 if (rtnl_rttable_a2n(&tid
, *argv
))
824 invarg("\"table\" value is invalid\n", *argv
);
825 req
.r
.rtm_table
= tid
;
827 } else if (strcmp(*argv
, "dev") == 0 ||
828 strcmp(*argv
, "oif") == 0) {
835 if (strcmp(*argv
, "to") == 0) {
838 if ((**argv
< '0' || **argv
> '9') &&
839 rtnl_rtntype_a2n(&type
, *argv
) == 0) {
841 req
.r
.rtm_type
= type
;
845 if (matches(*argv
, "help") == 0)
848 duparg2("to", *argv
);
849 get_prefix(&dst
, *argv
, req
.r
.rtm_family
);
850 if (req
.r
.rtm_family
== AF_UNSPEC
)
851 req
.r
.rtm_family
= dst
.family
;
852 req
.r
.rtm_dst_len
= dst
.bitlen
;
855 addattr_l(&req
.n
, sizeof(req
), RTA_DST
, &dst
.data
, dst
.bytelen
);
860 if (rtnl_open(&rth
, 0) < 0)
869 if ((idx
= ll_name_to_index(d
)) == 0) {
870 fprintf(stderr
, "Cannot find device \"%s\"\n", d
);
873 addattr32(&req
.n
, sizeof(req
), RTA_OIF
, idx
);
877 if (mxrta
->rta_len
> RTA_LENGTH(0)) {
879 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_LOCK
, mxlock
);
880 addattr_l(&req
.n
, sizeof(req
), RTA_METRICS
, RTA_DATA(mxrta
), RTA_PAYLOAD(mxrta
));
884 parse_nexthops(&req
.n
, &req
.r
, argc
, argv
);
887 if (req
.r
.rtm_type
== RTN_LOCAL
||
888 req
.r
.rtm_type
== RTN_BROADCAST
||
889 req
.r
.rtm_type
== RTN_NAT
||
890 req
.r
.rtm_type
== RTN_ANYCAST
)
891 req
.r
.rtm_table
= RT_TABLE_LOCAL
;
894 if (req
.r
.rtm_type
== RTN_LOCAL
||
895 req
.r
.rtm_type
== RTN_NAT
)
896 req
.r
.rtm_scope
= RT_SCOPE_HOST
;
897 else if (req
.r
.rtm_type
== RTN_BROADCAST
||
898 req
.r
.rtm_type
== RTN_MULTICAST
||
899 req
.r
.rtm_type
== RTN_ANYCAST
)
900 req
.r
.rtm_scope
= RT_SCOPE_LINK
;
901 else if (req
.r
.rtm_type
== RTN_UNICAST
||
902 req
.r
.rtm_type
== RTN_UNSPEC
) {
903 if (cmd
== RTM_DELROUTE
)
904 req
.r
.rtm_scope
= RT_SCOPE_NOWHERE
;
905 else if (!gw_ok
&& !nhs_ok
)
906 req
.r
.rtm_scope
= RT_SCOPE_LINK
;
910 if (req
.r
.rtm_family
== AF_UNSPEC
)
911 req
.r
.rtm_family
= AF_INET
;
913 if (rtnl_talk(&rth
, &req
.n
, 0, 0, NULL
, NULL
, NULL
) < 0)
919 static int rtnl_rtcache_request(struct rtnl_handle
*rth
, int family
)
925 struct sockaddr_nl nladdr
;
927 memset(&nladdr
, 0, sizeof(nladdr
));
928 memset(&req
, 0, sizeof(req
));
929 nladdr
.nl_family
= AF_NETLINK
;
931 req
.nlh
.nlmsg_len
= sizeof(req
);
932 req
.nlh
.nlmsg_type
= RTM_GETROUTE
;
933 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
|NLM_F_REQUEST
;
934 req
.nlh
.nlmsg_pid
= 0;
935 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
936 req
.rtm
.rtm_family
= family
;
937 req
.rtm
.rtm_flags
|= RTM_F_CLONED
;
939 return sendto(rth
->fd
, (void*)&req
, sizeof(req
), 0, (struct sockaddr
*)&nladdr
, sizeof(nladdr
));
942 static int iproute_flush_cache(void)
944 #define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
947 int flush_fd
= open (ROUTE_FLUSH_PATH
, O_WRONLY
);
951 fprintf (stderr
, "Cannot open \"%s\"\n", ROUTE_FLUSH_PATH
);
955 len
= strlen (buffer
);
957 if ((write (flush_fd
, (void *)buffer
, len
)) < len
) {
958 fprintf (stderr
, "Cannot flush routing cache\n");
966 static int iproute_list_or_flush(int argc
, char **argv
, int flush
)
968 int do_ipv6
= preferred_family
;
969 struct rtnl_handle rth
;
973 iproute_reset_filter();
974 filter
.tb
= RT_TABLE_MAIN
;
976 if (flush
&& argc
<= 0) {
977 fprintf(stderr
, "\"ip route flush\" requires arguments.\n");
982 if (matches(*argv
, "table") == 0) {
985 if (rtnl_rttable_a2n(&tid
, *argv
)) {
986 if (strcmp(*argv
, "all") == 0) {
988 } else if (strcmp(*argv
, "cache") == 0) {
990 } else if (strcmp(*argv
, "help") == 0) {
993 invarg("table id value is invalid\n", *argv
);
997 } else if (matches(*argv
, "cached") == 0 ||
998 matches(*argv
, "cloned") == 0) {
1000 } else if (strcmp(*argv
, "tos") == 0 ||
1001 matches(*argv
, "dsfield") == 0) {
1004 if (rtnl_dsfield_a2n(&tos
, *argv
))
1005 invarg("TOS value is invalid\n", *argv
);
1007 filter
.tosmask
= -1;
1008 } else if (matches(*argv
, "protocol") == 0) {
1011 filter
.protocolmask
= -1;
1012 if (rtnl_rtprot_a2n(&prot
, *argv
)) {
1013 if (strcmp(*argv
, "all") != 0)
1014 invarg("invalid \"protocol\"\n", *argv
);
1016 filter
.protocolmask
= 0;
1018 filter
.protocol
= prot
;
1019 } else if (matches(*argv
, "scope") == 0) {
1022 filter
.scopemask
= -1;
1023 if (rtnl_rtscope_a2n(&scope
, *argv
)) {
1024 if (strcmp(*argv
, "all") != 0)
1025 invarg("invalid \"scope\"\n", *argv
);
1026 scope
= RT_SCOPE_NOWHERE
;
1027 filter
.scopemask
= 0;
1029 filter
.scope
= scope
;
1030 } else if (matches(*argv
, "type") == 0) {
1033 filter
.typemask
= -1;
1034 if (rtnl_rtntype_a2n(&type
, *argv
))
1035 invarg("node type value is invalid\n", *argv
);
1037 } else if (strcmp(*argv
, "dev") == 0 ||
1038 strcmp(*argv
, "oif") == 0) {
1041 } else if (strcmp(*argv
, "iif") == 0) {
1044 } else if (strcmp(*argv
, "via") == 0) {
1046 get_prefix(&filter
.rvia
, *argv
, do_ipv6
);
1047 } else if (strcmp(*argv
, "src") == 0) {
1049 get_prefix(&filter
.rprefsrc
, *argv
, do_ipv6
);
1050 } else if (matches(*argv
, "realms") == 0) {
1053 if (get_rt_realms(&realm
, *argv
))
1054 invarg("invalid realms\n", *argv
);
1055 filter
.realm
= realm
;
1056 filter
.realmmask
= ~0U;
1057 if ((filter
.realm
&0xFFFF) == 0 &&
1058 (*argv
)[strlen(*argv
) - 1] == '/')
1059 filter
.realmmask
&= ~0xFFFF;
1060 if ((filter
.realm
&0xFFFF0000U
) == 0 &&
1061 (strchr(*argv
, '/') == NULL
||
1063 filter
.realmmask
&= ~0xFFFF0000U
;
1064 } else if (matches(*argv
, "from") == 0) {
1066 if (matches(*argv
, "root") == 0) {
1068 get_prefix(&filter
.rsrc
, *argv
, do_ipv6
);
1069 } else if (matches(*argv
, "match") == 0) {
1071 get_prefix(&filter
.msrc
, *argv
, do_ipv6
);
1073 if (matches(*argv
, "exact") == 0) {
1076 get_prefix(&filter
.msrc
, *argv
, do_ipv6
);
1077 filter
.rsrc
= filter
.msrc
;
1080 if (matches(*argv
, "to") == 0) {
1083 if (matches(*argv
, "root") == 0) {
1085 get_prefix(&filter
.rdst
, *argv
, do_ipv6
);
1086 } else if (matches(*argv
, "match") == 0) {
1088 get_prefix(&filter
.mdst
, *argv
, do_ipv6
);
1090 if (matches(*argv
, "exact") == 0) {
1093 get_prefix(&filter
.mdst
, *argv
, do_ipv6
);
1094 filter
.rdst
= filter
.mdst
;
1100 if (do_ipv6
== AF_UNSPEC
&& filter
.tb
)
1103 if (rtnl_open(&rth
, 0) < 0)
1112 if ((idx
= ll_name_to_index(id
)) == 0) {
1113 fprintf(stderr
, "Cannot find device \"%s\"\n", id
);
1117 filter
.iifmask
= -1;
1120 if ((idx
= ll_name_to_index(od
)) == 0) {
1121 fprintf(stderr
, "Cannot find device \"%s\"\n", od
);
1125 filter
.oifmask
= -1;
1131 char flushb
[4096-512];
1132 time_t start
= time(0);
1134 if (filter
.tb
== -1) {
1135 if (do_ipv6
!= AF_INET6
) {
1136 iproute_flush_cache();
1138 printf("*** IPv4 routing cache is flushed.\n");
1140 if (do_ipv6
== AF_INET
)
1144 filter
.flushb
= flushb
;
1146 filter
.flushe
= sizeof(flushb
);
1150 if (rtnl_wilddump_request(&rth
, do_ipv6
, RTM_GETROUTE
) < 0) {
1151 perror("Cannot send dump request");
1155 if (rtnl_dump_filter(&rth
, print_route
, stdout
, NULL
, NULL
) < 0) {
1156 fprintf(stderr
, "Flush terminated\n");
1159 if (filter
.flushed
== 0) {
1161 if (filter
.tb
!= -1 || do_ipv6
== AF_INET6
)
1162 fprintf(stderr
, "Nothing to flush.\n");
1163 } else if (show_stats
)
1164 printf("*** Flush is complete after %d round%s ***\n", round
, round
>1?"s":"");
1169 if (flush_update() < 0)
1172 if (time(0) - start
> 30) {
1173 printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
1174 time(0) - start
, filter
.flushed
);
1179 printf("\n*** Round %d, deleting %d entries ***\n", round
, filter
.flushed
);
1185 if (filter
.tb
!= -1) {
1186 if (rtnl_wilddump_request(&rth
, do_ipv6
, RTM_GETROUTE
) < 0) {
1187 perror("Cannot send dump request");
1191 if (rtnl_rtcache_request(&rth
, do_ipv6
) < 0) {
1192 perror("Cannot send dump request");
1197 if (rtnl_dump_filter(&rth
, print_route
, stdout
, NULL
, NULL
) < 0) {
1198 fprintf(stderr
, "Dump terminated\n");
1206 int iproute_get(int argc
, char **argv
)
1208 struct rtnl_handle rth
;
1219 memset(&req
, 0, sizeof(req
));
1221 iproute_reset_filter();
1223 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
1224 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
1225 req
.n
.nlmsg_type
= RTM_GETROUTE
;
1226 req
.r
.rtm_family
= preferred_family
;
1227 req
.r
.rtm_table
= 0;
1228 req
.r
.rtm_protocol
= 0;
1229 req
.r
.rtm_scope
= 0;
1231 req
.r
.rtm_src_len
= 0;
1232 req
.r
.rtm_dst_len
= 0;
1236 if (strcmp(*argv
, "tos") == 0 ||
1237 matches(*argv
, "dsfield") == 0) {
1240 if (rtnl_dsfield_a2n(&tos
, *argv
))
1241 invarg("TOS value is invalid\n", *argv
);
1242 req
.r
.rtm_tos
= tos
;
1243 } else if (matches(*argv
, "from") == 0) {
1246 if (matches(*argv
, "help") == 0)
1249 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
1250 if (req
.r
.rtm_family
== AF_UNSPEC
)
1251 req
.r
.rtm_family
= addr
.family
;
1253 addattr_l(&req
.n
, sizeof(req
), RTA_SRC
, &addr
.data
, addr
.bytelen
);
1254 req
.r
.rtm_src_len
= addr
.bitlen
;
1255 } else if (matches(*argv
, "iif") == 0) {
1258 } else if (matches(*argv
, "oif") == 0 ||
1259 strcmp(*argv
, "dev") == 0) {
1262 } else if (matches(*argv
, "notify") == 0) {
1263 req
.r
.rtm_flags
|= RTM_F_NOTIFY
;
1264 } else if (matches(*argv
, "connected") == 0) {
1268 if (strcmp(*argv
, "to") == 0) {
1271 if (matches(*argv
, "help") == 0)
1273 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
1274 if (req
.r
.rtm_family
== AF_UNSPEC
)
1275 req
.r
.rtm_family
= addr
.family
;
1277 addattr_l(&req
.n
, sizeof(req
), RTA_DST
, &addr
.data
, addr
.bytelen
);
1278 req
.r
.rtm_dst_len
= addr
.bitlen
;
1283 if (req
.r
.rtm_dst_len
== 0) {
1284 fprintf(stderr
, "need at least destination address\n");
1288 if (rtnl_open(&rth
, 0) < 0)
1297 if ((idx
= ll_name_to_index(idev
)) == 0) {
1298 fprintf(stderr
, "Cannot find device \"%s\"\n", idev
);
1301 addattr32(&req
.n
, sizeof(req
), RTA_IIF
, idx
);
1304 if ((idx
= ll_name_to_index(odev
)) == 0) {
1305 fprintf(stderr
, "Cannot find device \"%s\"\n", odev
);
1308 addattr32(&req
.n
, sizeof(req
), RTA_OIF
, idx
);
1312 if (req
.r
.rtm_family
== AF_UNSPEC
)
1313 req
.r
.rtm_family
= AF_INET
;
1315 if (rtnl_talk(&rth
, &req
.n
, 0, 0, &req
.n
, NULL
, NULL
) < 0)
1318 if (connected
&& !from_ok
) {
1319 struct rtmsg
*r
= NLMSG_DATA(&req
.n
);
1320 int len
= req
.n
.nlmsg_len
;
1321 struct rtattr
* tb
[RTA_MAX
+1];
1323 if (print_route(NULL
, &req
.n
, (void*)stdout
) < 0) {
1324 fprintf(stderr
, "An error :-)\n");
1328 if (req
.n
.nlmsg_type
!= RTM_NEWROUTE
) {
1329 fprintf(stderr
, "Not a route?\n");
1332 len
-= NLMSG_LENGTH(sizeof(*r
));
1334 fprintf(stderr
, "Wrong len %d\n", len
);
1338 parse_rtattr(tb
, RTA_MAX
, RTM_RTA(r
), len
);
1340 if (tb
[RTA_PREFSRC
]) {
1341 tb
[RTA_PREFSRC
]->rta_type
= RTA_SRC
;
1342 r
->rtm_src_len
= 8*RTA_PAYLOAD(tb
[RTA_PREFSRC
]);
1343 } else if (!tb
[RTA_SRC
]) {
1344 fprintf(stderr
, "Failed to connect the route\n");
1347 if (!odev
&& tb
[RTA_OIF
])
1348 tb
[RTA_OIF
]->rta_type
= 0;
1349 if (tb
[RTA_GATEWAY
])
1350 tb
[RTA_GATEWAY
]->rta_type
= 0;
1351 if (!idev
&& tb
[RTA_IIF
])
1352 tb
[RTA_IIF
]->rta_type
= 0;
1353 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
1354 req
.n
.nlmsg_type
= RTM_GETROUTE
;
1356 if (rtnl_talk(&rth
, &req
.n
, 0, 0, &req
.n
, NULL
, NULL
) < 0)
1360 if (print_route(NULL
, &req
.n
, (void*)stdout
) < 0) {
1361 fprintf(stderr
, "An error :-)\n");
1368 void iproute_reset_filter()
1370 memset(&filter
, 0, sizeof(filter
));
1371 filter
.mdst
.bitlen
= -1;
1372 filter
.msrc
.bitlen
= -1;
1375 int do_iproute(int argc
, char **argv
)
1378 return iproute_list_or_flush(0, NULL
, 0);
1380 if (matches(*argv
, "add") == 0)
1381 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_EXCL
,
1383 if (matches(*argv
, "change") == 0 || strcmp(*argv
, "chg") == 0)
1384 return iproute_modify(RTM_NEWROUTE
, NLM_F_REPLACE
,
1386 if (matches(*argv
, "replace") == 0)
1387 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_REPLACE
,
1389 if (matches(*argv
, "prepend") == 0)
1390 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
,
1392 if (matches(*argv
, "append") == 0)
1393 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_APPEND
,
1395 if (matches(*argv
, "test") == 0)
1396 return iproute_modify(RTM_NEWROUTE
, NLM_F_EXCL
,
1398 if (matches(*argv
, "delete") == 0)
1399 return iproute_modify(RTM_DELROUTE
, 0,
1401 if (matches(*argv
, "list") == 0 || matches(*argv
, "show") == 0
1402 || matches(*argv
, "lst") == 0)
1403 return iproute_list_or_flush(argc
-1, argv
+1, 0);
1404 if (matches(*argv
, "get") == 0)
1405 return iproute_get(argc
-1, argv
+1);
1406 if (matches(*argv
, "flush") == 0)
1407 return iproute_list_or_flush(argc
-1, argv
+1, 1);
1408 if (matches(*argv
, "help") == 0)
1410 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv
);