]>
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>
31 #include <linux/ip_mp_alg.h>
35 #include "ip_common.h"
38 #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",
55 static void usage(void) __attribute__((noreturn
));
57 static void usage(void)
59 fprintf(stderr
, "Usage: ip route { list | flush } SELECTOR\n");
60 fprintf(stderr
, " ip route get ADDRESS [ from ADDRESS iif STRING ]\n");
61 fprintf(stderr
, " [ oif STRING ] [ tos TOS ]\n");
62 fprintf(stderr
, " ip route { add | del | change | append | replace | monitor } ROUTE\n");
63 fprintf(stderr
, "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n");
64 fprintf(stderr
, " [ table TABLE_ID ] [ proto RTPROTO ]\n");
65 fprintf(stderr
, " [ type TYPE ] [ scope SCOPE ]\n");
66 fprintf(stderr
, "ROUTE := NODE_SPEC [ INFO_SPEC ]\n");
67 fprintf(stderr
, "NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n");
68 fprintf(stderr
, " [ table TABLE_ID ] [ proto RTPROTO ]\n");
69 fprintf(stderr
, " [ scope SCOPE ] [ metric METRIC ]\n");
70 fprintf(stderr
, " [ mpath MP_ALGO ]\n");
71 fprintf(stderr
, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n");
72 fprintf(stderr
, "NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
73 fprintf(stderr
, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]\n");
74 fprintf(stderr
, " [ rtt NUMBER ] [ rttvar NUMBER ]\n");
75 fprintf(stderr
, " [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n");
76 fprintf(stderr
, " [ ssthresh NUMBER ] [ realms REALM ]\n");
77 fprintf(stderr
, "TYPE := [ unicast | local | broadcast | multicast | throw |\n");
78 fprintf(stderr
, " unreachable | prohibit | blackhole | nat ]\n");
79 fprintf(stderr
, "TABLE_ID := [ local | main | default | all | NUMBER ]\n");
80 fprintf(stderr
, "SCOPE := [ host | link | global | NUMBER ]\n");
81 fprintf(stderr
, "FLAGS := [ equalize ]\n");
82 fprintf(stderr
, "MP_ALGO := { rr | drr | random | wrandom }\n");
83 fprintf(stderr
, "NHFLAGS := [ onlink | pervasive ]\n");
84 fprintf(stderr
, "RTPROTO := [ kernel | boot | static | NUMBER ]\n");
97 int protocol
, protocolmask
;
103 int realm
, realmmask
;
104 inet_prefix rprefsrc
;
112 static char *mp_alg_names
[IP_MP_ALG_MAX
+1] = {
113 [IP_MP_ALG_NONE
] = "none",
114 [IP_MP_ALG_RR
] = "rr",
115 [IP_MP_ALG_DRR
] = "drr",
116 [IP_MP_ALG_RANDOM
] = "random",
117 [IP_MP_ALG_WRANDOM
] = "wrandom"
120 static int flush_update(void)
122 if (rtnl_send(&rth
, filter
.flushb
, filter
.flushp
) < 0) {
123 perror("Failed to send flush request\n");
130 int print_route(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
, void *arg
)
132 FILE *fp
= (FILE*)arg
;
133 struct rtmsg
*r
= NLMSG_DATA(n
);
134 int len
= n
->nlmsg_len
;
135 struct rtattr
* tb
[RTA_MAX
+1];
142 static int ip6_multiple_tables
;
147 if (n
->nlmsg_type
!= RTM_NEWROUTE
&& n
->nlmsg_type
!= RTM_DELROUTE
) {
148 fprintf(stderr
, "Not a route: %08x %08x %08x\n",
149 n
->nlmsg_len
, n
->nlmsg_type
, n
->nlmsg_flags
);
152 if (filter
.flushb
&& n
->nlmsg_type
!= RTM_NEWROUTE
)
154 len
-= NLMSG_LENGTH(sizeof(*r
));
156 fprintf(stderr
, "BUG: wrong nlmsg len %d\n", len
);
160 if (r
->rtm_family
== AF_INET6
)
162 else if (r
->rtm_family
== AF_INET
)
164 else if (r
->rtm_family
== AF_DECnet
)
166 else if (r
->rtm_family
== AF_IPX
)
169 parse_rtattr(tb
, RTA_MAX
, RTM_RTA(r
), len
);
170 table
= rtm_get_table(r
, tb
);
172 if (r
->rtm_family
== AF_INET6
&& table
!= RT_TABLE_MAIN
)
173 ip6_multiple_tables
= 1;
175 if (r
->rtm_family
== AF_INET6
&& !ip6_multiple_tables
) {
177 if (!(r
->rtm_flags
&RTM_F_CLONED
))
181 if (!filter
.cloned
&& r
->rtm_flags
&RTM_F_CLONED
)
183 if (filter
.tb
== RT_TABLE_LOCAL
) {
184 if (r
->rtm_type
!= RTN_LOCAL
)
186 } else if (filter
.tb
== RT_TABLE_MAIN
) {
187 if (r
->rtm_type
== RTN_LOCAL
)
195 if (!(r
->rtm_flags
&RTM_F_CLONED
))
198 if (filter
.tb
> 0 && filter
.tb
!= table
)
201 if ((filter
.protocol
^r
->rtm_protocol
)&filter
.protocolmask
)
203 if ((filter
.scope
^r
->rtm_scope
)&filter
.scopemask
)
205 if ((filter
.type
^r
->rtm_type
)&filter
.typemask
)
207 if ((filter
.tos
^r
->rtm_tos
)&filter
.tosmask
)
209 if (filter
.rdst
.family
&&
210 (r
->rtm_family
!= filter
.rdst
.family
|| filter
.rdst
.bitlen
> r
->rtm_dst_len
))
212 if (filter
.mdst
.family
&&
213 (r
->rtm_family
!= filter
.mdst
.family
||
214 (filter
.mdst
.bitlen
>= 0 && filter
.mdst
.bitlen
< r
->rtm_dst_len
)))
216 if (filter
.rsrc
.family
&&
217 (r
->rtm_family
!= filter
.rsrc
.family
|| filter
.rsrc
.bitlen
> r
->rtm_src_len
))
219 if (filter
.msrc
.family
&&
220 (r
->rtm_family
!= filter
.msrc
.family
||
221 (filter
.msrc
.bitlen
>= 0 && filter
.msrc
.bitlen
< r
->rtm_src_len
)))
223 if (filter
.rvia
.family
&& r
->rtm_family
!= filter
.rvia
.family
)
225 if (filter
.rprefsrc
.family
&& r
->rtm_family
!= filter
.rprefsrc
.family
)
228 memset(&dst
, 0, sizeof(dst
));
229 dst
.family
= r
->rtm_family
;
231 memcpy(&dst
.data
, RTA_DATA(tb
[RTA_DST
]), (r
->rtm_dst_len
+7)/8);
232 if (filter
.rsrc
.family
|| filter
.msrc
.family
) {
233 memset(&src
, 0, sizeof(src
));
234 src
.family
= r
->rtm_family
;
236 memcpy(&src
.data
, RTA_DATA(tb
[RTA_SRC
]), (r
->rtm_src_len
+7)/8);
238 if (filter
.rvia
.bitlen
>0) {
239 memset(&via
, 0, sizeof(via
));
240 via
.family
= r
->rtm_family
;
242 memcpy(&via
.data
, RTA_DATA(tb
[RTA_GATEWAY
]), host_len
/8);
244 if (filter
.rprefsrc
.bitlen
>0) {
245 memset(&prefsrc
, 0, sizeof(prefsrc
));
246 prefsrc
.family
= r
->rtm_family
;
248 memcpy(&prefsrc
.data
, RTA_DATA(tb
[RTA_PREFSRC
]), host_len
/8);
251 if (filter
.rdst
.family
&& inet_addr_match(&dst
, &filter
.rdst
, filter
.rdst
.bitlen
))
253 if (filter
.mdst
.family
&& filter
.mdst
.bitlen
>= 0 &&
254 inet_addr_match(&dst
, &filter
.mdst
, r
->rtm_dst_len
))
257 if (filter
.rsrc
.family
&& inet_addr_match(&src
, &filter
.rsrc
, filter
.rsrc
.bitlen
))
259 if (filter
.msrc
.family
&& filter
.msrc
.bitlen
>= 0 &&
260 inet_addr_match(&src
, &filter
.msrc
, r
->rtm_src_len
))
263 if (filter
.rvia
.family
&& inet_addr_match(&via
, &filter
.rvia
, filter
.rvia
.bitlen
))
265 if (filter
.rprefsrc
.family
&& inet_addr_match(&prefsrc
, &filter
.rprefsrc
, filter
.rprefsrc
.bitlen
))
267 if (filter
.realmmask
) {
270 realms
= *(__u32
*)RTA_DATA(tb
[RTA_FLOW
]);
271 if ((realms
^filter
.realm
)&filter
.realmmask
)
274 if (filter
.iifmask
) {
277 iif
= *(int*)RTA_DATA(tb
[RTA_IIF
]);
278 if ((iif
^filter
.iif
)&filter
.iifmask
)
281 if (filter
.oifmask
) {
284 oif
= *(int*)RTA_DATA(tb
[RTA_OIF
]);
285 if ((oif
^filter
.oif
)&filter
.oifmask
)
289 r
->rtm_family
== AF_INET6
&&
290 r
->rtm_dst_len
== 0 &&
291 r
->rtm_type
== RTN_UNREACHABLE
&&
293 *(int*)RTA_DATA(tb
[RTA_PRIORITY
]) == -1)
298 if (NLMSG_ALIGN(filter
.flushp
) + n
->nlmsg_len
> filter
.flushe
) {
302 fn
= (struct nlmsghdr
*)(filter
.flushb
+ NLMSG_ALIGN(filter
.flushp
));
303 memcpy(fn
, n
, n
->nlmsg_len
);
304 fn
->nlmsg_type
= RTM_DELROUTE
;
305 fn
->nlmsg_flags
= NLM_F_REQUEST
;
306 fn
->nlmsg_seq
= ++rth
.seq
;
307 filter
.flushp
= (((char*)fn
) + n
->nlmsg_len
) - filter
.flushb
;
313 if (n
->nlmsg_type
== RTM_DELROUTE
)
314 fprintf(fp
, "Deleted ");
315 if (r
->rtm_type
!= RTN_UNICAST
&& !filter
.type
)
316 fprintf(fp
, "%s ", rtnl_rtntype_n2a(r
->rtm_type
, b1
, sizeof(b1
)));
319 if (r
->rtm_dst_len
!= host_len
) {
320 fprintf(fp
, "%s/%u ", rt_addr_n2a(r
->rtm_family
,
321 RTA_PAYLOAD(tb
[RTA_DST
]),
322 RTA_DATA(tb
[RTA_DST
]),
327 fprintf(fp
, "%s ", format_host(r
->rtm_family
,
328 RTA_PAYLOAD(tb
[RTA_DST
]),
329 RTA_DATA(tb
[RTA_DST
]),
333 } else if (r
->rtm_dst_len
) {
334 fprintf(fp
, "0/%d ", r
->rtm_dst_len
);
336 fprintf(fp
, "default ");
339 if (r
->rtm_src_len
!= host_len
) {
340 fprintf(fp
, "from %s/%u ", rt_addr_n2a(r
->rtm_family
,
341 RTA_PAYLOAD(tb
[RTA_SRC
]),
342 RTA_DATA(tb
[RTA_SRC
]),
347 fprintf(fp
, "from %s ", format_host(r
->rtm_family
,
348 RTA_PAYLOAD(tb
[RTA_SRC
]),
349 RTA_DATA(tb
[RTA_SRC
]),
353 } else if (r
->rtm_src_len
) {
354 fprintf(fp
, "from 0/%u ", r
->rtm_src_len
);
356 if (r
->rtm_tos
&& filter
.tosmask
!= -1) {
358 fprintf(fp
, "tos %s ", rtnl_dsfield_n2a(r
->rtm_tos
, b1
, sizeof(b1
)));
361 if (tb
[RTA_MP_ALGO
]) {
362 __u32 mp_alg
= *(__u32
*) RTA_DATA(tb
[RTA_MP_ALGO
]);
363 if (mp_alg
> IP_MP_ALG_NONE
) {
364 fprintf(fp
, "mpath %s ",
365 mp_alg
< IP_MP_ALG_MAX
? mp_alg_names
[mp_alg
] : "unknown");
369 if (tb
[RTA_GATEWAY
] && filter
.rvia
.bitlen
!= host_len
) {
370 fprintf(fp
, "via %s ",
371 format_host(r
->rtm_family
,
372 RTA_PAYLOAD(tb
[RTA_GATEWAY
]),
373 RTA_DATA(tb
[RTA_GATEWAY
]),
374 abuf
, sizeof(abuf
)));
376 if (tb
[RTA_OIF
] && filter
.oifmask
!= -1)
377 fprintf(fp
, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb
[RTA_OIF
])));
379 if (!(r
->rtm_flags
&RTM_F_CLONED
)) {
380 if (table
!= RT_TABLE_MAIN
&& !filter
.tb
)
381 fprintf(fp
, " table %s ", rtnl_rttable_n2a(table
, b1
, sizeof(b1
)));
382 if (r
->rtm_protocol
!= RTPROT_BOOT
&& filter
.protocolmask
!= -1)
383 fprintf(fp
, " proto %s ", rtnl_rtprot_n2a(r
->rtm_protocol
, b1
, sizeof(b1
)));
384 if (r
->rtm_scope
!= RT_SCOPE_UNIVERSE
&& filter
.scopemask
!= -1)
385 fprintf(fp
, " scope %s ", rtnl_rtscope_n2a(r
->rtm_scope
, b1
, sizeof(b1
)));
387 if (tb
[RTA_PREFSRC
] && filter
.rprefsrc
.bitlen
!= host_len
) {
388 /* Do not use format_host(). It is our local addr
389 and symbolic name will not be useful.
391 fprintf(fp
, " src %s ",
392 rt_addr_n2a(r
->rtm_family
,
393 RTA_PAYLOAD(tb
[RTA_PREFSRC
]),
394 RTA_DATA(tb
[RTA_PREFSRC
]),
395 abuf
, sizeof(abuf
)));
397 if (tb
[RTA_PRIORITY
])
398 fprintf(fp
, " metric %d ", *(__u32
*)RTA_DATA(tb
[RTA_PRIORITY
]));
399 if (r
->rtm_flags
& RTNH_F_DEAD
)
400 fprintf(fp
, "dead ");
401 if (r
->rtm_flags
& RTNH_F_ONLINK
)
402 fprintf(fp
, "onlink ");
403 if (r
->rtm_flags
& RTNH_F_PERVASIVE
)
404 fprintf(fp
, "pervasive ");
405 if (r
->rtm_flags
& RTM_F_EQUALIZE
)
406 fprintf(fp
, "equalize ");
407 if (r
->rtm_flags
& RTM_F_NOTIFY
)
408 fprintf(fp
, "notify ");
410 if (tb
[RTA_FLOW
] && filter
.realmmask
!= ~0U) {
411 __u32 to
= *(__u32
*)RTA_DATA(tb
[RTA_FLOW
]);
414 fprintf(fp
, "realm%s ", from
? "s" : "");
417 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
420 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
422 if ((r
->rtm_flags
&RTM_F_CLONED
) && r
->rtm_family
== AF_INET
) {
423 __u32 flags
= r
->rtm_flags
&~0xFFFF;
426 fprintf(fp
, "%s cache ", _SL_
);
428 #define PRTFL(fl,flname) if (flags&RTCF_##fl) { \
429 flags &= ~RTCF_##fl; \
430 fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \
432 PRTFL(LOCAL
, "local");
433 PRTFL(REJECT
, "reject");
434 PRTFL(MULTICAST
, "mc");
435 PRTFL(BROADCAST
, "brd");
436 PRTFL(DNAT
, "dst-nat");
437 PRTFL(SNAT
, "src-nat");
439 PRTFL(DIRECTDST
, "dst-direct");
440 PRTFL(DIRECTSRC
, "src-direct");
441 PRTFL(REDIRECTED
, "redirected");
442 PRTFL(DOREDIRECT
, "redirect");
443 PRTFL(FAST
, "fastroute");
444 PRTFL(NOTIFY
, "notify");
445 PRTFL(TPROXY
, "proxy");
447 PRTFL(EQUALIZE
, "equalize");
450 fprintf(fp
, "%s%x> ", first
? "<" : "", flags
);
451 if (tb
[RTA_CACHEINFO
]) {
452 struct rta_cacheinfo
*ci
= RTA_DATA(tb
[RTA_CACHEINFO
]);
455 if (ci
->rta_expires
!= 0)
456 fprintf(fp
, " expires %dsec", ci
->rta_expires
/hz
);
457 if (ci
->rta_error
!= 0)
458 fprintf(fp
, " error %d", ci
->rta_error
);
461 fprintf(fp
, " users %d", ci
->rta_clntref
);
462 if (ci
->rta_used
!= 0)
463 fprintf(fp
, " used %d", ci
->rta_used
);
464 if (ci
->rta_lastuse
!= 0)
465 fprintf(fp
, " age %dsec", ci
->rta_lastuse
/hz
);
467 #ifdef RTNETLINK_HAVE_PEERINFO
469 fprintf(fp
, " ipid 0x%04x", ci
->rta_id
);
470 if (ci
->rta_ts
|| ci
->rta_tsage
)
471 fprintf(fp
, " ts 0x%x tsage %dsec", ci
->rta_ts
, ci
->rta_tsage
);
474 } else if (r
->rtm_family
== AF_INET6
) {
475 struct rta_cacheinfo
*ci
= NULL
;
476 if (tb
[RTA_CACHEINFO
])
477 ci
= RTA_DATA(tb
[RTA_CACHEINFO
]);
478 if ((r
->rtm_flags
& RTM_F_CLONED
) || (ci
&& ci
->rta_expires
)) {
481 if (r
->rtm_flags
& RTM_F_CLONED
)
482 fprintf(fp
, "%s cache ", _SL_
);
484 fprintf(fp
, " expires %dsec", ci
->rta_expires
/hz
);
485 if (ci
->rta_error
!= 0)
486 fprintf(fp
, " error %d", ci
->rta_error
);
489 fprintf(fp
, " users %d", ci
->rta_clntref
);
490 if (ci
->rta_used
!= 0)
491 fprintf(fp
, " used %d", ci
->rta_used
);
492 if (ci
->rta_lastuse
!= 0)
493 fprintf(fp
, " age %dsec", ci
->rta_lastuse
/hz
);
496 if (ci
->rta_error
!= 0)
497 fprintf(fp
, " error %d", ci
->rta_error
);
500 if (tb
[RTA_METRICS
]) {
503 struct rtattr
*mxrta
[RTAX_MAX
+1];
505 parse_rtattr(mxrta
, RTAX_MAX
, RTA_DATA(tb
[RTA_METRICS
]),
506 RTA_PAYLOAD(tb
[RTA_METRICS
]));
507 if (mxrta
[RTAX_LOCK
])
508 mxlock
= *(unsigned*)RTA_DATA(mxrta
[RTAX_LOCK
]);
510 for (i
=2; i
<= RTAX_MAX
; i
++) {
511 if (mxrta
[i
] == NULL
)
516 if (i
< sizeof(mx_names
)/sizeof(char*) && mx_names
[i
])
517 fprintf(fp
, " %s", mx_names
[i
]);
519 fprintf(fp
, " metric %d", i
);
521 fprintf(fp
, " lock");
523 if (i
!= RTAX_RTT
&& i
!= RTAX_RTTVAR
)
524 fprintf(fp
, " %u", *(unsigned*)RTA_DATA(mxrta
[i
]));
526 unsigned val
= *(unsigned*)RTA_DATA(mxrta
[i
]);
534 fprintf(fp
, " %ums", val
/hz
);
536 fprintf(fp
, " %.2fms", (float)val
/hz
);
540 if (tb
[RTA_IIF
] && filter
.iifmask
!= -1) {
541 fprintf(fp
, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb
[RTA_IIF
])));
543 if (tb
[RTA_MULTIPATH
]) {
544 struct rtnexthop
*nh
= RTA_DATA(tb
[RTA_MULTIPATH
]);
547 len
= RTA_PAYLOAD(tb
[RTA_MULTIPATH
]);
550 if (len
< sizeof(*nh
))
552 if (nh
->rtnh_len
> len
)
554 if (r
->rtm_flags
&RTM_F_CLONED
&& r
->rtm_type
== RTN_MULTICAST
) {
556 fprintf(fp
, " Oifs:");
560 fprintf(fp
, "%s\tnexthop", _SL_
);
561 if (nh
->rtnh_len
> sizeof(*nh
)) {
562 parse_rtattr(tb
, RTA_MAX
, RTNH_DATA(nh
), nh
->rtnh_len
- sizeof(*nh
));
563 if (tb
[RTA_GATEWAY
]) {
564 fprintf(fp
, " via %s ",
565 format_host(r
->rtm_family
,
566 RTA_PAYLOAD(tb
[RTA_GATEWAY
]),
567 RTA_DATA(tb
[RTA_GATEWAY
]),
568 abuf
, sizeof(abuf
)));
571 __u32 to
= *(__u32
*)RTA_DATA(tb
[RTA_FLOW
]);
574 fprintf(fp
, " realm%s ", from
? "s" : "");
577 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
580 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
583 if (r
->rtm_flags
&RTM_F_CLONED
&& r
->rtm_type
== RTN_MULTICAST
) {
584 fprintf(fp
, " %s", ll_index_to_name(nh
->rtnh_ifindex
));
585 if (nh
->rtnh_hops
!= 1)
586 fprintf(fp
, "(ttl>%d)", nh
->rtnh_hops
);
588 fprintf(fp
, " dev %s", ll_index_to_name(nh
->rtnh_ifindex
));
589 fprintf(fp
, " weight %d", nh
->rtnh_hops
+1);
591 if (nh
->rtnh_flags
& RTNH_F_DEAD
)
592 fprintf(fp
, " dead");
593 if (nh
->rtnh_flags
& RTNH_F_ONLINK
)
594 fprintf(fp
, " onlink");
595 if (nh
->rtnh_flags
& RTNH_F_PERVASIVE
)
596 fprintf(fp
, " pervasive");
597 len
-= NLMSG_ALIGN(nh
->rtnh_len
);
607 int parse_one_nh(struct rtattr
*rta
, struct rtnexthop
*rtnh
, int *argcp
, char ***argvp
)
610 char **argv
= *argvp
;
612 while (++argv
, --argc
> 0) {
613 if (strcmp(*argv
, "via") == 0) {
615 rta_addattr32(rta
, 4096, RTA_GATEWAY
, get_addr32(*argv
));
616 rtnh
->rtnh_len
+= sizeof(struct rtattr
) + 4;
617 } else if (strcmp(*argv
, "dev") == 0) {
619 if ((rtnh
->rtnh_ifindex
= ll_name_to_index(*argv
)) == 0) {
620 fprintf(stderr
, "Cannot find device \"%s\"\n", *argv
);
623 } else if (strcmp(*argv
, "weight") == 0) {
626 if (get_unsigned(&w
, *argv
, 0) || w
== 0 || w
> 256)
627 invarg("\"weight\" is invalid\n", *argv
);
628 rtnh
->rtnh_hops
= w
- 1;
629 } else if (strcmp(*argv
, "onlink") == 0) {
630 rtnh
->rtnh_flags
|= RTNH_F_ONLINK
;
631 } else if (matches(*argv
, "realms") == 0) {
634 if (get_rt_realms(&realm
, *argv
))
635 invarg("\"realm\" value is invalid\n", *argv
);
636 rta_addattr32(rta
, 4096, RTA_FLOW
, realm
);
637 rtnh
->rtnh_len
+= sizeof(struct rtattr
) + 4;
646 int parse_nexthops(struct nlmsghdr
*n
, struct rtmsg
*r
, int argc
, char **argv
)
649 struct rtattr
*rta
= (void*)buf
;
650 struct rtnexthop
*rtnh
;
652 rta
->rta_type
= RTA_MULTIPATH
;
653 rta
->rta_len
= RTA_LENGTH(0);
654 rtnh
= RTA_DATA(rta
);
657 if (strcmp(*argv
, "nexthop") != 0) {
658 fprintf(stderr
, "Error: \"nexthop\" or end of line is expected instead of \"%s\"\n", *argv
);
662 fprintf(stderr
, "Error: unexpected end of line after \"nexthop\"\n");
665 memset(rtnh
, 0, sizeof(*rtnh
));
666 rtnh
->rtnh_len
= sizeof(*rtnh
);
667 rta
->rta_len
+= rtnh
->rtnh_len
;
668 parse_one_nh(rta
, rtnh
, &argc
, &argv
);
669 rtnh
= RTNH_NEXT(rtnh
);
672 if (rta
->rta_len
> RTA_LENGTH(0))
673 addattr_l(n
, 1024, RTA_MULTIPATH
, RTA_DATA(rta
), RTA_PAYLOAD(rta
));
678 int iproute_modify(int cmd
, unsigned flags
, int argc
, char **argv
)
686 struct rtattr
* mxrta
= (void*)mxbuf
;
697 memset(&req
, 0, sizeof(req
));
699 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
700 req
.n
.nlmsg_flags
= NLM_F_REQUEST
|flags
;
701 req
.n
.nlmsg_type
= cmd
;
702 req
.r
.rtm_family
= preferred_family
;
703 req
.r
.rtm_table
= RT_TABLE_MAIN
;
704 req
.r
.rtm_scope
= RT_SCOPE_NOWHERE
;
706 if (cmd
!= RTM_DELROUTE
) {
707 req
.r
.rtm_protocol
= RTPROT_BOOT
;
708 req
.r
.rtm_scope
= RT_SCOPE_UNIVERSE
;
709 req
.r
.rtm_type
= RTN_UNICAST
;
712 mxrta
->rta_type
= RTA_METRICS
;
713 mxrta
->rta_len
= RTA_LENGTH(0);
716 if (strcmp(*argv
, "src") == 0) {
719 get_addr(&addr
, *argv
, req
.r
.rtm_family
);
720 if (req
.r
.rtm_family
== AF_UNSPEC
)
721 req
.r
.rtm_family
= addr
.family
;
722 addattr_l(&req
.n
, sizeof(req
), RTA_PREFSRC
, &addr
.data
, addr
.bytelen
);
723 } else if (strcmp(*argv
, "via") == 0) {
727 get_addr(&addr
, *argv
, req
.r
.rtm_family
);
728 if (req
.r
.rtm_family
== AF_UNSPEC
)
729 req
.r
.rtm_family
= addr
.family
;
730 addattr_l(&req
.n
, sizeof(req
), RTA_GATEWAY
, &addr
.data
, addr
.bytelen
);
731 } else if (strcmp(*argv
, "from") == 0) {
734 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
735 if (req
.r
.rtm_family
== AF_UNSPEC
)
736 req
.r
.rtm_family
= addr
.family
;
738 addattr_l(&req
.n
, sizeof(req
), RTA_SRC
, &addr
.data
, addr
.bytelen
);
739 req
.r
.rtm_src_len
= addr
.bitlen
;
740 } else if (strcmp(*argv
, "tos") == 0 ||
741 matches(*argv
, "dsfield") == 0) {
744 if (rtnl_dsfield_a2n(&tos
, *argv
))
745 invarg("\"tos\" value is invalid\n", *argv
);
747 } else if (matches(*argv
, "metric") == 0 ||
748 matches(*argv
, "priority") == 0 ||
749 matches(*argv
, "preference") == 0) {
752 if (get_u32(&metric
, *argv
, 0))
753 invarg("\"metric\" value is invalid\n", *argv
);
754 addattr32(&req
.n
, sizeof(req
), RTA_PRIORITY
, metric
);
755 } else if (strcmp(*argv
, "scope") == 0) {
758 if (rtnl_rtscope_a2n(&scope
, *argv
))
759 invarg("invalid \"scope\" value\n", *argv
);
760 req
.r
.rtm_scope
= scope
;
762 } else if (strcmp(*argv
, "mtu") == 0) {
765 if (strcmp(*argv
, "lock") == 0) {
766 mxlock
|= (1<<RTAX_MTU
);
769 if (get_unsigned(&mtu
, *argv
, 0))
770 invarg("\"mtu\" value is invalid\n", *argv
);
771 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_MTU
, mtu
);
773 } else if (strcmp(*argv
, "advmss") == 0) {
776 if (strcmp(*argv
, "lock") == 0) {
777 mxlock
|= (1<<RTAX_ADVMSS
);
780 if (get_unsigned(&mss
, *argv
, 0))
781 invarg("\"mss\" value is invalid\n", *argv
);
782 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_ADVMSS
, mss
);
784 #ifdef RTAX_REORDERING
785 } else if (matches(*argv
, "reordering") == 0) {
788 if (strcmp(*argv
, "lock") == 0) {
789 mxlock
|= (1<<RTAX_REORDERING
);
792 if (get_unsigned(&reord
, *argv
, 0))
793 invarg("\"reordering\" value is invalid\n", *argv
);
794 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_REORDERING
, reord
);
796 } else if (strcmp(*argv
, "rtt") == 0) {
799 if (strcmp(*argv
, "lock") == 0) {
800 mxlock
|= (1<<RTAX_RTT
);
803 if (get_unsigned(&rtt
, *argv
, 0))
804 invarg("\"rtt\" value is invalid\n", *argv
);
805 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_RTT
, rtt
);
806 } else if (matches(*argv
, "window") == 0) {
809 if (strcmp(*argv
, "lock") == 0) {
810 mxlock
|= (1<<RTAX_WINDOW
);
813 if (get_unsigned(&win
, *argv
, 0))
814 invarg("\"window\" value is invalid\n", *argv
);
815 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_WINDOW
, win
);
816 } else if (matches(*argv
, "cwnd") == 0) {
819 if (strcmp(*argv
, "lock") == 0) {
820 mxlock
|= (1<<RTAX_CWND
);
823 if (get_unsigned(&win
, *argv
, 0))
824 invarg("\"cwnd\" value is invalid\n", *argv
);
825 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_CWND
, win
);
826 } else if (matches(*argv
, "initcwnd") == 0) {
829 if (strcmp(*argv
, "lock") == 0) {
830 mxlock
|= (1<<RTAX_INITCWND
);
833 if (get_unsigned(&win
, *argv
, 0))
834 invarg("\"initcwnd\" value is invalid\n", *argv
);
835 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_INITCWND
, win
);
836 } else if (matches(*argv
, "rttvar") == 0) {
839 if (strcmp(*argv
, "lock") == 0) {
840 mxlock
|= (1<<RTAX_RTTVAR
);
843 if (get_unsigned(&win
, *argv
, 0))
844 invarg("\"rttvar\" value is invalid\n", *argv
);
845 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_RTTVAR
, win
);
846 } else if (matches(*argv
, "ssthresh") == 0) {
849 if (strcmp(*argv
, "lock") == 0) {
850 mxlock
|= (1<<RTAX_SSTHRESH
);
853 if (get_unsigned(&win
, *argv
, 0))
854 invarg("\"ssthresh\" value is invalid\n", *argv
);
855 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_SSTHRESH
, win
);
856 } else if (matches(*argv
, "realms") == 0) {
859 if (get_rt_realms(&realm
, *argv
))
860 invarg("\"realm\" value is invalid\n", *argv
);
861 addattr32(&req
.n
, sizeof(req
), RTA_FLOW
, realm
);
862 } else if (strcmp(*argv
, "onlink") == 0) {
863 req
.r
.rtm_flags
|= RTNH_F_ONLINK
;
864 } else if (matches(*argv
, "equalize") == 0 ||
865 strcmp(*argv
, "eql") == 0) {
866 req
.r
.rtm_flags
|= RTM_F_EQUALIZE
;
867 } else if (strcmp(*argv
, "nexthop") == 0) {
870 } else if (matches(*argv
, "protocol") == 0) {
873 if (rtnl_rtprot_a2n(&prot
, *argv
))
874 invarg("\"protocol\" value is invalid\n", *argv
);
875 req
.r
.rtm_protocol
= prot
;
877 } else if (matches(*argv
, "table") == 0) {
880 if (rtnl_rttable_a2n(&tid
, *argv
))
881 invarg("\"table\" value is invalid\n", *argv
);
883 req
.r
.rtm_table
= tid
;
885 req
.r
.rtm_table
= RT_TABLE_UNSPEC
;
886 addattr32(&req
.n
, sizeof(req
), RTA_TABLE
, tid
);
889 } else if (strcmp(*argv
, "dev") == 0 ||
890 strcmp(*argv
, "oif") == 0) {
893 } else if (strcmp(*argv
, "mpath") == 0 ||
894 strcmp(*argv
, "mp") == 0) {
896 __u32 mp_alg
= IP_MP_ALG_NONE
;
899 for (i
= 1; i
< ARRAY_SIZE(mp_alg_names
); i
++)
900 if (strcmp(*argv
, mp_alg_names
[i
]) == 0)
902 if (mp_alg
== IP_MP_ALG_NONE
)
903 invarg("\"mpath\" value is invalid\n", *argv
);
904 addattr_l(&req
.n
, sizeof(req
), RTA_MP_ALGO
, &mp_alg
, sizeof(mp_alg
));
909 if (strcmp(*argv
, "to") == 0) {
912 if ((**argv
< '0' || **argv
> '9') &&
913 rtnl_rtntype_a2n(&type
, *argv
) == 0) {
915 req
.r
.rtm_type
= type
;
919 if (matches(*argv
, "help") == 0)
922 duparg2("to", *argv
);
923 get_prefix(&dst
, *argv
, req
.r
.rtm_family
);
924 if (req
.r
.rtm_family
== AF_UNSPEC
)
925 req
.r
.rtm_family
= dst
.family
;
926 req
.r
.rtm_dst_len
= dst
.bitlen
;
929 addattr_l(&req
.n
, sizeof(req
), RTA_DST
, &dst
.data
, dst
.bytelen
);
940 if ((idx
= ll_name_to_index(d
)) == 0) {
941 fprintf(stderr
, "Cannot find device \"%s\"\n", d
);
944 addattr32(&req
.n
, sizeof(req
), RTA_OIF
, idx
);
948 if (mxrta
->rta_len
> RTA_LENGTH(0)) {
950 rta_addattr32(mxrta
, sizeof(mxbuf
), RTAX_LOCK
, mxlock
);
951 addattr_l(&req
.n
, sizeof(req
), RTA_METRICS
, RTA_DATA(mxrta
), RTA_PAYLOAD(mxrta
));
955 parse_nexthops(&req
.n
, &req
.r
, argc
, argv
);
958 if (req
.r
.rtm_type
== RTN_LOCAL
||
959 req
.r
.rtm_type
== RTN_BROADCAST
||
960 req
.r
.rtm_type
== RTN_NAT
||
961 req
.r
.rtm_type
== RTN_ANYCAST
)
962 req
.r
.rtm_table
= RT_TABLE_LOCAL
;
965 if (req
.r
.rtm_type
== RTN_LOCAL
||
966 req
.r
.rtm_type
== RTN_NAT
)
967 req
.r
.rtm_scope
= RT_SCOPE_HOST
;
968 else if (req
.r
.rtm_type
== RTN_BROADCAST
||
969 req
.r
.rtm_type
== RTN_MULTICAST
||
970 req
.r
.rtm_type
== RTN_ANYCAST
)
971 req
.r
.rtm_scope
= RT_SCOPE_LINK
;
972 else if (req
.r
.rtm_type
== RTN_UNICAST
||
973 req
.r
.rtm_type
== RTN_UNSPEC
) {
974 if (cmd
== RTM_DELROUTE
)
975 req
.r
.rtm_scope
= RT_SCOPE_NOWHERE
;
976 else if (!gw_ok
&& !nhs_ok
)
977 req
.r
.rtm_scope
= RT_SCOPE_LINK
;
981 if (req
.r
.rtm_family
== AF_UNSPEC
)
982 req
.r
.rtm_family
= AF_INET
;
984 if (rtnl_talk(&rth
, &req
.n
, 0, 0, NULL
, NULL
, NULL
) < 0)
990 static int rtnl_rtcache_request(struct rtnl_handle
*rth
, int family
)
996 struct sockaddr_nl nladdr
;
998 memset(&nladdr
, 0, sizeof(nladdr
));
999 memset(&req
, 0, sizeof(req
));
1000 nladdr
.nl_family
= AF_NETLINK
;
1002 req
.nlh
.nlmsg_len
= sizeof(req
);
1003 req
.nlh
.nlmsg_type
= RTM_GETROUTE
;
1004 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
|NLM_F_REQUEST
;
1005 req
.nlh
.nlmsg_pid
= 0;
1006 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
1007 req
.rtm
.rtm_family
= family
;
1008 req
.rtm
.rtm_flags
|= RTM_F_CLONED
;
1010 return sendto(rth
->fd
, (void*)&req
, sizeof(req
), 0, (struct sockaddr
*)&nladdr
, sizeof(nladdr
));
1013 static int iproute_flush_cache(void)
1015 #define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
1018 int flush_fd
= open (ROUTE_FLUSH_PATH
, O_WRONLY
);
1019 char *buffer
= "-1";
1022 fprintf (stderr
, "Cannot open \"%s\"\n", ROUTE_FLUSH_PATH
);
1026 len
= strlen (buffer
);
1028 if ((write (flush_fd
, (void *)buffer
, len
)) < len
) {
1029 fprintf (stderr
, "Cannot flush routing cache\n");
1037 static int iproute_list_or_flush(int argc
, char **argv
, int flush
)
1039 int do_ipv6
= preferred_family
;
1043 iproute_reset_filter();
1044 filter
.tb
= RT_TABLE_MAIN
;
1046 if (flush
&& argc
<= 0) {
1047 fprintf(stderr
, "\"ip route flush\" requires arguments.\n");
1052 if (matches(*argv
, "table") == 0) {
1055 if (rtnl_rttable_a2n(&tid
, *argv
)) {
1056 if (strcmp(*argv
, "all") == 0) {
1058 } else if (strcmp(*argv
, "cache") == 0) {
1060 } else if (strcmp(*argv
, "help") == 0) {
1063 invarg("table id value is invalid\n", *argv
);
1067 } else if (matches(*argv
, "cached") == 0 ||
1068 matches(*argv
, "cloned") == 0) {
1070 } else if (strcmp(*argv
, "tos") == 0 ||
1071 matches(*argv
, "dsfield") == 0) {
1074 if (rtnl_dsfield_a2n(&tos
, *argv
))
1075 invarg("TOS value is invalid\n", *argv
);
1077 filter
.tosmask
= -1;
1078 } else if (matches(*argv
, "protocol") == 0) {
1081 filter
.protocolmask
= -1;
1082 if (rtnl_rtprot_a2n(&prot
, *argv
)) {
1083 if (strcmp(*argv
, "all") != 0)
1084 invarg("invalid \"protocol\"\n", *argv
);
1086 filter
.protocolmask
= 0;
1088 filter
.protocol
= prot
;
1089 } else if (matches(*argv
, "scope") == 0) {
1092 filter
.scopemask
= -1;
1093 if (rtnl_rtscope_a2n(&scope
, *argv
)) {
1094 if (strcmp(*argv
, "all") != 0)
1095 invarg("invalid \"scope\"\n", *argv
);
1096 scope
= RT_SCOPE_NOWHERE
;
1097 filter
.scopemask
= 0;
1099 filter
.scope
= scope
;
1100 } else if (matches(*argv
, "type") == 0) {
1103 filter
.typemask
= -1;
1104 if (rtnl_rtntype_a2n(&type
, *argv
))
1105 invarg("node type value is invalid\n", *argv
);
1107 } else if (strcmp(*argv
, "dev") == 0 ||
1108 strcmp(*argv
, "oif") == 0) {
1111 } else if (strcmp(*argv
, "iif") == 0) {
1114 } else if (strcmp(*argv
, "via") == 0) {
1116 get_prefix(&filter
.rvia
, *argv
, do_ipv6
);
1117 } else if (strcmp(*argv
, "src") == 0) {
1119 get_prefix(&filter
.rprefsrc
, *argv
, do_ipv6
);
1120 } else if (matches(*argv
, "realms") == 0) {
1123 if (get_rt_realms(&realm
, *argv
))
1124 invarg("invalid realms\n", *argv
);
1125 filter
.realm
= realm
;
1126 filter
.realmmask
= ~0U;
1127 if ((filter
.realm
&0xFFFF) == 0 &&
1128 (*argv
)[strlen(*argv
) - 1] == '/')
1129 filter
.realmmask
&= ~0xFFFF;
1130 if ((filter
.realm
&0xFFFF0000U
) == 0 &&
1131 (strchr(*argv
, '/') == NULL
||
1133 filter
.realmmask
&= ~0xFFFF0000U
;
1134 } else if (matches(*argv
, "from") == 0) {
1136 if (matches(*argv
, "root") == 0) {
1138 get_prefix(&filter
.rsrc
, *argv
, do_ipv6
);
1139 } else if (matches(*argv
, "match") == 0) {
1141 get_prefix(&filter
.msrc
, *argv
, do_ipv6
);
1143 if (matches(*argv
, "exact") == 0) {
1146 get_prefix(&filter
.msrc
, *argv
, do_ipv6
);
1147 filter
.rsrc
= filter
.msrc
;
1150 if (matches(*argv
, "to") == 0) {
1153 if (matches(*argv
, "root") == 0) {
1155 get_prefix(&filter
.rdst
, *argv
, do_ipv6
);
1156 } else if (matches(*argv
, "match") == 0) {
1158 get_prefix(&filter
.mdst
, *argv
, do_ipv6
);
1160 if (matches(*argv
, "exact") == 0) {
1163 get_prefix(&filter
.mdst
, *argv
, do_ipv6
);
1164 filter
.rdst
= filter
.mdst
;
1170 if (do_ipv6
== AF_UNSPEC
&& filter
.tb
)
1179 if ((idx
= ll_name_to_index(id
)) == 0) {
1180 fprintf(stderr
, "Cannot find device \"%s\"\n", id
);
1184 filter
.iifmask
= -1;
1187 if ((idx
= ll_name_to_index(od
)) == 0) {
1188 fprintf(stderr
, "Cannot find device \"%s\"\n", od
);
1192 filter
.oifmask
= -1;
1198 char flushb
[4096-512];
1199 time_t start
= time(0);
1201 if (filter
.cloned
) {
1202 if (do_ipv6
!= AF_INET6
) {
1203 iproute_flush_cache();
1205 printf("*** IPv4 routing cache is flushed.\n");
1207 if (do_ipv6
== AF_INET
)
1211 filter
.flushb
= flushb
;
1213 filter
.flushe
= sizeof(flushb
);
1216 if (rtnl_wilddump_request(&rth
, do_ipv6
, RTM_GETROUTE
) < 0) {
1217 perror("Cannot send dump request");
1221 if (rtnl_dump_filter(&rth
, print_route
, stdout
, NULL
, NULL
) < 0) {
1222 fprintf(stderr
, "Flush terminated\n");
1225 if (filter
.flushed
== 0) {
1227 if (!filter
.cloned
|| do_ipv6
== AF_INET6
)
1228 fprintf(stderr
, "Nothing to flush.\n");
1229 } else if (show_stats
)
1230 printf("*** Flush is complete after %d round%s ***\n", round
, round
>1?"s":"");
1235 if (flush_update() < 0)
1238 if (time(0) - start
> 30) {
1239 printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
1240 time(0) - start
, filter
.flushed
);
1245 printf("\n*** Round %d, deleting %d entries ***\n", round
, filter
.flushed
);
1251 if (!filter
.cloned
) {
1252 if (rtnl_wilddump_request(&rth
, do_ipv6
, RTM_GETROUTE
) < 0) {
1253 perror("Cannot send dump request");
1257 if (rtnl_rtcache_request(&rth
, do_ipv6
) < 0) {
1258 perror("Cannot send dump request");
1263 if (rtnl_dump_filter(&rth
, print_route
, stdout
, NULL
, NULL
) < 0) {
1264 fprintf(stderr
, "Dump terminated\n");
1272 int iproute_get(int argc
, char **argv
)
1284 memset(&req
, 0, sizeof(req
));
1286 iproute_reset_filter();
1288 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
1289 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
1290 req
.n
.nlmsg_type
= RTM_GETROUTE
;
1291 req
.r
.rtm_family
= preferred_family
;
1292 req
.r
.rtm_table
= 0;
1293 req
.r
.rtm_protocol
= 0;
1294 req
.r
.rtm_scope
= 0;
1296 req
.r
.rtm_src_len
= 0;
1297 req
.r
.rtm_dst_len
= 0;
1301 if (strcmp(*argv
, "tos") == 0 ||
1302 matches(*argv
, "dsfield") == 0) {
1305 if (rtnl_dsfield_a2n(&tos
, *argv
))
1306 invarg("TOS value is invalid\n", *argv
);
1307 req
.r
.rtm_tos
= tos
;
1308 } else if (matches(*argv
, "from") == 0) {
1311 if (matches(*argv
, "help") == 0)
1314 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
1315 if (req
.r
.rtm_family
== AF_UNSPEC
)
1316 req
.r
.rtm_family
= addr
.family
;
1318 addattr_l(&req
.n
, sizeof(req
), RTA_SRC
, &addr
.data
, addr
.bytelen
);
1319 req
.r
.rtm_src_len
= addr
.bitlen
;
1320 } else if (matches(*argv
, "iif") == 0) {
1323 } else if (matches(*argv
, "oif") == 0 ||
1324 strcmp(*argv
, "dev") == 0) {
1327 } else if (matches(*argv
, "notify") == 0) {
1328 req
.r
.rtm_flags
|= RTM_F_NOTIFY
;
1329 } else if (matches(*argv
, "connected") == 0) {
1333 if (strcmp(*argv
, "to") == 0) {
1336 if (matches(*argv
, "help") == 0)
1338 get_prefix(&addr
, *argv
, req
.r
.rtm_family
);
1339 if (req
.r
.rtm_family
== AF_UNSPEC
)
1340 req
.r
.rtm_family
= addr
.family
;
1342 addattr_l(&req
.n
, sizeof(req
), RTA_DST
, &addr
.data
, addr
.bytelen
);
1343 req
.r
.rtm_dst_len
= addr
.bitlen
;
1348 if (req
.r
.rtm_dst_len
== 0) {
1349 fprintf(stderr
, "need at least destination address\n");
1359 if ((idx
= ll_name_to_index(idev
)) == 0) {
1360 fprintf(stderr
, "Cannot find device \"%s\"\n", idev
);
1363 addattr32(&req
.n
, sizeof(req
), RTA_IIF
, idx
);
1366 if ((idx
= ll_name_to_index(odev
)) == 0) {
1367 fprintf(stderr
, "Cannot find device \"%s\"\n", odev
);
1370 addattr32(&req
.n
, sizeof(req
), RTA_OIF
, idx
);
1374 if (req
.r
.rtm_family
== AF_UNSPEC
)
1375 req
.r
.rtm_family
= AF_INET
;
1377 if (rtnl_talk(&rth
, &req
.n
, 0, 0, &req
.n
, NULL
, NULL
) < 0)
1380 if (connected
&& !from_ok
) {
1381 struct rtmsg
*r
= NLMSG_DATA(&req
.n
);
1382 int len
= req
.n
.nlmsg_len
;
1383 struct rtattr
* tb
[RTA_MAX
+1];
1385 if (print_route(NULL
, &req
.n
, (void*)stdout
) < 0) {
1386 fprintf(stderr
, "An error :-)\n");
1390 if (req
.n
.nlmsg_type
!= RTM_NEWROUTE
) {
1391 fprintf(stderr
, "Not a route?\n");
1394 len
-= NLMSG_LENGTH(sizeof(*r
));
1396 fprintf(stderr
, "Wrong len %d\n", len
);
1400 parse_rtattr(tb
, RTA_MAX
, RTM_RTA(r
), len
);
1402 if (tb
[RTA_PREFSRC
]) {
1403 tb
[RTA_PREFSRC
]->rta_type
= RTA_SRC
;
1404 r
->rtm_src_len
= 8*RTA_PAYLOAD(tb
[RTA_PREFSRC
]);
1405 } else if (!tb
[RTA_SRC
]) {
1406 fprintf(stderr
, "Failed to connect the route\n");
1409 if (!odev
&& tb
[RTA_OIF
])
1410 tb
[RTA_OIF
]->rta_type
= 0;
1411 if (tb
[RTA_GATEWAY
])
1412 tb
[RTA_GATEWAY
]->rta_type
= 0;
1413 if (!idev
&& tb
[RTA_IIF
])
1414 tb
[RTA_IIF
]->rta_type
= 0;
1415 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
1416 req
.n
.nlmsg_type
= RTM_GETROUTE
;
1418 if (rtnl_talk(&rth
, &req
.n
, 0, 0, &req
.n
, NULL
, NULL
) < 0)
1422 if (print_route(NULL
, &req
.n
, (void*)stdout
) < 0) {
1423 fprintf(stderr
, "An error :-)\n");
1430 void iproute_reset_filter()
1432 memset(&filter
, 0, sizeof(filter
));
1433 filter
.mdst
.bitlen
= -1;
1434 filter
.msrc
.bitlen
= -1;
1437 int do_iproute(int argc
, char **argv
)
1440 return iproute_list_or_flush(0, NULL
, 0);
1442 if (matches(*argv
, "add") == 0)
1443 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_EXCL
,
1445 if (matches(*argv
, "change") == 0 || strcmp(*argv
, "chg") == 0)
1446 return iproute_modify(RTM_NEWROUTE
, NLM_F_REPLACE
,
1448 if (matches(*argv
, "replace") == 0)
1449 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_REPLACE
,
1451 if (matches(*argv
, "prepend") == 0)
1452 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
,
1454 if (matches(*argv
, "append") == 0)
1455 return iproute_modify(RTM_NEWROUTE
, NLM_F_CREATE
|NLM_F_APPEND
,
1457 if (matches(*argv
, "test") == 0)
1458 return iproute_modify(RTM_NEWROUTE
, NLM_F_EXCL
,
1460 if (matches(*argv
, "delete") == 0)
1461 return iproute_modify(RTM_DELROUTE
, 0,
1463 if (matches(*argv
, "list") == 0 || matches(*argv
, "show") == 0
1464 || matches(*argv
, "lst") == 0)
1465 return iproute_list_or_flush(argc
-1, argv
+1, 0);
1466 if (matches(*argv
, "get") == 0)
1467 return iproute_get(argc
-1, argv
+1);
1468 if (matches(*argv
, "flush") == 0)
1469 return iproute_list_or_flush(argc
-1, argv
+1, 1);
1470 if (matches(*argv
, "help") == 0)
1472 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv
);