]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iproute.c
iproute: refactor metrics print
[mirror_iproute2.git] / ip / iproute.c
1 /*
2 * iproute.c "ip route".
3 *
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.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <string.h>
18 #include <time.h>
19 #include <sys/time.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <netinet/ip.h>
23 #include <arpa/inet.h>
24 #include <linux/in_route.h>
25 #include <linux/icmpv6.h>
26 #include <errno.h>
27
28 #include "rt_names.h"
29 #include "utils.h"
30 #include "ip_common.h"
31
32 #ifndef RTAX_RTTVAR
33 #define RTAX_RTTVAR RTAX_HOPS
34 #endif
35
36 enum list_action {
37 IPROUTE_LIST,
38 IPROUTE_FLUSH,
39 IPROUTE_SAVE,
40 };
41 static const char *mx_names[RTAX_MAX+1] = {
42 [RTAX_MTU] = "mtu",
43 [RTAX_WINDOW] = "window",
44 [RTAX_RTT] = "rtt",
45 [RTAX_RTTVAR] = "rttvar",
46 [RTAX_SSTHRESH] = "ssthresh",
47 [RTAX_CWND] = "cwnd",
48 [RTAX_ADVMSS] = "advmss",
49 [RTAX_REORDERING] = "reordering",
50 [RTAX_HOPLIMIT] = "hoplimit",
51 [RTAX_INITCWND] = "initcwnd",
52 [RTAX_FEATURES] = "features",
53 [RTAX_RTO_MIN] = "rto_min",
54 [RTAX_INITRWND] = "initrwnd",
55 [RTAX_QUICKACK] = "quickack",
56 [RTAX_CC_ALGO] = "congctl",
57 [RTAX_FASTOPEN_NO_COOKIE] = "fastopen_no_cookie"
58 };
59 static void usage(void) __attribute__((noreturn));
60
61 static void usage(void)
62 {
63 fprintf(stderr,
64 "Usage: ip route { list | flush } SELECTOR\n"
65 " ip route save SELECTOR\n"
66 " ip route restore\n"
67 " ip route showdump\n"
68 " ip route get [ ROUTE_GET_FLAGS ] ADDRESS\n"
69 " [ from ADDRESS iif STRING ]\n"
70 " [ oif STRING ] [ tos TOS ]\n"
71 " [ mark NUMBER ] [ vrf NAME ]\n"
72 " [ uid NUMBER ]\n"
73 " ip route { add | del | change | append | replace } ROUTE\n"
74 "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n"
75 " [ table TABLE_ID ] [ vrf NAME ] [ proto RTPROTO ]\n"
76 " [ type TYPE ] [ scope SCOPE ]\n"
77 "ROUTE := NODE_SPEC [ INFO_SPEC ]\n"
78 "NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n"
79 " [ table TABLE_ID ] [ proto RTPROTO ]\n"
80 " [ scope SCOPE ] [ metric METRIC ]\n"
81 " [ ttl-propagate { enabled | disabled } ]\n"
82 "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n"
83 "NH := [ encap ENCAPTYPE ENCAPHDR ] [ via [ FAMILY ] ADDRESS ]\n"
84 " [ dev STRING ] [ weight NUMBER ] NHFLAGS\n"
85 "FAMILY := [ inet | inet6 | ipx | dnet | mpls | bridge | link ]\n"
86 "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n"
87 " [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n"
88 " [ window NUMBER ] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n"
89 " [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n"
90 " [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n"
91 " [ features FEATURES ] [ quickack BOOL ] [ congctl NAME ]\n"
92 " [ pref PREF ] [ expires TIME ] [ fastopen_no_cookie BOOL ]\n"
93 "TYPE := { unicast | local | broadcast | multicast | throw |\n"
94 " unreachable | prohibit | blackhole | nat }\n"
95 "TABLE_ID := [ local | main | default | all | NUMBER ]\n"
96 "SCOPE := [ host | link | global | NUMBER ]\n"
97 "NHFLAGS := [ onlink | pervasive ]\n"
98 "RTPROTO := [ kernel | boot | static | NUMBER ]\n"
99 "PREF := [ low | medium | high ]\n"
100 "TIME := NUMBER[s|ms]\n"
101 "BOOL := [1|0]\n"
102 "FEATURES := ecn\n"
103 "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local ]\n"
104 "ENCAPHDR := [ MPLSLABEL | SEG6HDR ]\n"
105 "SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n"
106 "SEGMODE := [ encap | inline ]\n"
107 "ROUTE_GET_FLAGS := [ fibmatch ]\n");
108 exit(-1);
109 }
110
111
112 static struct
113 {
114 unsigned int tb;
115 int cloned;
116 int flushed;
117 char *flushb;
118 int flushp;
119 int flushe;
120 int protocol, protocolmask;
121 int scope, scopemask;
122 __u64 typemask;
123 int tos, tosmask;
124 int iif, iifmask;
125 int oif, oifmask;
126 int mark, markmask;
127 int realm, realmmask;
128 __u32 metric, metricmask;
129 inet_prefix rprefsrc;
130 inet_prefix rvia;
131 inet_prefix rdst;
132 inet_prefix mdst;
133 inet_prefix rsrc;
134 inet_prefix msrc;
135 } filter;
136
137 static int flush_update(void)
138 {
139 if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
140 perror("Failed to send flush request");
141 return -2;
142 }
143 filter.flushp = 0;
144 return 0;
145 }
146
147 static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
148 {
149 struct rtmsg *r = NLMSG_DATA(n);
150 inet_prefix dst = { .family = r->rtm_family };
151 inet_prefix src = { .family = r->rtm_family };
152 inet_prefix via = { .family = r->rtm_family };
153 inet_prefix prefsrc = { .family = r->rtm_family };
154 __u32 table;
155 static int ip6_multiple_tables;
156
157 table = rtm_get_table(r, tb);
158
159 if (preferred_family != AF_UNSPEC && r->rtm_family != preferred_family)
160 return 0;
161
162 if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN)
163 ip6_multiple_tables = 1;
164
165 if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED))
166 return 0;
167
168 if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) {
169 if (filter.tb) {
170 if (filter.tb == RT_TABLE_LOCAL) {
171 if (r->rtm_type != RTN_LOCAL)
172 return 0;
173 } else if (filter.tb == RT_TABLE_MAIN) {
174 if (r->rtm_type == RTN_LOCAL)
175 return 0;
176 } else {
177 return 0;
178 }
179 }
180 } else {
181 if (filter.tb > 0 && filter.tb != table)
182 return 0;
183 }
184 if ((filter.protocol^r->rtm_protocol)&filter.protocolmask)
185 return 0;
186 if ((filter.scope^r->rtm_scope)&filter.scopemask)
187 return 0;
188
189 if (filter.typemask && !(filter.typemask & (1 << r->rtm_type)))
190 return 0;
191 if ((filter.tos^r->rtm_tos)&filter.tosmask)
192 return 0;
193 if (filter.rdst.family) {
194 if (r->rtm_family != filter.rdst.family ||
195 filter.rdst.bitlen > r->rtm_dst_len)
196 return 0;
197 } else if (filter.rdst.flags & PREFIXLEN_SPECIFIED) {
198 if (filter.rdst.bitlen > r->rtm_dst_len)
199 return 0;
200 }
201 if (filter.mdst.family) {
202 if (r->rtm_family != filter.mdst.family ||
203 (filter.mdst.bitlen >= 0 &&
204 filter.mdst.bitlen < r->rtm_dst_len))
205 return 0;
206 } else if (filter.mdst.flags & PREFIXLEN_SPECIFIED) {
207 if (filter.mdst.bitlen >= 0 &&
208 filter.mdst.bitlen < r->rtm_dst_len)
209 return 0;
210 }
211 if (filter.rsrc.family) {
212 if (r->rtm_family != filter.rsrc.family ||
213 filter.rsrc.bitlen > r->rtm_src_len)
214 return 0;
215 } else if (filter.rsrc.flags & PREFIXLEN_SPECIFIED) {
216 if (filter.rsrc.bitlen > r->rtm_src_len)
217 return 0;
218 }
219 if (filter.msrc.family) {
220 if (r->rtm_family != filter.msrc.family ||
221 (filter.msrc.bitlen >= 0 &&
222 filter.msrc.bitlen < r->rtm_src_len))
223 return 0;
224 } else if (filter.msrc.flags & PREFIXLEN_SPECIFIED) {
225 if (filter.msrc.bitlen >= 0 &&
226 filter.msrc.bitlen < r->rtm_src_len)
227 return 0;
228 }
229 if (filter.rvia.family) {
230 int family = r->rtm_family;
231
232 if (tb[RTA_VIA]) {
233 struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
234
235 family = via->rtvia_family;
236 }
237 if (family != filter.rvia.family)
238 return 0;
239 }
240 if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family)
241 return 0;
242
243 if (tb[RTA_DST])
244 memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), (r->rtm_dst_len+7)/8);
245 if (filter.rsrc.family || filter.msrc.family ||
246 filter.rsrc.flags & PREFIXLEN_SPECIFIED ||
247 filter.msrc.flags & PREFIXLEN_SPECIFIED) {
248 if (tb[RTA_SRC])
249 memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), (r->rtm_src_len+7)/8);
250 }
251 if (filter.rvia.bitlen > 0) {
252 if (tb[RTA_GATEWAY])
253 memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8);
254 if (tb[RTA_VIA]) {
255 size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
256 struct rtvia *rtvia = RTA_DATA(tb[RTA_VIA]);
257
258 via.family = rtvia->rtvia_family;
259 memcpy(&via.data, rtvia->rtvia_addr, len);
260 }
261 }
262 if (filter.rprefsrc.bitlen > 0) {
263 if (tb[RTA_PREFSRC])
264 memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len/8);
265 }
266
267 if ((filter.rdst.family || filter.rdst.flags & PREFIXLEN_SPECIFIED) &&
268 inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
269 return 0;
270 if ((filter.mdst.family || filter.mdst.flags & PREFIXLEN_SPECIFIED) &&
271 inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
272 return 0;
273
274 if ((filter.rsrc.family || filter.rsrc.flags & PREFIXLEN_SPECIFIED) &&
275 inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen))
276 return 0;
277 if ((filter.msrc.family || filter.msrc.flags & PREFIXLEN_SPECIFIED) &&
278 filter.msrc.bitlen >= 0 &&
279 inet_addr_match(&src, &filter.msrc, r->rtm_src_len))
280 return 0;
281
282 if (filter.rvia.family && inet_addr_match(&via, &filter.rvia, filter.rvia.bitlen))
283 return 0;
284 if (filter.rprefsrc.family && inet_addr_match(&prefsrc, &filter.rprefsrc, filter.rprefsrc.bitlen))
285 return 0;
286 if (filter.realmmask) {
287 __u32 realms = 0;
288
289 if (tb[RTA_FLOW])
290 realms = rta_getattr_u32(tb[RTA_FLOW]);
291 if ((realms^filter.realm)&filter.realmmask)
292 return 0;
293 }
294 if (filter.iifmask) {
295 int iif = 0;
296
297 if (tb[RTA_IIF])
298 iif = rta_getattr_u32(tb[RTA_IIF]);
299 if ((iif^filter.iif)&filter.iifmask)
300 return 0;
301 }
302 if (filter.oifmask) {
303 int oif = 0;
304
305 if (tb[RTA_OIF])
306 oif = rta_getattr_u32(tb[RTA_OIF]);
307 if ((oif^filter.oif)&filter.oifmask)
308 return 0;
309 }
310 if (filter.markmask) {
311 int mark = 0;
312
313 if (tb[RTA_MARK])
314 mark = rta_getattr_u32(tb[RTA_MARK]);
315 if ((mark ^ filter.mark) & filter.markmask)
316 return 0;
317 }
318 if (filter.metricmask) {
319 __u32 metric = 0;
320
321 if (tb[RTA_PRIORITY])
322 metric = rta_getattr_u32(tb[RTA_PRIORITY]);
323 if ((metric ^ filter.metric) & filter.metricmask)
324 return 0;
325 }
326 if (filter.flushb &&
327 r->rtm_family == AF_INET6 &&
328 r->rtm_dst_len == 0 &&
329 r->rtm_type == RTN_UNREACHABLE &&
330 tb[RTA_PRIORITY] &&
331 rta_getattr_u32(tb[RTA_PRIORITY]) == -1)
332 return 0;
333
334 return 1;
335 }
336
337 static void print_rtax_features(FILE *fp, unsigned int features)
338 {
339 unsigned int of = features;
340
341 if (features & RTAX_FEATURE_ECN) {
342 fprintf(fp, "ecn ");
343 features &= ~RTAX_FEATURE_ECN;
344 }
345
346 if (features)
347 fprintf(fp, "0x%x ", of);
348 }
349
350 static void print_rt_flags(FILE *fp, unsigned int flags)
351 {
352 if (flags & RTNH_F_DEAD)
353 fprintf(fp, "dead ");
354 if (flags & RTNH_F_ONLINK)
355 fprintf(fp, "onlink ");
356 if (flags & RTNH_F_PERVASIVE)
357 fprintf(fp, "pervasive ");
358 if (flags & RTNH_F_OFFLOAD)
359 fprintf(fp, "offload ");
360 if (flags & RTNH_F_LINKDOWN)
361 fprintf(fp, "linkdown ");
362 if (flags & RTNH_F_UNRESOLVED)
363 fprintf(fp, "unresolved ");
364 }
365
366 static void print_rt_pref(FILE *fp, unsigned int pref)
367 {
368 fprintf(fp, "pref ");
369
370 switch (pref) {
371 case ICMPV6_ROUTER_PREF_LOW:
372 fprintf(fp, "low");
373 break;
374 case ICMPV6_ROUTER_PREF_MEDIUM:
375 fprintf(fp, "medium");
376 break;
377 case ICMPV6_ROUTER_PREF_HIGH:
378 fprintf(fp, "high");
379 break;
380 default:
381 fprintf(fp, "%u", pref);
382 }
383 }
384
385 static void print_cache_flags(FILE *fp, __u32 flags)
386 {
387 flags &= ~0xFFFF;
388
389 fprintf(fp, "%s cache ", _SL_);
390
391 if (flags == 0)
392 return;
393
394 putc('<', fp);
395
396 #define PRTFL(fl, flname) \
397 if (flags & RTCF_##fl) { \
398 flags &= ~RTCF_##fl; \
399 fprintf(fp, "%s%s", flname, flags ? "," : "> "); \
400 }
401
402 PRTFL(LOCAL, "local");
403 PRTFL(REJECT, "reject");
404 PRTFL(MULTICAST, "mc");
405 PRTFL(BROADCAST, "brd");
406 PRTFL(DNAT, "dst-nat");
407 PRTFL(SNAT, "src-nat");
408 PRTFL(MASQ, "masq");
409 PRTFL(DIRECTDST, "dst-direct");
410 PRTFL(DIRECTSRC, "src-direct");
411 PRTFL(REDIRECTED, "redirected");
412 PRTFL(DOREDIRECT, "redirect");
413 PRTFL(FAST, "fastroute");
414 PRTFL(NOTIFY, "notify");
415 PRTFL(TPROXY, "proxy");
416 #undef PRTFL
417
418 if (flags)
419 fprintf(fp, "%#x> ", flags);
420 }
421
422 static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
423 {
424 static int hz;
425
426 if (!hz)
427 hz = get_user_hz();
428 if (ci->rta_expires != 0)
429 fprintf(fp, "expires %dsec ", ci->rta_expires/hz);
430 if (ci->rta_error != 0)
431 fprintf(fp, "error %d ", ci->rta_error);
432 if (show_stats) {
433 if (ci->rta_clntref)
434 fprintf(fp, "users %d ", ci->rta_clntref);
435 if (ci->rta_used != 0)
436 fprintf(fp, "used %d ", ci->rta_used);
437 if (ci->rta_lastuse != 0)
438 fprintf(fp, "age %dsec ", ci->rta_lastuse/hz);
439 }
440 if (ci->rta_id)
441 fprintf(fp, "ipid 0x%04x ", ci->rta_id);
442 if (ci->rta_ts || ci->rta_tsage)
443 fprintf(fp, "ts 0x%x tsage %dsec ",
444 ci->rta_ts, ci->rta_tsage);
445 }
446
447 static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
448 {
449 struct rtattr *mxrta[RTAX_MAX+1];
450 unsigned int mxlock = 0;
451 int i;
452
453 parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta));
454
455 if (mxrta[RTAX_LOCK])
456 mxlock = rta_getattr_u32(mxrta[RTAX_LOCK]);
457
458 for (i = 2; i <= RTAX_MAX; i++) {
459 __u32 val = 0U;
460
461 if (mxrta[i] == NULL && !(mxlock & (1 << i)))
462 continue;
463
464 if (mxrta[i] != NULL && i != RTAX_CC_ALGO)
465 val = rta_getattr_u32(mxrta[i]);
466
467 if (i == RTAX_HOPLIMIT && (int)val == -1)
468 continue;
469
470 if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
471 fprintf(fp, "%s ", mx_names[i]);
472 else
473 fprintf(fp, "metric %d ", i);
474
475 if (mxlock & (1<<i))
476 fprintf(fp, "lock ");
477
478 switch (i) {
479 case RTAX_FEATURES:
480 print_rtax_features(fp, val);
481 break;
482 default:
483 fprintf(fp, "%u ", val);
484 break;
485
486 case RTAX_RTT:
487 case RTAX_RTTVAR:
488 case RTAX_RTO_MIN:
489 if (i == RTAX_RTT)
490 val /= 8;
491 else if (i == RTAX_RTTVAR)
492 val /= 4;
493
494 if (val >= 1000)
495 fprintf(fp, "%gs ", val/1e3);
496 else
497 fprintf(fp, "%ums ", val);
498 break;
499 case RTAX_CC_ALGO:
500 fprintf(fp, "%s ", rta_getattr_str(mxrta[i]));
501 break;
502 }
503 }
504 }
505
506 int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
507 {
508 FILE *fp = (FILE *)arg;
509 struct rtmsg *r = NLMSG_DATA(n);
510 int len = n->nlmsg_len;
511 struct rtattr *tb[RTA_MAX+1];
512 int host_len, family;
513 __u32 table;
514 int ret;
515
516 SPRINT_BUF(b1);
517
518 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
519 fprintf(stderr, "Not a route: %08x %08x %08x\n",
520 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
521 return -1;
522 }
523 if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
524 return 0;
525 len -= NLMSG_LENGTH(sizeof(*r));
526 if (len < 0) {
527 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
528 return -1;
529 }
530
531 host_len = af_bit_len(r->rtm_family);
532
533 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
534 table = rtm_get_table(r, tb);
535
536 if (!filter_nlmsg(n, tb, host_len))
537 return 0;
538
539 if (filter.flushb) {
540 struct nlmsghdr *fn;
541
542 if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
543 if ((ret = flush_update()) < 0)
544 return ret;
545 }
546 fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp));
547 memcpy(fn, n, n->nlmsg_len);
548 fn->nlmsg_type = RTM_DELROUTE;
549 fn->nlmsg_flags = NLM_F_REQUEST;
550 fn->nlmsg_seq = ++rth.seq;
551 filter.flushp = (((char *)fn) + n->nlmsg_len) - filter.flushb;
552 filter.flushed++;
553 if (show_stats < 2)
554 return 0;
555 }
556
557 if (n->nlmsg_type == RTM_DELROUTE)
558 fprintf(fp, "Deleted ");
559 if ((r->rtm_type != RTN_UNICAST || show_details > 0) &&
560 (!filter.typemask || (filter.typemask & (1 << r->rtm_type))))
561 fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
562
563 if (tb[RTA_DST]) {
564 family = get_real_family(r->rtm_type, r->rtm_family);
565 if (r->rtm_dst_len != host_len) {
566 fprintf(fp, "%s/%u ",
567 rt_addr_n2a_rta(family, tb[RTA_DST]),
568 r->rtm_dst_len);
569 } else {
570 fprintf(fp, "%s ",
571 format_host_rta(family, tb[RTA_DST]));
572 }
573 } else if (r->rtm_dst_len) {
574 fprintf(fp, "0/%d ", r->rtm_dst_len);
575 } else {
576 fprintf(fp, "default ");
577 }
578 if (tb[RTA_SRC]) {
579 family = get_real_family(r->rtm_type, r->rtm_family);
580 if (r->rtm_src_len != host_len) {
581 fprintf(fp, "from %s/%u ",
582 rt_addr_n2a_rta(family, tb[RTA_SRC]),
583 r->rtm_src_len);
584 } else {
585 fprintf(fp, "from %s ",
586 format_host_rta(family, tb[RTA_SRC]));
587 }
588 } else if (r->rtm_src_len) {
589 fprintf(fp, "from 0/%u ", r->rtm_src_len);
590 }
591 if (tb[RTA_NEWDST]) {
592 fprintf(fp, "as to %s ",
593 format_host_rta(r->rtm_family, tb[RTA_NEWDST]));
594 }
595
596 if (tb[RTA_ENCAP])
597 lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]);
598
599 if (r->rtm_tos && filter.tosmask != -1) {
600 SPRINT_BUF(b1);
601 fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
602 }
603
604 if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
605 fprintf(fp, "via %s ",
606 format_host_rta(r->rtm_family, tb[RTA_GATEWAY]));
607 }
608 if (tb[RTA_VIA]) {
609 size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
610 struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
611
612 fprintf(fp, "via %s %s ",
613 family_name(via->rtvia_family),
614 format_host(via->rtvia_family, len, via->rtvia_addr));
615 }
616 if (tb[RTA_OIF] && filter.oifmask != -1)
617 fprintf(fp, "dev %s ", ll_index_to_name(rta_getattr_u32(tb[RTA_OIF])));
618
619 if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
620 fprintf(fp, "table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
621 if (!(r->rtm_flags&RTM_F_CLONED)) {
622 if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1)
623 fprintf(fp, "proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
624 if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1)
625 fprintf(fp, "scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
626 }
627 if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
628 /* Do not use format_host(). It is our local addr
629 and symbolic name will not be useful.
630 */
631 fprintf(fp, "src %s ",
632 rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC]));
633 }
634 if (tb[RTA_PRIORITY] && filter.metricmask != -1)
635 fprintf(fp, "metric %u ", rta_getattr_u32(tb[RTA_PRIORITY]));
636
637 print_rt_flags(fp, r->rtm_flags);
638
639 if (tb[RTA_MARK]) {
640 unsigned int mark = rta_getattr_u32(tb[RTA_MARK]);
641
642 if (mark) {
643 if (mark >= 16)
644 fprintf(fp, "mark 0x%x ", mark);
645 else
646 fprintf(fp, "mark %u ", mark);
647 }
648 }
649
650 if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
651 __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
652 __u32 from = to>>16;
653
654 to &= 0xFFFF;
655 fprintf(fp, "realm%s ", from ? "s" : "");
656 if (from) {
657 fprintf(fp, "%s/",
658 rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
659 }
660 fprintf(fp, "%s ",
661 rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
662 }
663
664 if (tb[RTA_UID])
665 fprintf(fp, "uid %u ", rta_getattr_u32(tb[RTA_UID]));
666
667 if ((r->rtm_flags & RTM_F_CLONED) && r->rtm_family == AF_INET) {
668 print_cache_flags(fp, r->rtm_flags);
669
670 if (tb[RTA_CACHEINFO])
671 print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
672
673 } else if (r->rtm_family == AF_INET6) {
674
675 if (r->rtm_flags & RTM_F_CLONED)
676 fprintf(fp, "%s cache ", _SL_);
677
678 if (tb[RTA_CACHEINFO])
679 print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
680 }
681
682 if (tb[RTA_METRICS])
683 print_rta_metrics(fp, tb[RTA_METRICS]);
684
685 if (tb[RTA_IIF] && filter.iifmask != -1) {
686 fprintf(fp, "iif %s ",
687 ll_index_to_name(rta_getattr_u32(tb[RTA_IIF])));
688 }
689 if (tb[RTA_MULTIPATH]) {
690 struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]);
691 int first = 1;
692
693 len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
694
695 for (;;) {
696 if (len < sizeof(*nh))
697 break;
698 if (nh->rtnh_len > len)
699 break;
700 if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
701 if (first) {
702 fprintf(fp, "Oifs: ");
703 first = 0;
704 } else {
705 fprintf(fp, " ");
706 }
707 } else
708 fprintf(fp, "%s\tnexthop ", _SL_);
709 if (nh->rtnh_len > sizeof(*nh)) {
710 parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh));
711
712 if (tb[RTA_ENCAP])
713 lwt_print_encap(fp,
714 tb[RTA_ENCAP_TYPE],
715 tb[RTA_ENCAP]);
716 if (tb[RTA_NEWDST]) {
717 fprintf(fp, "as to %s ",
718 format_host_rta(r->rtm_family,
719 tb[RTA_NEWDST]));
720 }
721 if (tb[RTA_GATEWAY]) {
722 fprintf(fp, "via %s ",
723 format_host_rta(r->rtm_family,
724 tb[RTA_GATEWAY]));
725 }
726 if (tb[RTA_VIA]) {
727 size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
728 struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
729
730 fprintf(fp, "via %s %s ",
731 family_name(via->rtvia_family),
732 format_host(via->rtvia_family, len, via->rtvia_addr));
733 }
734 if (tb[RTA_FLOW]) {
735 __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
736 __u32 from = to>>16;
737
738 to &= 0xFFFF;
739 fprintf(fp, "realm%s ", from ? "s" : "");
740 if (from) {
741 fprintf(fp, "%s/",
742 rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
743 }
744 fprintf(fp, "%s ",
745 rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
746 }
747 }
748 if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
749 fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
750 if (nh->rtnh_hops != 1)
751 fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
752 fprintf(fp, " ");
753 } else {
754 fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
755 if (r->rtm_family != AF_MPLS)
756 fprintf(fp, "weight %d ",
757 nh->rtnh_hops+1);
758 }
759
760 print_rt_flags(fp, nh->rtnh_flags);
761
762 len -= NLMSG_ALIGN(nh->rtnh_len);
763 nh = RTNH_NEXT(nh);
764 }
765 }
766
767 if (tb[RTA_PREF])
768 print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF]));
769
770 if (tb[RTA_TTL_PROPAGATE]) {
771 fprintf(fp, "ttl-propagate ");
772 if (rta_getattr_u8(tb[RTA_TTL_PROPAGATE]))
773 fprintf(fp, "enabled");
774 else
775 fprintf(fp, "disabled");
776 }
777 fprintf(fp, "\n");
778 fflush(fp);
779 return 0;
780 }
781
782 static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
783 struct rtattr *rta, struct rtnexthop *rtnh,
784 int *argcp, char ***argvp)
785 {
786 int argc = *argcp;
787 char **argv = *argvp;
788
789 while (++argv, --argc > 0) {
790 if (strcmp(*argv, "via") == 0) {
791 inet_prefix addr;
792 int family;
793
794 NEXT_ARG();
795 family = read_family(*argv);
796 if (family == AF_UNSPEC)
797 family = r->rtm_family;
798 else
799 NEXT_ARG();
800 get_addr(&addr, *argv, family);
801 if (r->rtm_family == AF_UNSPEC)
802 r->rtm_family = addr.family;
803 if (addr.family == r->rtm_family) {
804 rta_addattr_l(rta, 4096, RTA_GATEWAY, &addr.data, addr.bytelen);
805 rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
806 } else {
807 rta_addattr_l(rta, 4096, RTA_VIA, &addr.family, addr.bytelen+2);
808 rtnh->rtnh_len += RTA_SPACE(addr.bytelen+2);
809 }
810 } else if (strcmp(*argv, "dev") == 0) {
811 NEXT_ARG();
812 if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) {
813 fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
814 return -1;
815 }
816 } else if (strcmp(*argv, "weight") == 0) {
817 unsigned int w;
818
819 NEXT_ARG();
820 if (get_unsigned(&w, *argv, 0) || w == 0 || w > 256)
821 invarg("\"weight\" is invalid\n", *argv);
822 rtnh->rtnh_hops = w - 1;
823 } else if (strcmp(*argv, "onlink") == 0) {
824 rtnh->rtnh_flags |= RTNH_F_ONLINK;
825 } else if (matches(*argv, "realms") == 0) {
826 __u32 realm;
827
828 NEXT_ARG();
829 if (get_rt_realms_or_raw(&realm, *argv))
830 invarg("\"realm\" value is invalid\n", *argv);
831 rta_addattr32(rta, 4096, RTA_FLOW, realm);
832 rtnh->rtnh_len += sizeof(struct rtattr) + 4;
833 } else if (strcmp(*argv, "encap") == 0) {
834 int len = rta->rta_len;
835
836 lwt_parse_encap(rta, 4096, &argc, &argv);
837 rtnh->rtnh_len += rta->rta_len - len;
838 } else if (strcmp(*argv, "as") == 0) {
839 inet_prefix addr;
840
841 NEXT_ARG();
842 if (strcmp(*argv, "to") == 0)
843 NEXT_ARG();
844 get_addr(&addr, *argv, r->rtm_family);
845 rta_addattr_l(rta, 4096, RTA_NEWDST, &addr.data,
846 addr.bytelen);
847 rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
848 } else
849 break;
850 }
851 *argcp = argc;
852 *argvp = argv;
853 return 0;
854 }
855
856 static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r,
857 int argc, char **argv)
858 {
859 char buf[1024];
860 struct rtattr *rta = (void *)buf;
861 struct rtnexthop *rtnh;
862
863 rta->rta_type = RTA_MULTIPATH;
864 rta->rta_len = RTA_LENGTH(0);
865 rtnh = RTA_DATA(rta);
866
867 while (argc > 0) {
868 if (strcmp(*argv, "nexthop") != 0) {
869 fprintf(stderr, "Error: \"nexthop\" or end of line is expected instead of \"%s\"\n", *argv);
870 exit(-1);
871 }
872 if (argc <= 1) {
873 fprintf(stderr, "Error: unexpected end of line after \"nexthop\"\n");
874 exit(-1);
875 }
876 memset(rtnh, 0, sizeof(*rtnh));
877 rtnh->rtnh_len = sizeof(*rtnh);
878 rta->rta_len += rtnh->rtnh_len;
879 parse_one_nh(n, r, rta, rtnh, &argc, &argv);
880 rtnh = RTNH_NEXT(rtnh);
881 }
882
883 if (rta->rta_len > RTA_LENGTH(0))
884 addattr_l(n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
885 return 0;
886 }
887
888 static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
889 {
890 struct {
891 struct nlmsghdr n;
892 struct rtmsg r;
893 char buf[1024];
894 } req = {
895 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
896 .n.nlmsg_flags = NLM_F_REQUEST | flags,
897 .n.nlmsg_type = cmd,
898 .r.rtm_family = preferred_family,
899 .r.rtm_table = RT_TABLE_MAIN,
900 .r.rtm_scope = RT_SCOPE_NOWHERE,
901 };
902 char mxbuf[256];
903 struct rtattr *mxrta = (void *)mxbuf;
904 unsigned int mxlock = 0;
905 char *d = NULL;
906 int gw_ok = 0;
907 int dst_ok = 0;
908 int nhs_ok = 0;
909 int scope_ok = 0;
910 int table_ok = 0;
911 int raw = 0;
912 int type_ok = 0;
913
914 if (cmd != RTM_DELROUTE) {
915 req.r.rtm_protocol = RTPROT_BOOT;
916 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
917 req.r.rtm_type = RTN_UNICAST;
918 }
919
920 mxrta->rta_type = RTA_METRICS;
921 mxrta->rta_len = RTA_LENGTH(0);
922
923 while (argc > 0) {
924 if (strcmp(*argv, "src") == 0) {
925 inet_prefix addr;
926
927 NEXT_ARG();
928 get_addr(&addr, *argv, req.r.rtm_family);
929 if (req.r.rtm_family == AF_UNSPEC)
930 req.r.rtm_family = addr.family;
931 addattr_l(&req.n, sizeof(req),
932 RTA_PREFSRC, &addr.data, addr.bytelen);
933 } else if (strcmp(*argv, "as") == 0) {
934 inet_prefix addr;
935
936 NEXT_ARG();
937 if (strcmp(*argv, "to") == 0) {
938 NEXT_ARG();
939 }
940 get_addr(&addr, *argv, req.r.rtm_family);
941 if (req.r.rtm_family == AF_UNSPEC)
942 req.r.rtm_family = addr.family;
943 addattr_l(&req.n, sizeof(req),
944 RTA_NEWDST, &addr.data, addr.bytelen);
945 } else if (strcmp(*argv, "via") == 0) {
946 inet_prefix addr;
947 int family;
948
949 if (gw_ok) {
950 invarg("use nexthop syntax to specify multiple via\n",
951 *argv);
952 }
953 gw_ok = 1;
954 NEXT_ARG();
955 family = read_family(*argv);
956 if (family == AF_UNSPEC)
957 family = req.r.rtm_family;
958 else
959 NEXT_ARG();
960 get_addr(&addr, *argv, family);
961 if (req.r.rtm_family == AF_UNSPEC)
962 req.r.rtm_family = addr.family;
963 if (addr.family == req.r.rtm_family)
964 addattr_l(&req.n, sizeof(req), RTA_GATEWAY,
965 &addr.data, addr.bytelen);
966 else
967 addattr_l(&req.n, sizeof(req), RTA_VIA,
968 &addr.family, addr.bytelen+2);
969 } else if (strcmp(*argv, "from") == 0) {
970 inet_prefix addr;
971
972 NEXT_ARG();
973 get_prefix(&addr, *argv, req.r.rtm_family);
974 if (req.r.rtm_family == AF_UNSPEC)
975 req.r.rtm_family = addr.family;
976 if (addr.bytelen)
977 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
978 req.r.rtm_src_len = addr.bitlen;
979 } else if (strcmp(*argv, "tos") == 0 ||
980 matches(*argv, "dsfield") == 0) {
981 __u32 tos;
982
983 NEXT_ARG();
984 if (rtnl_dsfield_a2n(&tos, *argv))
985 invarg("\"tos\" value is invalid\n", *argv);
986 req.r.rtm_tos = tos;
987 } else if (strcmp(*argv, "expires") == 0) {
988 __u32 expires;
989
990 NEXT_ARG();
991 if (get_u32(&expires, *argv, 0))
992 invarg("\"expires\" value is invalid\n", *argv);
993 addattr32(&req.n, sizeof(req), RTA_EXPIRES, expires);
994 } else if (matches(*argv, "metric") == 0 ||
995 matches(*argv, "priority") == 0 ||
996 strcmp(*argv, "preference") == 0) {
997 __u32 metric;
998
999 NEXT_ARG();
1000 if (get_u32(&metric, *argv, 0))
1001 invarg("\"metric\" value is invalid\n", *argv);
1002 addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
1003 } else if (strcmp(*argv, "scope") == 0) {
1004 __u32 scope = 0;
1005
1006 NEXT_ARG();
1007 if (rtnl_rtscope_a2n(&scope, *argv))
1008 invarg("invalid \"scope\" value\n", *argv);
1009 req.r.rtm_scope = scope;
1010 scope_ok = 1;
1011 } else if (strcmp(*argv, "mtu") == 0) {
1012 unsigned int mtu;
1013
1014 NEXT_ARG();
1015 if (strcmp(*argv, "lock") == 0) {
1016 mxlock |= (1<<RTAX_MTU);
1017 NEXT_ARG();
1018 }
1019 if (get_unsigned(&mtu, *argv, 0))
1020 invarg("\"mtu\" value is invalid\n", *argv);
1021 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
1022 } else if (strcmp(*argv, "hoplimit") == 0) {
1023 unsigned int hoplimit;
1024
1025 NEXT_ARG();
1026 if (strcmp(*argv, "lock") == 0) {
1027 mxlock |= (1<<RTAX_HOPLIMIT);
1028 NEXT_ARG();
1029 }
1030 if (get_unsigned(&hoplimit, *argv, 0) || hoplimit > 255)
1031 invarg("\"hoplimit\" value is invalid\n", *argv);
1032 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_HOPLIMIT, hoplimit);
1033 } else if (strcmp(*argv, "advmss") == 0) {
1034 unsigned int mss;
1035
1036 NEXT_ARG();
1037 if (strcmp(*argv, "lock") == 0) {
1038 mxlock |= (1<<RTAX_ADVMSS);
1039 NEXT_ARG();
1040 }
1041 if (get_unsigned(&mss, *argv, 0))
1042 invarg("\"mss\" value is invalid\n", *argv);
1043 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss);
1044 } else if (matches(*argv, "reordering") == 0) {
1045 unsigned int reord;
1046
1047 NEXT_ARG();
1048 if (strcmp(*argv, "lock") == 0) {
1049 mxlock |= (1<<RTAX_REORDERING);
1050 NEXT_ARG();
1051 }
1052 if (get_unsigned(&reord, *argv, 0))
1053 invarg("\"reordering\" value is invalid\n", *argv);
1054 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord);
1055 } else if (strcmp(*argv, "rtt") == 0) {
1056 unsigned int rtt;
1057
1058 NEXT_ARG();
1059 if (strcmp(*argv, "lock") == 0) {
1060 mxlock |= (1<<RTAX_RTT);
1061 NEXT_ARG();
1062 }
1063 if (get_time_rtt(&rtt, *argv, &raw))
1064 invarg("\"rtt\" value is invalid\n", *argv);
1065 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT,
1066 (raw) ? rtt : rtt * 8);
1067 } else if (strcmp(*argv, "rto_min") == 0) {
1068 unsigned int rto_min;
1069
1070 NEXT_ARG();
1071 mxlock |= (1<<RTAX_RTO_MIN);
1072 if (get_time_rtt(&rto_min, *argv, &raw))
1073 invarg("\"rto_min\" value is invalid\n",
1074 *argv);
1075 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
1076 rto_min);
1077 } else if (matches(*argv, "window") == 0) {
1078 unsigned int win;
1079
1080 NEXT_ARG();
1081 if (strcmp(*argv, "lock") == 0) {
1082 mxlock |= (1<<RTAX_WINDOW);
1083 NEXT_ARG();
1084 }
1085 if (get_unsigned(&win, *argv, 0))
1086 invarg("\"window\" value is invalid\n", *argv);
1087 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_WINDOW, win);
1088 } else if (matches(*argv, "cwnd") == 0) {
1089 unsigned int win;
1090
1091 NEXT_ARG();
1092 if (strcmp(*argv, "lock") == 0) {
1093 mxlock |= (1<<RTAX_CWND);
1094 NEXT_ARG();
1095 }
1096 if (get_unsigned(&win, *argv, 0))
1097 invarg("\"cwnd\" value is invalid\n", *argv);
1098 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win);
1099 } else if (matches(*argv, "initcwnd") == 0) {
1100 unsigned int win;
1101
1102 NEXT_ARG();
1103 if (strcmp(*argv, "lock") == 0) {
1104 mxlock |= (1<<RTAX_INITCWND);
1105 NEXT_ARG();
1106 }
1107 if (get_unsigned(&win, *argv, 0))
1108 invarg("\"initcwnd\" value is invalid\n", *argv);
1109 rta_addattr32(mxrta, sizeof(mxbuf),
1110 RTAX_INITCWND, win);
1111 } else if (matches(*argv, "initrwnd") == 0) {
1112 unsigned int win;
1113
1114 NEXT_ARG();
1115 if (strcmp(*argv, "lock") == 0) {
1116 mxlock |= (1<<RTAX_INITRWND);
1117 NEXT_ARG();
1118 }
1119 if (get_unsigned(&win, *argv, 0))
1120 invarg("\"initrwnd\" value is invalid\n", *argv);
1121 rta_addattr32(mxrta, sizeof(mxbuf),
1122 RTAX_INITRWND, win);
1123 } else if (matches(*argv, "features") == 0) {
1124 unsigned int features = 0;
1125
1126 while (argc > 0) {
1127 NEXT_ARG();
1128
1129 if (strcmp(*argv, "ecn") == 0)
1130 features |= RTAX_FEATURE_ECN;
1131 else
1132 invarg("\"features\" value not valid\n", *argv);
1133 break;
1134 }
1135
1136 rta_addattr32(mxrta, sizeof(mxbuf),
1137 RTAX_FEATURES, features);
1138 } else if (matches(*argv, "quickack") == 0) {
1139 unsigned int quickack;
1140
1141 NEXT_ARG();
1142 if (get_unsigned(&quickack, *argv, 0))
1143 invarg("\"quickack\" value is invalid\n", *argv);
1144 if (quickack != 1 && quickack != 0)
1145 invarg("\"quickack\" value should be 0 or 1\n", *argv);
1146 rta_addattr32(mxrta, sizeof(mxbuf),
1147 RTAX_QUICKACK, quickack);
1148 } else if (matches(*argv, "congctl") == 0) {
1149 NEXT_ARG();
1150 if (strcmp(*argv, "lock") == 0) {
1151 mxlock |= 1 << RTAX_CC_ALGO;
1152 NEXT_ARG();
1153 }
1154 rta_addattr_l(mxrta, sizeof(mxbuf), RTAX_CC_ALGO, *argv,
1155 strlen(*argv));
1156 } else if (matches(*argv, "rttvar") == 0) {
1157 unsigned int win;
1158
1159 NEXT_ARG();
1160 if (strcmp(*argv, "lock") == 0) {
1161 mxlock |= (1<<RTAX_RTTVAR);
1162 NEXT_ARG();
1163 }
1164 if (get_time_rtt(&win, *argv, &raw))
1165 invarg("\"rttvar\" value is invalid\n", *argv);
1166 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
1167 (raw) ? win : win * 4);
1168 } else if (matches(*argv, "ssthresh") == 0) {
1169 unsigned int win;
1170
1171 NEXT_ARG();
1172 if (strcmp(*argv, "lock") == 0) {
1173 mxlock |= (1<<RTAX_SSTHRESH);
1174 NEXT_ARG();
1175 }
1176 if (get_unsigned(&win, *argv, 0))
1177 invarg("\"ssthresh\" value is invalid\n", *argv);
1178 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_SSTHRESH, win);
1179 } else if (matches(*argv, "realms") == 0) {
1180 __u32 realm;
1181
1182 NEXT_ARG();
1183 if (get_rt_realms_or_raw(&realm, *argv))
1184 invarg("\"realm\" value is invalid\n", *argv);
1185 addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
1186 } else if (strcmp(*argv, "onlink") == 0) {
1187 req.r.rtm_flags |= RTNH_F_ONLINK;
1188 } else if (strcmp(*argv, "nexthop") == 0) {
1189 nhs_ok = 1;
1190 break;
1191 } else if (matches(*argv, "protocol") == 0) {
1192 __u32 prot;
1193
1194 NEXT_ARG();
1195 if (rtnl_rtprot_a2n(&prot, *argv))
1196 invarg("\"protocol\" value is invalid\n", *argv);
1197 req.r.rtm_protocol = prot;
1198 } else if (matches(*argv, "table") == 0) {
1199 __u32 tid;
1200
1201 NEXT_ARG();
1202 if (rtnl_rttable_a2n(&tid, *argv))
1203 invarg("\"table\" value is invalid\n", *argv);
1204 if (tid < 256)
1205 req.r.rtm_table = tid;
1206 else {
1207 req.r.rtm_table = RT_TABLE_UNSPEC;
1208 addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
1209 }
1210 table_ok = 1;
1211 } else if (matches(*argv, "vrf") == 0) {
1212 __u32 tid;
1213
1214 NEXT_ARG();
1215 tid = ipvrf_get_table(*argv);
1216 if (tid == 0)
1217 invarg("Invalid VRF\n", *argv);
1218 if (tid < 256)
1219 req.r.rtm_table = tid;
1220 else {
1221 req.r.rtm_table = RT_TABLE_UNSPEC;
1222 addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
1223 }
1224 table_ok = 1;
1225 } else if (strcmp(*argv, "dev") == 0 ||
1226 strcmp(*argv, "oif") == 0) {
1227 NEXT_ARG();
1228 d = *argv;
1229 } else if (matches(*argv, "pref") == 0) {
1230 __u8 pref;
1231
1232 NEXT_ARG();
1233 if (strcmp(*argv, "low") == 0)
1234 pref = ICMPV6_ROUTER_PREF_LOW;
1235 else if (strcmp(*argv, "medium") == 0)
1236 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1237 else if (strcmp(*argv, "high") == 0)
1238 pref = ICMPV6_ROUTER_PREF_HIGH;
1239 else if (get_u8(&pref, *argv, 0))
1240 invarg("\"pref\" value is invalid\n", *argv);
1241 addattr8(&req.n, sizeof(req), RTA_PREF, pref);
1242 } else if (strcmp(*argv, "encap") == 0) {
1243 char buf[1024];
1244 struct rtattr *rta = (void *)buf;
1245
1246 rta->rta_type = RTA_ENCAP;
1247 rta->rta_len = RTA_LENGTH(0);
1248
1249 lwt_parse_encap(rta, sizeof(buf), &argc, &argv);
1250
1251 if (rta->rta_len > RTA_LENGTH(0))
1252 addraw_l(&req.n, 1024
1253 , RTA_DATA(rta), RTA_PAYLOAD(rta));
1254 } else if (strcmp(*argv, "ttl-propagate") == 0) {
1255 __u8 ttl_prop;
1256
1257 NEXT_ARG();
1258 if (matches(*argv, "enabled") == 0)
1259 ttl_prop = 1;
1260 else if (matches(*argv, "disabled") == 0)
1261 ttl_prop = 0;
1262 else
1263 invarg("\"ttl-propagate\" value is invalid\n",
1264 *argv);
1265
1266 addattr8(&req.n, sizeof(req), RTA_TTL_PROPAGATE,
1267 ttl_prop);
1268 } else if (matches(*argv, "fastopen_no_cookie") == 0) {
1269 unsigned int fastopen_no_cookie;
1270
1271 NEXT_ARG();
1272 if (get_unsigned(&fastopen_no_cookie, *argv, 0))
1273 invarg("\"fastopen_no_cookie\" value is invalid\n", *argv);
1274 if (fastopen_no_cookie != 1 && fastopen_no_cookie != 0)
1275 invarg("\"fastopen_no_cookie\" value should be 0 or 1\n", *argv);
1276 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_FASTOPEN_NO_COOKIE, fastopen_no_cookie);
1277 } else {
1278 int type;
1279 inet_prefix dst;
1280
1281 if (strcmp(*argv, "to") == 0) {
1282 NEXT_ARG();
1283 }
1284 if ((**argv < '0' || **argv > '9') &&
1285 rtnl_rtntype_a2n(&type, *argv) == 0) {
1286 NEXT_ARG();
1287 req.r.rtm_type = type;
1288 type_ok = 1;
1289 }
1290
1291 if (matches(*argv, "help") == 0)
1292 usage();
1293 if (dst_ok)
1294 duparg2("to", *argv);
1295 get_prefix(&dst, *argv, req.r.rtm_family);
1296 if (req.r.rtm_family == AF_UNSPEC)
1297 req.r.rtm_family = dst.family;
1298 req.r.rtm_dst_len = dst.bitlen;
1299 dst_ok = 1;
1300 if (dst.bytelen)
1301 addattr_l(&req.n, sizeof(req),
1302 RTA_DST, &dst.data, dst.bytelen);
1303 }
1304 argc--; argv++;
1305 }
1306
1307 if (!dst_ok)
1308 usage();
1309
1310 if (d) {
1311 int idx;
1312
1313 if ((idx = ll_name_to_index(d)) == 0) {
1314 fprintf(stderr, "Cannot find device \"%s\"\n", d);
1315 return -1;
1316 }
1317 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1318 }
1319
1320 if (mxrta->rta_len > RTA_LENGTH(0)) {
1321 if (mxlock)
1322 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
1323 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
1324 }
1325
1326 if (nhs_ok)
1327 parse_nexthops(&req.n, &req.r, argc, argv);
1328
1329 if (req.r.rtm_family == AF_UNSPEC)
1330 req.r.rtm_family = AF_INET;
1331
1332 if (!table_ok) {
1333 if (req.r.rtm_type == RTN_LOCAL ||
1334 req.r.rtm_type == RTN_BROADCAST ||
1335 req.r.rtm_type == RTN_NAT ||
1336 req.r.rtm_type == RTN_ANYCAST)
1337 req.r.rtm_table = RT_TABLE_LOCAL;
1338 }
1339 if (!scope_ok) {
1340 if (req.r.rtm_family == AF_INET6 ||
1341 req.r.rtm_family == AF_MPLS)
1342 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1343 else if (req.r.rtm_type == RTN_LOCAL ||
1344 req.r.rtm_type == RTN_NAT)
1345 req.r.rtm_scope = RT_SCOPE_HOST;
1346 else if (req.r.rtm_type == RTN_BROADCAST ||
1347 req.r.rtm_type == RTN_MULTICAST ||
1348 req.r.rtm_type == RTN_ANYCAST)
1349 req.r.rtm_scope = RT_SCOPE_LINK;
1350 else if (req.r.rtm_type == RTN_UNICAST ||
1351 req.r.rtm_type == RTN_UNSPEC) {
1352 if (cmd == RTM_DELROUTE)
1353 req.r.rtm_scope = RT_SCOPE_NOWHERE;
1354 else if (!gw_ok && !nhs_ok)
1355 req.r.rtm_scope = RT_SCOPE_LINK;
1356 }
1357 }
1358
1359 if (!type_ok && req.r.rtm_family == AF_MPLS)
1360 req.r.rtm_type = RTN_UNICAST;
1361
1362 if (rtnl_talk(&rth, &req.n, NULL) < 0)
1363 return -2;
1364
1365 return 0;
1366 }
1367
1368 static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
1369 {
1370 struct {
1371 struct nlmsghdr nlh;
1372 struct rtmsg rtm;
1373 } req = {
1374 .nlh.nlmsg_len = sizeof(req),
1375 .nlh.nlmsg_type = RTM_GETROUTE,
1376 .nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST,
1377 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
1378 .rtm.rtm_family = family,
1379 .rtm.rtm_flags = RTM_F_CLONED,
1380 };
1381 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
1382
1383 return sendto(rth->fd, (void *)&req, sizeof(req), 0, (struct sockaddr *)&nladdr, sizeof(nladdr));
1384 }
1385
1386 static int iproute_flush_cache(void)
1387 {
1388 #define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
1389
1390 int len;
1391 int flush_fd = open(ROUTE_FLUSH_PATH, O_WRONLY);
1392 char *buffer = "-1";
1393
1394 if (flush_fd < 0) {
1395 fprintf(stderr, "Cannot open \"%s\": %s\n",
1396 ROUTE_FLUSH_PATH, strerror(errno));
1397 return -1;
1398 }
1399
1400 len = strlen(buffer);
1401
1402 if ((write(flush_fd, (void *)buffer, len)) < len) {
1403 fprintf(stderr, "Cannot flush routing cache\n");
1404 close(flush_fd);
1405 return -1;
1406 }
1407 close(flush_fd);
1408 return 0;
1409 }
1410
1411 static __u32 route_dump_magic = 0x45311224;
1412
1413 static int save_route(const struct sockaddr_nl *who, struct nlmsghdr *n,
1414 void *arg)
1415 {
1416 int ret;
1417 int len = n->nlmsg_len;
1418 struct rtmsg *r = NLMSG_DATA(n);
1419 struct rtattr *tb[RTA_MAX+1];
1420 int host_len;
1421
1422 host_len = af_bit_len(r->rtm_family);
1423 len -= NLMSG_LENGTH(sizeof(*r));
1424 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1425
1426 if (!filter_nlmsg(n, tb, host_len))
1427 return 0;
1428
1429 ret = write(STDOUT_FILENO, n, n->nlmsg_len);
1430 if ((ret > 0) && (ret != n->nlmsg_len)) {
1431 fprintf(stderr, "Short write while saving nlmsg\n");
1432 ret = -EIO;
1433 }
1434
1435 return ret == n->nlmsg_len ? 0 : ret;
1436 }
1437
1438 static int save_route_prep(void)
1439 {
1440 int ret;
1441
1442 if (isatty(STDOUT_FILENO)) {
1443 fprintf(stderr, "Not sending a binary stream to stdout\n");
1444 return -1;
1445 }
1446
1447 ret = write(STDOUT_FILENO, &route_dump_magic, sizeof(route_dump_magic));
1448 if (ret != sizeof(route_dump_magic)) {
1449 fprintf(stderr, "Can't write magic to dump file\n");
1450 return -1;
1451 }
1452
1453 return 0;
1454 }
1455
1456 static int iproute_list_flush_or_save(int argc, char **argv, int action)
1457 {
1458 int do_ipv6 = preferred_family;
1459 char *id = NULL;
1460 char *od = NULL;
1461 unsigned int mark = 0;
1462 rtnl_filter_t filter_fn;
1463 int ret;
1464
1465 if (action == IPROUTE_SAVE) {
1466 if (save_route_prep())
1467 return -1;
1468
1469 filter_fn = save_route;
1470 } else
1471 filter_fn = print_route;
1472
1473 iproute_reset_filter(0);
1474 filter.tb = RT_TABLE_MAIN;
1475
1476 if ((action == IPROUTE_FLUSH) && argc <= 0) {
1477 fprintf(stderr, "\"ip route flush\" requires arguments.\n");
1478 return -1;
1479 }
1480
1481 while (argc > 0) {
1482 if (matches(*argv, "table") == 0) {
1483 __u32 tid;
1484
1485 NEXT_ARG();
1486 if (rtnl_rttable_a2n(&tid, *argv)) {
1487 if (strcmp(*argv, "all") == 0) {
1488 filter.tb = 0;
1489 } else if (strcmp(*argv, "cache") == 0) {
1490 filter.cloned = 1;
1491 } else if (strcmp(*argv, "help") == 0) {
1492 usage();
1493 } else {
1494 invarg("table id value is invalid\n", *argv);
1495 }
1496 } else
1497 filter.tb = tid;
1498 } else if (matches(*argv, "vrf") == 0) {
1499 __u32 tid;
1500
1501 NEXT_ARG();
1502 tid = ipvrf_get_table(*argv);
1503 if (tid == 0)
1504 invarg("Invalid VRF\n", *argv);
1505 filter.tb = tid;
1506 filter.typemask = ~(1 << RTN_LOCAL | 1<<RTN_BROADCAST);
1507 } else if (matches(*argv, "cached") == 0 ||
1508 matches(*argv, "cloned") == 0) {
1509 filter.cloned = 1;
1510 } else if (strcmp(*argv, "tos") == 0 ||
1511 matches(*argv, "dsfield") == 0) {
1512 __u32 tos;
1513
1514 NEXT_ARG();
1515 if (rtnl_dsfield_a2n(&tos, *argv))
1516 invarg("TOS value is invalid\n", *argv);
1517 filter.tos = tos;
1518 filter.tosmask = -1;
1519 } else if (matches(*argv, "protocol") == 0) {
1520 __u32 prot = 0;
1521
1522 NEXT_ARG();
1523 filter.protocolmask = -1;
1524 if (rtnl_rtprot_a2n(&prot, *argv)) {
1525 if (strcmp(*argv, "all") != 0)
1526 invarg("invalid \"protocol\"\n", *argv);
1527 prot = 0;
1528 filter.protocolmask = 0;
1529 }
1530 filter.protocol = prot;
1531 } else if (matches(*argv, "scope") == 0) {
1532 __u32 scope = 0;
1533
1534 NEXT_ARG();
1535 filter.scopemask = -1;
1536 if (rtnl_rtscope_a2n(&scope, *argv)) {
1537 if (strcmp(*argv, "all") != 0)
1538 invarg("invalid \"scope\"\n", *argv);
1539 scope = RT_SCOPE_NOWHERE;
1540 filter.scopemask = 0;
1541 }
1542 filter.scope = scope;
1543 } else if (matches(*argv, "type") == 0) {
1544 int type;
1545
1546 NEXT_ARG();
1547 if (rtnl_rtntype_a2n(&type, *argv))
1548 invarg("node type value is invalid\n", *argv);
1549 filter.typemask = (1<<type);
1550 } else if (strcmp(*argv, "dev") == 0 ||
1551 strcmp(*argv, "oif") == 0) {
1552 NEXT_ARG();
1553 od = *argv;
1554 } else if (strcmp(*argv, "iif") == 0) {
1555 NEXT_ARG();
1556 id = *argv;
1557 } else if (strcmp(*argv, "mark") == 0) {
1558 NEXT_ARG();
1559 if (get_unsigned(&mark, *argv, 0))
1560 invarg("invalid mark value", *argv);
1561 filter.markmask = -1;
1562 } else if (matches(*argv, "metric") == 0 ||
1563 matches(*argv, "priority") == 0 ||
1564 strcmp(*argv, "preference") == 0) {
1565 __u32 metric;
1566
1567 NEXT_ARG();
1568 if (get_u32(&metric, *argv, 0))
1569 invarg("\"metric\" value is invalid\n", *argv);
1570 filter.metric = metric;
1571 filter.metricmask = -1;
1572 } else if (strcmp(*argv, "via") == 0) {
1573 int family;
1574
1575 NEXT_ARG();
1576 family = read_family(*argv);
1577 if (family == AF_UNSPEC)
1578 family = do_ipv6;
1579 else
1580 NEXT_ARG();
1581 get_prefix(&filter.rvia, *argv, family);
1582 } else if (strcmp(*argv, "src") == 0) {
1583 NEXT_ARG();
1584 get_prefix(&filter.rprefsrc, *argv, do_ipv6);
1585 } else if (matches(*argv, "realms") == 0) {
1586 __u32 realm;
1587
1588 NEXT_ARG();
1589 if (get_rt_realms_or_raw(&realm, *argv))
1590 invarg("invalid realms\n", *argv);
1591 filter.realm = realm;
1592 filter.realmmask = ~0U;
1593 if ((filter.realm&0xFFFF) == 0 &&
1594 (*argv)[strlen(*argv) - 1] == '/')
1595 filter.realmmask &= ~0xFFFF;
1596 if ((filter.realm&0xFFFF0000U) == 0 &&
1597 (strchr(*argv, '/') == NULL ||
1598 (*argv)[0] == '/'))
1599 filter.realmmask &= ~0xFFFF0000U;
1600 } else if (matches(*argv, "from") == 0) {
1601 NEXT_ARG();
1602 if (matches(*argv, "root") == 0) {
1603 NEXT_ARG();
1604 get_prefix(&filter.rsrc, *argv, do_ipv6);
1605 } else if (matches(*argv, "match") == 0) {
1606 NEXT_ARG();
1607 get_prefix(&filter.msrc, *argv, do_ipv6);
1608 } else {
1609 if (matches(*argv, "exact") == 0) {
1610 NEXT_ARG();
1611 }
1612 get_prefix(&filter.msrc, *argv, do_ipv6);
1613 filter.rsrc = filter.msrc;
1614 }
1615 } else {
1616 if (matches(*argv, "to") == 0) {
1617 NEXT_ARG();
1618 }
1619 if (matches(*argv, "root") == 0) {
1620 NEXT_ARG();
1621 get_prefix(&filter.rdst, *argv, do_ipv6);
1622 } else if (matches(*argv, "match") == 0) {
1623 NEXT_ARG();
1624 get_prefix(&filter.mdst, *argv, do_ipv6);
1625 } else {
1626 if (matches(*argv, "exact") == 0) {
1627 NEXT_ARG();
1628 }
1629 get_prefix(&filter.mdst, *argv, do_ipv6);
1630 filter.rdst = filter.mdst;
1631 }
1632 }
1633 argc--; argv++;
1634 }
1635
1636 if (do_ipv6 == AF_UNSPEC && filter.tb)
1637 do_ipv6 = AF_INET;
1638
1639 if (id || od) {
1640 int idx;
1641
1642 if (id) {
1643 if ((idx = ll_name_to_index(id)) == 0) {
1644 fprintf(stderr, "Cannot find device \"%s\"\n", id);
1645 return -1;
1646 }
1647 filter.iif = idx;
1648 filter.iifmask = -1;
1649 }
1650 if (od) {
1651 if ((idx = ll_name_to_index(od)) == 0) {
1652 fprintf(stderr, "Cannot find device \"%s\"\n", od);
1653 return -1;
1654 }
1655 filter.oif = idx;
1656 filter.oifmask = -1;
1657 }
1658 }
1659 filter.mark = mark;
1660
1661 if (action == IPROUTE_FLUSH) {
1662 int round = 0;
1663 char flushb[4096-512];
1664 time_t start = time(0);
1665
1666 if (filter.cloned) {
1667 if (do_ipv6 != AF_INET6) {
1668 iproute_flush_cache();
1669 if (show_stats)
1670 printf("*** IPv4 routing cache is flushed.\n");
1671 }
1672 if (do_ipv6 == AF_INET)
1673 return 0;
1674 }
1675
1676 filter.flushb = flushb;
1677 filter.flushp = 0;
1678 filter.flushe = sizeof(flushb);
1679
1680 for (;;) {
1681 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
1682 perror("Cannot send dump request");
1683 return -2;
1684 }
1685 filter.flushed = 0;
1686 if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
1687 fprintf(stderr, "Flush terminated\n");
1688 return -2;
1689 }
1690 if (filter.flushed == 0) {
1691 if (show_stats) {
1692 if (round == 0 && (!filter.cloned || do_ipv6 == AF_INET6))
1693 printf("Nothing to flush.\n");
1694 else
1695 printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":"");
1696 }
1697 fflush(stdout);
1698 return 0;
1699 }
1700 round++;
1701 if ((ret = flush_update()) < 0)
1702 return ret;
1703
1704 if (time(0) - start > 30) {
1705 printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
1706 (long)(time(0) - start), filter.flushed);
1707 return -1;
1708 }
1709
1710 if (show_stats) {
1711 printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
1712 fflush(stdout);
1713 }
1714 }
1715 }
1716
1717 if (!filter.cloned) {
1718 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
1719 perror("Cannot send dump request");
1720 return -2;
1721 }
1722 } else {
1723 if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
1724 perror("Cannot send dump request");
1725 return -2;
1726 }
1727 }
1728
1729 if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
1730 fprintf(stderr, "Dump terminated\n");
1731 return -2;
1732 }
1733
1734 return 0;
1735 }
1736
1737
1738 static int iproute_get(int argc, char **argv)
1739 {
1740 struct {
1741 struct nlmsghdr n;
1742 struct rtmsg r;
1743 char buf[1024];
1744 } req = {
1745 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
1746 .n.nlmsg_flags = NLM_F_REQUEST,
1747 .n.nlmsg_type = RTM_GETROUTE,
1748 .r.rtm_family = preferred_family,
1749 };
1750 char *idev = NULL;
1751 char *odev = NULL;
1752 struct nlmsghdr *answer;
1753 int connected = 0;
1754 int fib_match = 0;
1755 int from_ok = 0;
1756 unsigned int mark = 0;
1757
1758 iproute_reset_filter(0);
1759 filter.cloned = 2;
1760
1761 while (argc > 0) {
1762 if (strcmp(*argv, "tos") == 0 ||
1763 matches(*argv, "dsfield") == 0) {
1764 __u32 tos;
1765
1766 NEXT_ARG();
1767 if (rtnl_dsfield_a2n(&tos, *argv))
1768 invarg("TOS value is invalid\n", *argv);
1769 req.r.rtm_tos = tos;
1770 } else if (matches(*argv, "from") == 0) {
1771 inet_prefix addr;
1772
1773 NEXT_ARG();
1774 if (matches(*argv, "help") == 0)
1775 usage();
1776 from_ok = 1;
1777 get_prefix(&addr, *argv, req.r.rtm_family);
1778 if (req.r.rtm_family == AF_UNSPEC)
1779 req.r.rtm_family = addr.family;
1780 if (addr.bytelen)
1781 addattr_l(&req.n, sizeof(req), RTA_SRC,
1782 &addr.data, addr.bytelen);
1783 req.r.rtm_src_len = addr.bitlen;
1784 } else if (matches(*argv, "iif") == 0) {
1785 NEXT_ARG();
1786 idev = *argv;
1787 } else if (matches(*argv, "mark") == 0) {
1788 NEXT_ARG();
1789 if (get_unsigned(&mark, *argv, 0))
1790 invarg("invalid mark value", *argv);
1791 } else if (matches(*argv, "oif") == 0 ||
1792 strcmp(*argv, "dev") == 0) {
1793 NEXT_ARG();
1794 odev = *argv;
1795 } else if (matches(*argv, "notify") == 0) {
1796 req.r.rtm_flags |= RTM_F_NOTIFY;
1797 } else if (matches(*argv, "connected") == 0) {
1798 connected = 1;
1799 } else if (matches(*argv, "vrf") == 0) {
1800 NEXT_ARG();
1801 if (!name_is_vrf(*argv))
1802 invarg("Invalid VRF\n", *argv);
1803 odev = *argv;
1804 } else if (matches(*argv, "uid") == 0) {
1805 uid_t uid;
1806
1807 NEXT_ARG();
1808 if (get_unsigned(&uid, *argv, 0))
1809 invarg("invalid UID\n", *argv);
1810 addattr32(&req.n, sizeof(req), RTA_UID, uid);
1811 } else if (matches(*argv, "fibmatch") == 0) {
1812 fib_match = 1;
1813 } else if (strcmp(*argv, "as") == 0) {
1814 inet_prefix addr;
1815
1816 NEXT_ARG();
1817 if (strcmp(*argv, "to") == 0)
1818 NEXT_ARG();
1819 get_addr(&addr, *argv, req.r.rtm_family);
1820 if (req.r.rtm_family == AF_UNSPEC)
1821 req.r.rtm_family = addr.family;
1822 addattr_l(&req.n, sizeof(req), RTA_NEWDST,
1823 &addr.data, addr.bytelen);
1824 } else {
1825 inet_prefix addr;
1826
1827 if (strcmp(*argv, "to") == 0) {
1828 NEXT_ARG();
1829 }
1830 if (matches(*argv, "help") == 0)
1831 usage();
1832 get_prefix(&addr, *argv, req.r.rtm_family);
1833 if (req.r.rtm_family == AF_UNSPEC)
1834 req.r.rtm_family = addr.family;
1835 if (addr.bytelen)
1836 addattr_l(&req.n, sizeof(req),
1837 RTA_DST, &addr.data, addr.bytelen);
1838 req.r.rtm_dst_len = addr.bitlen;
1839 }
1840 argc--; argv++;
1841 }
1842
1843 if (req.r.rtm_dst_len == 0) {
1844 fprintf(stderr, "need at least a destination address\n");
1845 return -1;
1846 }
1847
1848 if (idev || odev) {
1849 int idx;
1850
1851 if (idev) {
1852 if ((idx = ll_name_to_index(idev)) == 0) {
1853 fprintf(stderr, "Cannot find device \"%s\"\n", idev);
1854 return -1;
1855 }
1856 addattr32(&req.n, sizeof(req), RTA_IIF, idx);
1857 }
1858 if (odev) {
1859 if ((idx = ll_name_to_index(odev)) == 0) {
1860 fprintf(stderr, "Cannot find device \"%s\"\n", odev);
1861 return -1;
1862 }
1863 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1864 }
1865 }
1866 if (mark)
1867 addattr32(&req.n, sizeof(req), RTA_MARK, mark);
1868
1869 if (req.r.rtm_family == AF_UNSPEC)
1870 req.r.rtm_family = AF_INET;
1871
1872 req.r.rtm_flags |= RTM_F_LOOKUP_TABLE;
1873 if (fib_match)
1874 req.r.rtm_flags |= RTM_F_FIB_MATCH;
1875
1876 if (rtnl_talk(&rth, &req.n, &answer) < 0)
1877 return -2;
1878
1879 if (connected && !from_ok) {
1880 struct rtmsg *r = NLMSG_DATA(answer);
1881 int len = answer->nlmsg_len;
1882 struct rtattr *tb[RTA_MAX+1];
1883
1884 if (print_route(NULL, answer, (void *)stdout) < 0) {
1885 fprintf(stderr, "An error :-)\n");
1886 free(answer);
1887 return -1;
1888 }
1889
1890 if (answer->nlmsg_type != RTM_NEWROUTE) {
1891 fprintf(stderr, "Not a route?\n");
1892 free(answer);
1893 return -1;
1894 }
1895 len -= NLMSG_LENGTH(sizeof(*r));
1896 if (len < 0) {
1897 fprintf(stderr, "Wrong len %d\n", len);
1898 free(answer);
1899 return -1;
1900 }
1901
1902 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1903
1904 if (tb[RTA_PREFSRC]) {
1905 tb[RTA_PREFSRC]->rta_type = RTA_SRC;
1906 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
1907 } else if (!tb[RTA_SRC]) {
1908 fprintf(stderr, "Failed to connect the route\n");
1909 free(answer);
1910 return -1;
1911 }
1912 if (!odev && tb[RTA_OIF])
1913 tb[RTA_OIF]->rta_type = 0;
1914 if (tb[RTA_GATEWAY])
1915 tb[RTA_GATEWAY]->rta_type = 0;
1916 if (tb[RTA_VIA])
1917 tb[RTA_VIA]->rta_type = 0;
1918 if (!idev && tb[RTA_IIF])
1919 tb[RTA_IIF]->rta_type = 0;
1920 req.n.nlmsg_flags = NLM_F_REQUEST;
1921 req.n.nlmsg_type = RTM_GETROUTE;
1922
1923 free(answer);
1924 if (rtnl_talk(&rth, &req.n, &answer) < 0)
1925 return -2;
1926 }
1927
1928 if (print_route(NULL, answer, (void *)stdout) < 0) {
1929 fprintf(stderr, "An error :-)\n");
1930 free(answer);
1931 return -1;
1932 }
1933
1934 free(answer);
1935 return 0;
1936 }
1937
1938 static int rtattr_cmp(const struct rtattr *rta1, const struct rtattr *rta2)
1939 {
1940 if (!rta1 || !rta2 || rta1->rta_len != rta2->rta_len)
1941 return 1;
1942
1943 return memcmp(RTA_DATA(rta1), RTA_DATA(rta2), RTA_PAYLOAD(rta1));
1944 }
1945
1946 static int restore_handler(const struct sockaddr_nl *nl,
1947 struct rtnl_ctrl_data *ctrl,
1948 struct nlmsghdr *n, void *arg)
1949 {
1950 struct rtmsg *r = NLMSG_DATA(n);
1951 struct rtattr *tb[RTA_MAX+1];
1952 int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
1953 int ret, prio = *(int *)arg;
1954
1955 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1956
1957 /* Restore routes in correct order:
1958 * 0. ones for local addresses,
1959 * 1. ones for local networks,
1960 * 2. others (remote networks/hosts).
1961 */
1962 if (!prio && !tb[RTA_GATEWAY] && (!tb[RTA_PREFSRC] ||
1963 !rtattr_cmp(tb[RTA_PREFSRC], tb[RTA_DST])))
1964 goto restore;
1965 else if (prio == 1 && !tb[RTA_GATEWAY] && tb[RTA_PREFSRC] &&
1966 rtattr_cmp(tb[RTA_PREFSRC], tb[RTA_DST]))
1967 goto restore;
1968 else if (prio == 2 && tb[RTA_GATEWAY])
1969 goto restore;
1970
1971 return 0;
1972
1973 restore:
1974 n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
1975
1976 ll_init_map(&rth);
1977
1978 ret = rtnl_talk(&rth, n, NULL);
1979 if ((ret < 0) && (errno == EEXIST))
1980 ret = 0;
1981
1982 return ret;
1983 }
1984
1985 static int route_dump_check_magic(void)
1986 {
1987 int ret;
1988 __u32 magic = 0;
1989
1990 if (isatty(STDIN_FILENO)) {
1991 fprintf(stderr, "Can't restore route dump from a terminal\n");
1992 return -1;
1993 }
1994
1995 ret = fread(&magic, sizeof(magic), 1, stdin);
1996 if (magic != route_dump_magic) {
1997 fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n", ret, magic);
1998 return -1;
1999 }
2000
2001 return 0;
2002 }
2003
2004 static int iproute_restore(void)
2005 {
2006 int pos, prio;
2007
2008 if (route_dump_check_magic())
2009 return -1;
2010
2011 pos = ftell(stdin);
2012 if (pos == -1) {
2013 perror("Failed to restore: ftell");
2014 return -1;
2015 }
2016
2017 for (prio = 0; prio < 3; prio++) {
2018 int err;
2019
2020 err = rtnl_from_file(stdin, &restore_handler, &prio);
2021 if (err)
2022 return -2;
2023
2024 if (fseek(stdin, pos, SEEK_SET) == -1) {
2025 perror("Failed to restore: fseek");
2026 return -1;
2027 }
2028 }
2029
2030 return 0;
2031 }
2032
2033 static int show_handler(const struct sockaddr_nl *nl,
2034 struct rtnl_ctrl_data *ctrl,
2035 struct nlmsghdr *n, void *arg)
2036 {
2037 print_route(nl, n, stdout);
2038 return 0;
2039 }
2040
2041 static int iproute_showdump(void)
2042 {
2043 if (route_dump_check_magic())
2044 return -1;
2045
2046 if (rtnl_from_file(stdin, &show_handler, NULL))
2047 return -2;
2048
2049 return 0;
2050 }
2051
2052 void iproute_reset_filter(int ifindex)
2053 {
2054 memset(&filter, 0, sizeof(filter));
2055 filter.mdst.bitlen = -1;
2056 filter.msrc.bitlen = -1;
2057 filter.oif = ifindex;
2058 if (filter.oif > 0)
2059 filter.oifmask = -1;
2060 }
2061
2062 int do_iproute(int argc, char **argv)
2063 {
2064 if (argc < 1)
2065 return iproute_list_flush_or_save(0, NULL, IPROUTE_LIST);
2066
2067 if (matches(*argv, "add") == 0)
2068 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL,
2069 argc-1, argv+1);
2070 if (matches(*argv, "change") == 0 || strcmp(*argv, "chg") == 0)
2071 return iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE,
2072 argc-1, argv+1);
2073 if (matches(*argv, "replace") == 0)
2074 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE,
2075 argc-1, argv+1);
2076 if (matches(*argv, "prepend") == 0)
2077 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE,
2078 argc-1, argv+1);
2079 if (matches(*argv, "append") == 0)
2080 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_APPEND,
2081 argc-1, argv+1);
2082 if (matches(*argv, "test") == 0)
2083 return iproute_modify(RTM_NEWROUTE, NLM_F_EXCL,
2084 argc-1, argv+1);
2085 if (matches(*argv, "delete") == 0)
2086 return iproute_modify(RTM_DELROUTE, 0,
2087 argc-1, argv+1);
2088 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
2089 || matches(*argv, "lst") == 0)
2090 return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_LIST);
2091 if (matches(*argv, "get") == 0)
2092 return iproute_get(argc-1, argv+1);
2093 if (matches(*argv, "flush") == 0)
2094 return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_FLUSH);
2095 if (matches(*argv, "save") == 0)
2096 return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_SAVE);
2097 if (matches(*argv, "restore") == 0)
2098 return iproute_restore();
2099 if (matches(*argv, "showdump") == 0)
2100 return iproute_showdump();
2101 if (matches(*argv, "help") == 0)
2102 usage();
2103 fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
2104 exit(-1);
2105 }