]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iproute.c
iproute: refactor cacheinfo printing
[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 int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
448 {
449 FILE *fp = (FILE *)arg;
450 struct rtmsg *r = NLMSG_DATA(n);
451 int len = n->nlmsg_len;
452 struct rtattr *tb[RTA_MAX+1];
453 int host_len, family;
454 __u32 table;
455 int ret;
456
457 SPRINT_BUF(b1);
458
459 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
460 fprintf(stderr, "Not a route: %08x %08x %08x\n",
461 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
462 return -1;
463 }
464 if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
465 return 0;
466 len -= NLMSG_LENGTH(sizeof(*r));
467 if (len < 0) {
468 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
469 return -1;
470 }
471
472 host_len = af_bit_len(r->rtm_family);
473
474 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
475 table = rtm_get_table(r, tb);
476
477 if (!filter_nlmsg(n, tb, host_len))
478 return 0;
479
480 if (filter.flushb) {
481 struct nlmsghdr *fn;
482
483 if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
484 if ((ret = flush_update()) < 0)
485 return ret;
486 }
487 fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp));
488 memcpy(fn, n, n->nlmsg_len);
489 fn->nlmsg_type = RTM_DELROUTE;
490 fn->nlmsg_flags = NLM_F_REQUEST;
491 fn->nlmsg_seq = ++rth.seq;
492 filter.flushp = (((char *)fn) + n->nlmsg_len) - filter.flushb;
493 filter.flushed++;
494 if (show_stats < 2)
495 return 0;
496 }
497
498 if (n->nlmsg_type == RTM_DELROUTE)
499 fprintf(fp, "Deleted ");
500 if ((r->rtm_type != RTN_UNICAST || show_details > 0) &&
501 (!filter.typemask || (filter.typemask & (1 << r->rtm_type))))
502 fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
503
504 if (tb[RTA_DST]) {
505 family = get_real_family(r->rtm_type, r->rtm_family);
506 if (r->rtm_dst_len != host_len) {
507 fprintf(fp, "%s/%u ",
508 rt_addr_n2a_rta(family, tb[RTA_DST]),
509 r->rtm_dst_len);
510 } else {
511 fprintf(fp, "%s ",
512 format_host_rta(family, tb[RTA_DST]));
513 }
514 } else if (r->rtm_dst_len) {
515 fprintf(fp, "0/%d ", r->rtm_dst_len);
516 } else {
517 fprintf(fp, "default ");
518 }
519 if (tb[RTA_SRC]) {
520 family = get_real_family(r->rtm_type, r->rtm_family);
521 if (r->rtm_src_len != host_len) {
522 fprintf(fp, "from %s/%u ",
523 rt_addr_n2a_rta(family, tb[RTA_SRC]),
524 r->rtm_src_len);
525 } else {
526 fprintf(fp, "from %s ",
527 format_host_rta(family, tb[RTA_SRC]));
528 }
529 } else if (r->rtm_src_len) {
530 fprintf(fp, "from 0/%u ", r->rtm_src_len);
531 }
532 if (tb[RTA_NEWDST]) {
533 fprintf(fp, "as to %s ",
534 format_host_rta(r->rtm_family, tb[RTA_NEWDST]));
535 }
536
537 if (tb[RTA_ENCAP])
538 lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]);
539
540 if (r->rtm_tos && filter.tosmask != -1) {
541 SPRINT_BUF(b1);
542 fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
543 }
544
545 if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
546 fprintf(fp, "via %s ",
547 format_host_rta(r->rtm_family, tb[RTA_GATEWAY]));
548 }
549 if (tb[RTA_VIA]) {
550 size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
551 struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
552
553 fprintf(fp, "via %s %s ",
554 family_name(via->rtvia_family),
555 format_host(via->rtvia_family, len, via->rtvia_addr));
556 }
557 if (tb[RTA_OIF] && filter.oifmask != -1)
558 fprintf(fp, "dev %s ", ll_index_to_name(rta_getattr_u32(tb[RTA_OIF])));
559
560 if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
561 fprintf(fp, "table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
562 if (!(r->rtm_flags&RTM_F_CLONED)) {
563 if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1)
564 fprintf(fp, "proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
565 if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1)
566 fprintf(fp, "scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
567 }
568 if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
569 /* Do not use format_host(). It is our local addr
570 and symbolic name will not be useful.
571 */
572 fprintf(fp, "src %s ",
573 rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC]));
574 }
575 if (tb[RTA_PRIORITY] && filter.metricmask != -1)
576 fprintf(fp, "metric %u ", rta_getattr_u32(tb[RTA_PRIORITY]));
577
578 print_rt_flags(fp, r->rtm_flags);
579
580 if (tb[RTA_MARK]) {
581 unsigned int mark = rta_getattr_u32(tb[RTA_MARK]);
582
583 if (mark) {
584 if (mark >= 16)
585 fprintf(fp, "mark 0x%x ", mark);
586 else
587 fprintf(fp, "mark %u ", mark);
588 }
589 }
590
591 if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
592 __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
593 __u32 from = to>>16;
594
595 to &= 0xFFFF;
596 fprintf(fp, "realm%s ", from ? "s" : "");
597 if (from) {
598 fprintf(fp, "%s/",
599 rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
600 }
601 fprintf(fp, "%s ",
602 rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
603 }
604
605 if (tb[RTA_UID])
606 fprintf(fp, "uid %u ", rta_getattr_u32(tb[RTA_UID]));
607
608 if ((r->rtm_flags & RTM_F_CLONED) && r->rtm_family == AF_INET) {
609 print_cache_flags(fp, r->rtm_flags);
610
611 if (tb[RTA_CACHEINFO])
612 print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
613
614 } else if (r->rtm_family == AF_INET6) {
615
616 if (r->rtm_flags & RTM_F_CLONED)
617 fprintf(fp, "%s cache ", _SL_);
618
619 if (tb[RTA_CACHEINFO])
620 print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
621 }
622
623 if (tb[RTA_METRICS]) {
624 int i;
625 unsigned int mxlock = 0;
626 struct rtattr *mxrta[RTAX_MAX+1];
627
628 parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
629 RTA_PAYLOAD(tb[RTA_METRICS]));
630 if (mxrta[RTAX_LOCK])
631 mxlock = rta_getattr_u32(mxrta[RTAX_LOCK]);
632
633 for (i = 2; i <= RTAX_MAX; i++) {
634 __u32 val = 0U;
635
636 if (mxrta[i] == NULL && !(mxlock & (1 << i)))
637 continue;
638
639 if (mxrta[i] != NULL && i != RTAX_CC_ALGO)
640 val = rta_getattr_u32(mxrta[i]);
641
642 if (i == RTAX_HOPLIMIT && (int)val == -1)
643 continue;
644
645 if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
646 fprintf(fp, "%s ", mx_names[i]);
647 else
648 fprintf(fp, "metric %d ", i);
649
650 if (mxlock & (1<<i))
651 fprintf(fp, "lock ");
652
653 switch (i) {
654 case RTAX_FEATURES:
655 print_rtax_features(fp, val);
656 break;
657 default:
658 fprintf(fp, "%u ", val);
659 break;
660
661 case RTAX_RTT:
662 case RTAX_RTTVAR:
663 case RTAX_RTO_MIN:
664 if (i == RTAX_RTT)
665 val /= 8;
666 else if (i == RTAX_RTTVAR)
667 val /= 4;
668
669 if (val >= 1000)
670 fprintf(fp, "%gs ", val/1e3);
671 else
672 fprintf(fp, "%ums ", val);
673 break;
674 case RTAX_CC_ALGO:
675 fprintf(fp, "%s ", rta_getattr_str(mxrta[i]));
676 break;
677 }
678 }
679 }
680 if (tb[RTA_IIF] && filter.iifmask != -1) {
681 fprintf(fp, "iif %s ",
682 ll_index_to_name(rta_getattr_u32(tb[RTA_IIF])));
683 }
684 if (tb[RTA_MULTIPATH]) {
685 struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]);
686 int first = 1;
687
688 len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
689
690 for (;;) {
691 if (len < sizeof(*nh))
692 break;
693 if (nh->rtnh_len > len)
694 break;
695 if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
696 if (first) {
697 fprintf(fp, "Oifs: ");
698 first = 0;
699 } else {
700 fprintf(fp, " ");
701 }
702 } else
703 fprintf(fp, "%s\tnexthop ", _SL_);
704 if (nh->rtnh_len > sizeof(*nh)) {
705 parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh));
706
707 if (tb[RTA_ENCAP])
708 lwt_print_encap(fp,
709 tb[RTA_ENCAP_TYPE],
710 tb[RTA_ENCAP]);
711 if (tb[RTA_NEWDST]) {
712 fprintf(fp, "as to %s ",
713 format_host_rta(r->rtm_family,
714 tb[RTA_NEWDST]));
715 }
716 if (tb[RTA_GATEWAY]) {
717 fprintf(fp, "via %s ",
718 format_host_rta(r->rtm_family,
719 tb[RTA_GATEWAY]));
720 }
721 if (tb[RTA_VIA]) {
722 size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
723 struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
724
725 fprintf(fp, "via %s %s ",
726 family_name(via->rtvia_family),
727 format_host(via->rtvia_family, len, via->rtvia_addr));
728 }
729 if (tb[RTA_FLOW]) {
730 __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
731 __u32 from = to>>16;
732
733 to &= 0xFFFF;
734 fprintf(fp, "realm%s ", from ? "s" : "");
735 if (from) {
736 fprintf(fp, "%s/",
737 rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
738 }
739 fprintf(fp, "%s ",
740 rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
741 }
742 }
743 if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
744 fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
745 if (nh->rtnh_hops != 1)
746 fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
747 fprintf(fp, " ");
748 } else {
749 fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
750 if (r->rtm_family != AF_MPLS)
751 fprintf(fp, "weight %d ",
752 nh->rtnh_hops+1);
753 }
754
755 print_rt_flags(fp, nh->rtnh_flags);
756
757 len -= NLMSG_ALIGN(nh->rtnh_len);
758 nh = RTNH_NEXT(nh);
759 }
760 }
761
762 if (tb[RTA_PREF])
763 print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF]));
764
765 if (tb[RTA_TTL_PROPAGATE]) {
766 fprintf(fp, "ttl-propagate ");
767 if (rta_getattr_u8(tb[RTA_TTL_PROPAGATE]))
768 fprintf(fp, "enabled");
769 else
770 fprintf(fp, "disabled");
771 }
772 fprintf(fp, "\n");
773 fflush(fp);
774 return 0;
775 }
776
777 static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
778 struct rtattr *rta, struct rtnexthop *rtnh,
779 int *argcp, char ***argvp)
780 {
781 int argc = *argcp;
782 char **argv = *argvp;
783
784 while (++argv, --argc > 0) {
785 if (strcmp(*argv, "via") == 0) {
786 inet_prefix addr;
787 int family;
788
789 NEXT_ARG();
790 family = read_family(*argv);
791 if (family == AF_UNSPEC)
792 family = r->rtm_family;
793 else
794 NEXT_ARG();
795 get_addr(&addr, *argv, family);
796 if (r->rtm_family == AF_UNSPEC)
797 r->rtm_family = addr.family;
798 if (addr.family == r->rtm_family) {
799 rta_addattr_l(rta, 4096, RTA_GATEWAY, &addr.data, addr.bytelen);
800 rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
801 } else {
802 rta_addattr_l(rta, 4096, RTA_VIA, &addr.family, addr.bytelen+2);
803 rtnh->rtnh_len += RTA_SPACE(addr.bytelen+2);
804 }
805 } else if (strcmp(*argv, "dev") == 0) {
806 NEXT_ARG();
807 if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) {
808 fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
809 return -1;
810 }
811 } else if (strcmp(*argv, "weight") == 0) {
812 unsigned int w;
813
814 NEXT_ARG();
815 if (get_unsigned(&w, *argv, 0) || w == 0 || w > 256)
816 invarg("\"weight\" is invalid\n", *argv);
817 rtnh->rtnh_hops = w - 1;
818 } else if (strcmp(*argv, "onlink") == 0) {
819 rtnh->rtnh_flags |= RTNH_F_ONLINK;
820 } else if (matches(*argv, "realms") == 0) {
821 __u32 realm;
822
823 NEXT_ARG();
824 if (get_rt_realms_or_raw(&realm, *argv))
825 invarg("\"realm\" value is invalid\n", *argv);
826 rta_addattr32(rta, 4096, RTA_FLOW, realm);
827 rtnh->rtnh_len += sizeof(struct rtattr) + 4;
828 } else if (strcmp(*argv, "encap") == 0) {
829 int len = rta->rta_len;
830
831 lwt_parse_encap(rta, 4096, &argc, &argv);
832 rtnh->rtnh_len += rta->rta_len - len;
833 } else if (strcmp(*argv, "as") == 0) {
834 inet_prefix addr;
835
836 NEXT_ARG();
837 if (strcmp(*argv, "to") == 0)
838 NEXT_ARG();
839 get_addr(&addr, *argv, r->rtm_family);
840 rta_addattr_l(rta, 4096, RTA_NEWDST, &addr.data,
841 addr.bytelen);
842 rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
843 } else
844 break;
845 }
846 *argcp = argc;
847 *argvp = argv;
848 return 0;
849 }
850
851 static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r,
852 int argc, char **argv)
853 {
854 char buf[1024];
855 struct rtattr *rta = (void *)buf;
856 struct rtnexthop *rtnh;
857
858 rta->rta_type = RTA_MULTIPATH;
859 rta->rta_len = RTA_LENGTH(0);
860 rtnh = RTA_DATA(rta);
861
862 while (argc > 0) {
863 if (strcmp(*argv, "nexthop") != 0) {
864 fprintf(stderr, "Error: \"nexthop\" or end of line is expected instead of \"%s\"\n", *argv);
865 exit(-1);
866 }
867 if (argc <= 1) {
868 fprintf(stderr, "Error: unexpected end of line after \"nexthop\"\n");
869 exit(-1);
870 }
871 memset(rtnh, 0, sizeof(*rtnh));
872 rtnh->rtnh_len = sizeof(*rtnh);
873 rta->rta_len += rtnh->rtnh_len;
874 parse_one_nh(n, r, rta, rtnh, &argc, &argv);
875 rtnh = RTNH_NEXT(rtnh);
876 }
877
878 if (rta->rta_len > RTA_LENGTH(0))
879 addattr_l(n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
880 return 0;
881 }
882
883 static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
884 {
885 struct {
886 struct nlmsghdr n;
887 struct rtmsg r;
888 char buf[1024];
889 } req = {
890 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
891 .n.nlmsg_flags = NLM_F_REQUEST | flags,
892 .n.nlmsg_type = cmd,
893 .r.rtm_family = preferred_family,
894 .r.rtm_table = RT_TABLE_MAIN,
895 .r.rtm_scope = RT_SCOPE_NOWHERE,
896 };
897 char mxbuf[256];
898 struct rtattr *mxrta = (void *)mxbuf;
899 unsigned int mxlock = 0;
900 char *d = NULL;
901 int gw_ok = 0;
902 int dst_ok = 0;
903 int nhs_ok = 0;
904 int scope_ok = 0;
905 int table_ok = 0;
906 int raw = 0;
907 int type_ok = 0;
908
909 if (cmd != RTM_DELROUTE) {
910 req.r.rtm_protocol = RTPROT_BOOT;
911 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
912 req.r.rtm_type = RTN_UNICAST;
913 }
914
915 mxrta->rta_type = RTA_METRICS;
916 mxrta->rta_len = RTA_LENGTH(0);
917
918 while (argc > 0) {
919 if (strcmp(*argv, "src") == 0) {
920 inet_prefix addr;
921
922 NEXT_ARG();
923 get_addr(&addr, *argv, req.r.rtm_family);
924 if (req.r.rtm_family == AF_UNSPEC)
925 req.r.rtm_family = addr.family;
926 addattr_l(&req.n, sizeof(req),
927 RTA_PREFSRC, &addr.data, addr.bytelen);
928 } else if (strcmp(*argv, "as") == 0) {
929 inet_prefix addr;
930
931 NEXT_ARG();
932 if (strcmp(*argv, "to") == 0) {
933 NEXT_ARG();
934 }
935 get_addr(&addr, *argv, req.r.rtm_family);
936 if (req.r.rtm_family == AF_UNSPEC)
937 req.r.rtm_family = addr.family;
938 addattr_l(&req.n, sizeof(req),
939 RTA_NEWDST, &addr.data, addr.bytelen);
940 } else if (strcmp(*argv, "via") == 0) {
941 inet_prefix addr;
942 int family;
943
944 if (gw_ok) {
945 invarg("use nexthop syntax to specify multiple via\n",
946 *argv);
947 }
948 gw_ok = 1;
949 NEXT_ARG();
950 family = read_family(*argv);
951 if (family == AF_UNSPEC)
952 family = req.r.rtm_family;
953 else
954 NEXT_ARG();
955 get_addr(&addr, *argv, family);
956 if (req.r.rtm_family == AF_UNSPEC)
957 req.r.rtm_family = addr.family;
958 if (addr.family == req.r.rtm_family)
959 addattr_l(&req.n, sizeof(req), RTA_GATEWAY,
960 &addr.data, addr.bytelen);
961 else
962 addattr_l(&req.n, sizeof(req), RTA_VIA,
963 &addr.family, addr.bytelen+2);
964 } else if (strcmp(*argv, "from") == 0) {
965 inet_prefix addr;
966
967 NEXT_ARG();
968 get_prefix(&addr, *argv, req.r.rtm_family);
969 if (req.r.rtm_family == AF_UNSPEC)
970 req.r.rtm_family = addr.family;
971 if (addr.bytelen)
972 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
973 req.r.rtm_src_len = addr.bitlen;
974 } else if (strcmp(*argv, "tos") == 0 ||
975 matches(*argv, "dsfield") == 0) {
976 __u32 tos;
977
978 NEXT_ARG();
979 if (rtnl_dsfield_a2n(&tos, *argv))
980 invarg("\"tos\" value is invalid\n", *argv);
981 req.r.rtm_tos = tos;
982 } else if (strcmp(*argv, "expires") == 0) {
983 __u32 expires;
984
985 NEXT_ARG();
986 if (get_u32(&expires, *argv, 0))
987 invarg("\"expires\" value is invalid\n", *argv);
988 addattr32(&req.n, sizeof(req), RTA_EXPIRES, expires);
989 } else if (matches(*argv, "metric") == 0 ||
990 matches(*argv, "priority") == 0 ||
991 strcmp(*argv, "preference") == 0) {
992 __u32 metric;
993
994 NEXT_ARG();
995 if (get_u32(&metric, *argv, 0))
996 invarg("\"metric\" value is invalid\n", *argv);
997 addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
998 } else if (strcmp(*argv, "scope") == 0) {
999 __u32 scope = 0;
1000
1001 NEXT_ARG();
1002 if (rtnl_rtscope_a2n(&scope, *argv))
1003 invarg("invalid \"scope\" value\n", *argv);
1004 req.r.rtm_scope = scope;
1005 scope_ok = 1;
1006 } else if (strcmp(*argv, "mtu") == 0) {
1007 unsigned int mtu;
1008
1009 NEXT_ARG();
1010 if (strcmp(*argv, "lock") == 0) {
1011 mxlock |= (1<<RTAX_MTU);
1012 NEXT_ARG();
1013 }
1014 if (get_unsigned(&mtu, *argv, 0))
1015 invarg("\"mtu\" value is invalid\n", *argv);
1016 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
1017 } else if (strcmp(*argv, "hoplimit") == 0) {
1018 unsigned int hoplimit;
1019
1020 NEXT_ARG();
1021 if (strcmp(*argv, "lock") == 0) {
1022 mxlock |= (1<<RTAX_HOPLIMIT);
1023 NEXT_ARG();
1024 }
1025 if (get_unsigned(&hoplimit, *argv, 0) || hoplimit > 255)
1026 invarg("\"hoplimit\" value is invalid\n", *argv);
1027 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_HOPLIMIT, hoplimit);
1028 } else if (strcmp(*argv, "advmss") == 0) {
1029 unsigned int mss;
1030
1031 NEXT_ARG();
1032 if (strcmp(*argv, "lock") == 0) {
1033 mxlock |= (1<<RTAX_ADVMSS);
1034 NEXT_ARG();
1035 }
1036 if (get_unsigned(&mss, *argv, 0))
1037 invarg("\"mss\" value is invalid\n", *argv);
1038 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss);
1039 } else if (matches(*argv, "reordering") == 0) {
1040 unsigned int reord;
1041
1042 NEXT_ARG();
1043 if (strcmp(*argv, "lock") == 0) {
1044 mxlock |= (1<<RTAX_REORDERING);
1045 NEXT_ARG();
1046 }
1047 if (get_unsigned(&reord, *argv, 0))
1048 invarg("\"reordering\" value is invalid\n", *argv);
1049 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord);
1050 } else if (strcmp(*argv, "rtt") == 0) {
1051 unsigned int rtt;
1052
1053 NEXT_ARG();
1054 if (strcmp(*argv, "lock") == 0) {
1055 mxlock |= (1<<RTAX_RTT);
1056 NEXT_ARG();
1057 }
1058 if (get_time_rtt(&rtt, *argv, &raw))
1059 invarg("\"rtt\" value is invalid\n", *argv);
1060 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT,
1061 (raw) ? rtt : rtt * 8);
1062 } else if (strcmp(*argv, "rto_min") == 0) {
1063 unsigned int rto_min;
1064
1065 NEXT_ARG();
1066 mxlock |= (1<<RTAX_RTO_MIN);
1067 if (get_time_rtt(&rto_min, *argv, &raw))
1068 invarg("\"rto_min\" value is invalid\n",
1069 *argv);
1070 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
1071 rto_min);
1072 } else if (matches(*argv, "window") == 0) {
1073 unsigned int win;
1074
1075 NEXT_ARG();
1076 if (strcmp(*argv, "lock") == 0) {
1077 mxlock |= (1<<RTAX_WINDOW);
1078 NEXT_ARG();
1079 }
1080 if (get_unsigned(&win, *argv, 0))
1081 invarg("\"window\" value is invalid\n", *argv);
1082 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_WINDOW, win);
1083 } else if (matches(*argv, "cwnd") == 0) {
1084 unsigned int win;
1085
1086 NEXT_ARG();
1087 if (strcmp(*argv, "lock") == 0) {
1088 mxlock |= (1<<RTAX_CWND);
1089 NEXT_ARG();
1090 }
1091 if (get_unsigned(&win, *argv, 0))
1092 invarg("\"cwnd\" value is invalid\n", *argv);
1093 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win);
1094 } else if (matches(*argv, "initcwnd") == 0) {
1095 unsigned int win;
1096
1097 NEXT_ARG();
1098 if (strcmp(*argv, "lock") == 0) {
1099 mxlock |= (1<<RTAX_INITCWND);
1100 NEXT_ARG();
1101 }
1102 if (get_unsigned(&win, *argv, 0))
1103 invarg("\"initcwnd\" value is invalid\n", *argv);
1104 rta_addattr32(mxrta, sizeof(mxbuf),
1105 RTAX_INITCWND, win);
1106 } else if (matches(*argv, "initrwnd") == 0) {
1107 unsigned int win;
1108
1109 NEXT_ARG();
1110 if (strcmp(*argv, "lock") == 0) {
1111 mxlock |= (1<<RTAX_INITRWND);
1112 NEXT_ARG();
1113 }
1114 if (get_unsigned(&win, *argv, 0))
1115 invarg("\"initrwnd\" value is invalid\n", *argv);
1116 rta_addattr32(mxrta, sizeof(mxbuf),
1117 RTAX_INITRWND, win);
1118 } else if (matches(*argv, "features") == 0) {
1119 unsigned int features = 0;
1120
1121 while (argc > 0) {
1122 NEXT_ARG();
1123
1124 if (strcmp(*argv, "ecn") == 0)
1125 features |= RTAX_FEATURE_ECN;
1126 else
1127 invarg("\"features\" value not valid\n", *argv);
1128 break;
1129 }
1130
1131 rta_addattr32(mxrta, sizeof(mxbuf),
1132 RTAX_FEATURES, features);
1133 } else if (matches(*argv, "quickack") == 0) {
1134 unsigned int quickack;
1135
1136 NEXT_ARG();
1137 if (get_unsigned(&quickack, *argv, 0))
1138 invarg("\"quickack\" value is invalid\n", *argv);
1139 if (quickack != 1 && quickack != 0)
1140 invarg("\"quickack\" value should be 0 or 1\n", *argv);
1141 rta_addattr32(mxrta, sizeof(mxbuf),
1142 RTAX_QUICKACK, quickack);
1143 } else if (matches(*argv, "congctl") == 0) {
1144 NEXT_ARG();
1145 if (strcmp(*argv, "lock") == 0) {
1146 mxlock |= 1 << RTAX_CC_ALGO;
1147 NEXT_ARG();
1148 }
1149 rta_addattr_l(mxrta, sizeof(mxbuf), RTAX_CC_ALGO, *argv,
1150 strlen(*argv));
1151 } else if (matches(*argv, "rttvar") == 0) {
1152 unsigned int win;
1153
1154 NEXT_ARG();
1155 if (strcmp(*argv, "lock") == 0) {
1156 mxlock |= (1<<RTAX_RTTVAR);
1157 NEXT_ARG();
1158 }
1159 if (get_time_rtt(&win, *argv, &raw))
1160 invarg("\"rttvar\" value is invalid\n", *argv);
1161 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
1162 (raw) ? win : win * 4);
1163 } else if (matches(*argv, "ssthresh") == 0) {
1164 unsigned int win;
1165
1166 NEXT_ARG();
1167 if (strcmp(*argv, "lock") == 0) {
1168 mxlock |= (1<<RTAX_SSTHRESH);
1169 NEXT_ARG();
1170 }
1171 if (get_unsigned(&win, *argv, 0))
1172 invarg("\"ssthresh\" value is invalid\n", *argv);
1173 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_SSTHRESH, win);
1174 } else if (matches(*argv, "realms") == 0) {
1175 __u32 realm;
1176
1177 NEXT_ARG();
1178 if (get_rt_realms_or_raw(&realm, *argv))
1179 invarg("\"realm\" value is invalid\n", *argv);
1180 addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
1181 } else if (strcmp(*argv, "onlink") == 0) {
1182 req.r.rtm_flags |= RTNH_F_ONLINK;
1183 } else if (strcmp(*argv, "nexthop") == 0) {
1184 nhs_ok = 1;
1185 break;
1186 } else if (matches(*argv, "protocol") == 0) {
1187 __u32 prot;
1188
1189 NEXT_ARG();
1190 if (rtnl_rtprot_a2n(&prot, *argv))
1191 invarg("\"protocol\" value is invalid\n", *argv);
1192 req.r.rtm_protocol = prot;
1193 } else if (matches(*argv, "table") == 0) {
1194 __u32 tid;
1195
1196 NEXT_ARG();
1197 if (rtnl_rttable_a2n(&tid, *argv))
1198 invarg("\"table\" value is invalid\n", *argv);
1199 if (tid < 256)
1200 req.r.rtm_table = tid;
1201 else {
1202 req.r.rtm_table = RT_TABLE_UNSPEC;
1203 addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
1204 }
1205 table_ok = 1;
1206 } else if (matches(*argv, "vrf") == 0) {
1207 __u32 tid;
1208
1209 NEXT_ARG();
1210 tid = ipvrf_get_table(*argv);
1211 if (tid == 0)
1212 invarg("Invalid VRF\n", *argv);
1213 if (tid < 256)
1214 req.r.rtm_table = tid;
1215 else {
1216 req.r.rtm_table = RT_TABLE_UNSPEC;
1217 addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
1218 }
1219 table_ok = 1;
1220 } else if (strcmp(*argv, "dev") == 0 ||
1221 strcmp(*argv, "oif") == 0) {
1222 NEXT_ARG();
1223 d = *argv;
1224 } else if (matches(*argv, "pref") == 0) {
1225 __u8 pref;
1226
1227 NEXT_ARG();
1228 if (strcmp(*argv, "low") == 0)
1229 pref = ICMPV6_ROUTER_PREF_LOW;
1230 else if (strcmp(*argv, "medium") == 0)
1231 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1232 else if (strcmp(*argv, "high") == 0)
1233 pref = ICMPV6_ROUTER_PREF_HIGH;
1234 else if (get_u8(&pref, *argv, 0))
1235 invarg("\"pref\" value is invalid\n", *argv);
1236 addattr8(&req.n, sizeof(req), RTA_PREF, pref);
1237 } else if (strcmp(*argv, "encap") == 0) {
1238 char buf[1024];
1239 struct rtattr *rta = (void *)buf;
1240
1241 rta->rta_type = RTA_ENCAP;
1242 rta->rta_len = RTA_LENGTH(0);
1243
1244 lwt_parse_encap(rta, sizeof(buf), &argc, &argv);
1245
1246 if (rta->rta_len > RTA_LENGTH(0))
1247 addraw_l(&req.n, 1024
1248 , RTA_DATA(rta), RTA_PAYLOAD(rta));
1249 } else if (strcmp(*argv, "ttl-propagate") == 0) {
1250 __u8 ttl_prop;
1251
1252 NEXT_ARG();
1253 if (matches(*argv, "enabled") == 0)
1254 ttl_prop = 1;
1255 else if (matches(*argv, "disabled") == 0)
1256 ttl_prop = 0;
1257 else
1258 invarg("\"ttl-propagate\" value is invalid\n",
1259 *argv);
1260
1261 addattr8(&req.n, sizeof(req), RTA_TTL_PROPAGATE,
1262 ttl_prop);
1263 } else if (matches(*argv, "fastopen_no_cookie") == 0) {
1264 unsigned int fastopen_no_cookie;
1265
1266 NEXT_ARG();
1267 if (get_unsigned(&fastopen_no_cookie, *argv, 0))
1268 invarg("\"fastopen_no_cookie\" value is invalid\n", *argv);
1269 if (fastopen_no_cookie != 1 && fastopen_no_cookie != 0)
1270 invarg("\"fastopen_no_cookie\" value should be 0 or 1\n", *argv);
1271 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_FASTOPEN_NO_COOKIE, fastopen_no_cookie);
1272 } else {
1273 int type;
1274 inet_prefix dst;
1275
1276 if (strcmp(*argv, "to") == 0) {
1277 NEXT_ARG();
1278 }
1279 if ((**argv < '0' || **argv > '9') &&
1280 rtnl_rtntype_a2n(&type, *argv) == 0) {
1281 NEXT_ARG();
1282 req.r.rtm_type = type;
1283 type_ok = 1;
1284 }
1285
1286 if (matches(*argv, "help") == 0)
1287 usage();
1288 if (dst_ok)
1289 duparg2("to", *argv);
1290 get_prefix(&dst, *argv, req.r.rtm_family);
1291 if (req.r.rtm_family == AF_UNSPEC)
1292 req.r.rtm_family = dst.family;
1293 req.r.rtm_dst_len = dst.bitlen;
1294 dst_ok = 1;
1295 if (dst.bytelen)
1296 addattr_l(&req.n, sizeof(req),
1297 RTA_DST, &dst.data, dst.bytelen);
1298 }
1299 argc--; argv++;
1300 }
1301
1302 if (!dst_ok)
1303 usage();
1304
1305 if (d) {
1306 int idx;
1307
1308 if ((idx = ll_name_to_index(d)) == 0) {
1309 fprintf(stderr, "Cannot find device \"%s\"\n", d);
1310 return -1;
1311 }
1312 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1313 }
1314
1315 if (mxrta->rta_len > RTA_LENGTH(0)) {
1316 if (mxlock)
1317 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
1318 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
1319 }
1320
1321 if (nhs_ok)
1322 parse_nexthops(&req.n, &req.r, argc, argv);
1323
1324 if (req.r.rtm_family == AF_UNSPEC)
1325 req.r.rtm_family = AF_INET;
1326
1327 if (!table_ok) {
1328 if (req.r.rtm_type == RTN_LOCAL ||
1329 req.r.rtm_type == RTN_BROADCAST ||
1330 req.r.rtm_type == RTN_NAT ||
1331 req.r.rtm_type == RTN_ANYCAST)
1332 req.r.rtm_table = RT_TABLE_LOCAL;
1333 }
1334 if (!scope_ok) {
1335 if (req.r.rtm_family == AF_INET6 ||
1336 req.r.rtm_family == AF_MPLS)
1337 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1338 else if (req.r.rtm_type == RTN_LOCAL ||
1339 req.r.rtm_type == RTN_NAT)
1340 req.r.rtm_scope = RT_SCOPE_HOST;
1341 else if (req.r.rtm_type == RTN_BROADCAST ||
1342 req.r.rtm_type == RTN_MULTICAST ||
1343 req.r.rtm_type == RTN_ANYCAST)
1344 req.r.rtm_scope = RT_SCOPE_LINK;
1345 else if (req.r.rtm_type == RTN_UNICAST ||
1346 req.r.rtm_type == RTN_UNSPEC) {
1347 if (cmd == RTM_DELROUTE)
1348 req.r.rtm_scope = RT_SCOPE_NOWHERE;
1349 else if (!gw_ok && !nhs_ok)
1350 req.r.rtm_scope = RT_SCOPE_LINK;
1351 }
1352 }
1353
1354 if (!type_ok && req.r.rtm_family == AF_MPLS)
1355 req.r.rtm_type = RTN_UNICAST;
1356
1357 if (rtnl_talk(&rth, &req.n, NULL) < 0)
1358 return -2;
1359
1360 return 0;
1361 }
1362
1363 static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
1364 {
1365 struct {
1366 struct nlmsghdr nlh;
1367 struct rtmsg rtm;
1368 } req = {
1369 .nlh.nlmsg_len = sizeof(req),
1370 .nlh.nlmsg_type = RTM_GETROUTE,
1371 .nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST,
1372 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
1373 .rtm.rtm_family = family,
1374 .rtm.rtm_flags = RTM_F_CLONED,
1375 };
1376 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
1377
1378 return sendto(rth->fd, (void *)&req, sizeof(req), 0, (struct sockaddr *)&nladdr, sizeof(nladdr));
1379 }
1380
1381 static int iproute_flush_cache(void)
1382 {
1383 #define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
1384
1385 int len;
1386 int flush_fd = open(ROUTE_FLUSH_PATH, O_WRONLY);
1387 char *buffer = "-1";
1388
1389 if (flush_fd < 0) {
1390 fprintf(stderr, "Cannot open \"%s\": %s\n",
1391 ROUTE_FLUSH_PATH, strerror(errno));
1392 return -1;
1393 }
1394
1395 len = strlen(buffer);
1396
1397 if ((write(flush_fd, (void *)buffer, len)) < len) {
1398 fprintf(stderr, "Cannot flush routing cache\n");
1399 close(flush_fd);
1400 return -1;
1401 }
1402 close(flush_fd);
1403 return 0;
1404 }
1405
1406 static __u32 route_dump_magic = 0x45311224;
1407
1408 static int save_route(const struct sockaddr_nl *who, struct nlmsghdr *n,
1409 void *arg)
1410 {
1411 int ret;
1412 int len = n->nlmsg_len;
1413 struct rtmsg *r = NLMSG_DATA(n);
1414 struct rtattr *tb[RTA_MAX+1];
1415 int host_len;
1416
1417 host_len = af_bit_len(r->rtm_family);
1418 len -= NLMSG_LENGTH(sizeof(*r));
1419 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1420
1421 if (!filter_nlmsg(n, tb, host_len))
1422 return 0;
1423
1424 ret = write(STDOUT_FILENO, n, n->nlmsg_len);
1425 if ((ret > 0) && (ret != n->nlmsg_len)) {
1426 fprintf(stderr, "Short write while saving nlmsg\n");
1427 ret = -EIO;
1428 }
1429
1430 return ret == n->nlmsg_len ? 0 : ret;
1431 }
1432
1433 static int save_route_prep(void)
1434 {
1435 int ret;
1436
1437 if (isatty(STDOUT_FILENO)) {
1438 fprintf(stderr, "Not sending a binary stream to stdout\n");
1439 return -1;
1440 }
1441
1442 ret = write(STDOUT_FILENO, &route_dump_magic, sizeof(route_dump_magic));
1443 if (ret != sizeof(route_dump_magic)) {
1444 fprintf(stderr, "Can't write magic to dump file\n");
1445 return -1;
1446 }
1447
1448 return 0;
1449 }
1450
1451 static int iproute_list_flush_or_save(int argc, char **argv, int action)
1452 {
1453 int do_ipv6 = preferred_family;
1454 char *id = NULL;
1455 char *od = NULL;
1456 unsigned int mark = 0;
1457 rtnl_filter_t filter_fn;
1458 int ret;
1459
1460 if (action == IPROUTE_SAVE) {
1461 if (save_route_prep())
1462 return -1;
1463
1464 filter_fn = save_route;
1465 } else
1466 filter_fn = print_route;
1467
1468 iproute_reset_filter(0);
1469 filter.tb = RT_TABLE_MAIN;
1470
1471 if ((action == IPROUTE_FLUSH) && argc <= 0) {
1472 fprintf(stderr, "\"ip route flush\" requires arguments.\n");
1473 return -1;
1474 }
1475
1476 while (argc > 0) {
1477 if (matches(*argv, "table") == 0) {
1478 __u32 tid;
1479
1480 NEXT_ARG();
1481 if (rtnl_rttable_a2n(&tid, *argv)) {
1482 if (strcmp(*argv, "all") == 0) {
1483 filter.tb = 0;
1484 } else if (strcmp(*argv, "cache") == 0) {
1485 filter.cloned = 1;
1486 } else if (strcmp(*argv, "help") == 0) {
1487 usage();
1488 } else {
1489 invarg("table id value is invalid\n", *argv);
1490 }
1491 } else
1492 filter.tb = tid;
1493 } else if (matches(*argv, "vrf") == 0) {
1494 __u32 tid;
1495
1496 NEXT_ARG();
1497 tid = ipvrf_get_table(*argv);
1498 if (tid == 0)
1499 invarg("Invalid VRF\n", *argv);
1500 filter.tb = tid;
1501 filter.typemask = ~(1 << RTN_LOCAL | 1<<RTN_BROADCAST);
1502 } else if (matches(*argv, "cached") == 0 ||
1503 matches(*argv, "cloned") == 0) {
1504 filter.cloned = 1;
1505 } else if (strcmp(*argv, "tos") == 0 ||
1506 matches(*argv, "dsfield") == 0) {
1507 __u32 tos;
1508
1509 NEXT_ARG();
1510 if (rtnl_dsfield_a2n(&tos, *argv))
1511 invarg("TOS value is invalid\n", *argv);
1512 filter.tos = tos;
1513 filter.tosmask = -1;
1514 } else if (matches(*argv, "protocol") == 0) {
1515 __u32 prot = 0;
1516
1517 NEXT_ARG();
1518 filter.protocolmask = -1;
1519 if (rtnl_rtprot_a2n(&prot, *argv)) {
1520 if (strcmp(*argv, "all") != 0)
1521 invarg("invalid \"protocol\"\n", *argv);
1522 prot = 0;
1523 filter.protocolmask = 0;
1524 }
1525 filter.protocol = prot;
1526 } else if (matches(*argv, "scope") == 0) {
1527 __u32 scope = 0;
1528
1529 NEXT_ARG();
1530 filter.scopemask = -1;
1531 if (rtnl_rtscope_a2n(&scope, *argv)) {
1532 if (strcmp(*argv, "all") != 0)
1533 invarg("invalid \"scope\"\n", *argv);
1534 scope = RT_SCOPE_NOWHERE;
1535 filter.scopemask = 0;
1536 }
1537 filter.scope = scope;
1538 } else if (matches(*argv, "type") == 0) {
1539 int type;
1540
1541 NEXT_ARG();
1542 if (rtnl_rtntype_a2n(&type, *argv))
1543 invarg("node type value is invalid\n", *argv);
1544 filter.typemask = (1<<type);
1545 } else if (strcmp(*argv, "dev") == 0 ||
1546 strcmp(*argv, "oif") == 0) {
1547 NEXT_ARG();
1548 od = *argv;
1549 } else if (strcmp(*argv, "iif") == 0) {
1550 NEXT_ARG();
1551 id = *argv;
1552 } else if (strcmp(*argv, "mark") == 0) {
1553 NEXT_ARG();
1554 if (get_unsigned(&mark, *argv, 0))
1555 invarg("invalid mark value", *argv);
1556 filter.markmask = -1;
1557 } else if (matches(*argv, "metric") == 0 ||
1558 matches(*argv, "priority") == 0 ||
1559 strcmp(*argv, "preference") == 0) {
1560 __u32 metric;
1561
1562 NEXT_ARG();
1563 if (get_u32(&metric, *argv, 0))
1564 invarg("\"metric\" value is invalid\n", *argv);
1565 filter.metric = metric;
1566 filter.metricmask = -1;
1567 } else if (strcmp(*argv, "via") == 0) {
1568 int family;
1569
1570 NEXT_ARG();
1571 family = read_family(*argv);
1572 if (family == AF_UNSPEC)
1573 family = do_ipv6;
1574 else
1575 NEXT_ARG();
1576 get_prefix(&filter.rvia, *argv, family);
1577 } else if (strcmp(*argv, "src") == 0) {
1578 NEXT_ARG();
1579 get_prefix(&filter.rprefsrc, *argv, do_ipv6);
1580 } else if (matches(*argv, "realms") == 0) {
1581 __u32 realm;
1582
1583 NEXT_ARG();
1584 if (get_rt_realms_or_raw(&realm, *argv))
1585 invarg("invalid realms\n", *argv);
1586 filter.realm = realm;
1587 filter.realmmask = ~0U;
1588 if ((filter.realm&0xFFFF) == 0 &&
1589 (*argv)[strlen(*argv) - 1] == '/')
1590 filter.realmmask &= ~0xFFFF;
1591 if ((filter.realm&0xFFFF0000U) == 0 &&
1592 (strchr(*argv, '/') == NULL ||
1593 (*argv)[0] == '/'))
1594 filter.realmmask &= ~0xFFFF0000U;
1595 } else if (matches(*argv, "from") == 0) {
1596 NEXT_ARG();
1597 if (matches(*argv, "root") == 0) {
1598 NEXT_ARG();
1599 get_prefix(&filter.rsrc, *argv, do_ipv6);
1600 } else if (matches(*argv, "match") == 0) {
1601 NEXT_ARG();
1602 get_prefix(&filter.msrc, *argv, do_ipv6);
1603 } else {
1604 if (matches(*argv, "exact") == 0) {
1605 NEXT_ARG();
1606 }
1607 get_prefix(&filter.msrc, *argv, do_ipv6);
1608 filter.rsrc = filter.msrc;
1609 }
1610 } else {
1611 if (matches(*argv, "to") == 0) {
1612 NEXT_ARG();
1613 }
1614 if (matches(*argv, "root") == 0) {
1615 NEXT_ARG();
1616 get_prefix(&filter.rdst, *argv, do_ipv6);
1617 } else if (matches(*argv, "match") == 0) {
1618 NEXT_ARG();
1619 get_prefix(&filter.mdst, *argv, do_ipv6);
1620 } else {
1621 if (matches(*argv, "exact") == 0) {
1622 NEXT_ARG();
1623 }
1624 get_prefix(&filter.mdst, *argv, do_ipv6);
1625 filter.rdst = filter.mdst;
1626 }
1627 }
1628 argc--; argv++;
1629 }
1630
1631 if (do_ipv6 == AF_UNSPEC && filter.tb)
1632 do_ipv6 = AF_INET;
1633
1634 if (id || od) {
1635 int idx;
1636
1637 if (id) {
1638 if ((idx = ll_name_to_index(id)) == 0) {
1639 fprintf(stderr, "Cannot find device \"%s\"\n", id);
1640 return -1;
1641 }
1642 filter.iif = idx;
1643 filter.iifmask = -1;
1644 }
1645 if (od) {
1646 if ((idx = ll_name_to_index(od)) == 0) {
1647 fprintf(stderr, "Cannot find device \"%s\"\n", od);
1648 return -1;
1649 }
1650 filter.oif = idx;
1651 filter.oifmask = -1;
1652 }
1653 }
1654 filter.mark = mark;
1655
1656 if (action == IPROUTE_FLUSH) {
1657 int round = 0;
1658 char flushb[4096-512];
1659 time_t start = time(0);
1660
1661 if (filter.cloned) {
1662 if (do_ipv6 != AF_INET6) {
1663 iproute_flush_cache();
1664 if (show_stats)
1665 printf("*** IPv4 routing cache is flushed.\n");
1666 }
1667 if (do_ipv6 == AF_INET)
1668 return 0;
1669 }
1670
1671 filter.flushb = flushb;
1672 filter.flushp = 0;
1673 filter.flushe = sizeof(flushb);
1674
1675 for (;;) {
1676 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
1677 perror("Cannot send dump request");
1678 return -2;
1679 }
1680 filter.flushed = 0;
1681 if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
1682 fprintf(stderr, "Flush terminated\n");
1683 return -2;
1684 }
1685 if (filter.flushed == 0) {
1686 if (show_stats) {
1687 if (round == 0 && (!filter.cloned || do_ipv6 == AF_INET6))
1688 printf("Nothing to flush.\n");
1689 else
1690 printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":"");
1691 }
1692 fflush(stdout);
1693 return 0;
1694 }
1695 round++;
1696 if ((ret = flush_update()) < 0)
1697 return ret;
1698
1699 if (time(0) - start > 30) {
1700 printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
1701 (long)(time(0) - start), filter.flushed);
1702 return -1;
1703 }
1704
1705 if (show_stats) {
1706 printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
1707 fflush(stdout);
1708 }
1709 }
1710 }
1711
1712 if (!filter.cloned) {
1713 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
1714 perror("Cannot send dump request");
1715 return -2;
1716 }
1717 } else {
1718 if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
1719 perror("Cannot send dump request");
1720 return -2;
1721 }
1722 }
1723
1724 if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
1725 fprintf(stderr, "Dump terminated\n");
1726 return -2;
1727 }
1728
1729 return 0;
1730 }
1731
1732
1733 static int iproute_get(int argc, char **argv)
1734 {
1735 struct {
1736 struct nlmsghdr n;
1737 struct rtmsg r;
1738 char buf[1024];
1739 } req = {
1740 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
1741 .n.nlmsg_flags = NLM_F_REQUEST,
1742 .n.nlmsg_type = RTM_GETROUTE,
1743 .r.rtm_family = preferred_family,
1744 };
1745 char *idev = NULL;
1746 char *odev = NULL;
1747 struct nlmsghdr *answer;
1748 int connected = 0;
1749 int fib_match = 0;
1750 int from_ok = 0;
1751 unsigned int mark = 0;
1752
1753 iproute_reset_filter(0);
1754 filter.cloned = 2;
1755
1756 while (argc > 0) {
1757 if (strcmp(*argv, "tos") == 0 ||
1758 matches(*argv, "dsfield") == 0) {
1759 __u32 tos;
1760
1761 NEXT_ARG();
1762 if (rtnl_dsfield_a2n(&tos, *argv))
1763 invarg("TOS value is invalid\n", *argv);
1764 req.r.rtm_tos = tos;
1765 } else if (matches(*argv, "from") == 0) {
1766 inet_prefix addr;
1767
1768 NEXT_ARG();
1769 if (matches(*argv, "help") == 0)
1770 usage();
1771 from_ok = 1;
1772 get_prefix(&addr, *argv, req.r.rtm_family);
1773 if (req.r.rtm_family == AF_UNSPEC)
1774 req.r.rtm_family = addr.family;
1775 if (addr.bytelen)
1776 addattr_l(&req.n, sizeof(req), RTA_SRC,
1777 &addr.data, addr.bytelen);
1778 req.r.rtm_src_len = addr.bitlen;
1779 } else if (matches(*argv, "iif") == 0) {
1780 NEXT_ARG();
1781 idev = *argv;
1782 } else if (matches(*argv, "mark") == 0) {
1783 NEXT_ARG();
1784 if (get_unsigned(&mark, *argv, 0))
1785 invarg("invalid mark value", *argv);
1786 } else if (matches(*argv, "oif") == 0 ||
1787 strcmp(*argv, "dev") == 0) {
1788 NEXT_ARG();
1789 odev = *argv;
1790 } else if (matches(*argv, "notify") == 0) {
1791 req.r.rtm_flags |= RTM_F_NOTIFY;
1792 } else if (matches(*argv, "connected") == 0) {
1793 connected = 1;
1794 } else if (matches(*argv, "vrf") == 0) {
1795 NEXT_ARG();
1796 if (!name_is_vrf(*argv))
1797 invarg("Invalid VRF\n", *argv);
1798 odev = *argv;
1799 } else if (matches(*argv, "uid") == 0) {
1800 uid_t uid;
1801
1802 NEXT_ARG();
1803 if (get_unsigned(&uid, *argv, 0))
1804 invarg("invalid UID\n", *argv);
1805 addattr32(&req.n, sizeof(req), RTA_UID, uid);
1806 } else if (matches(*argv, "fibmatch") == 0) {
1807 fib_match = 1;
1808 } else if (strcmp(*argv, "as") == 0) {
1809 inet_prefix addr;
1810
1811 NEXT_ARG();
1812 if (strcmp(*argv, "to") == 0)
1813 NEXT_ARG();
1814 get_addr(&addr, *argv, req.r.rtm_family);
1815 if (req.r.rtm_family == AF_UNSPEC)
1816 req.r.rtm_family = addr.family;
1817 addattr_l(&req.n, sizeof(req), RTA_NEWDST,
1818 &addr.data, addr.bytelen);
1819 } else {
1820 inet_prefix addr;
1821
1822 if (strcmp(*argv, "to") == 0) {
1823 NEXT_ARG();
1824 }
1825 if (matches(*argv, "help") == 0)
1826 usage();
1827 get_prefix(&addr, *argv, req.r.rtm_family);
1828 if (req.r.rtm_family == AF_UNSPEC)
1829 req.r.rtm_family = addr.family;
1830 if (addr.bytelen)
1831 addattr_l(&req.n, sizeof(req),
1832 RTA_DST, &addr.data, addr.bytelen);
1833 req.r.rtm_dst_len = addr.bitlen;
1834 }
1835 argc--; argv++;
1836 }
1837
1838 if (req.r.rtm_dst_len == 0) {
1839 fprintf(stderr, "need at least a destination address\n");
1840 return -1;
1841 }
1842
1843 if (idev || odev) {
1844 int idx;
1845
1846 if (idev) {
1847 if ((idx = ll_name_to_index(idev)) == 0) {
1848 fprintf(stderr, "Cannot find device \"%s\"\n", idev);
1849 return -1;
1850 }
1851 addattr32(&req.n, sizeof(req), RTA_IIF, idx);
1852 }
1853 if (odev) {
1854 if ((idx = ll_name_to_index(odev)) == 0) {
1855 fprintf(stderr, "Cannot find device \"%s\"\n", odev);
1856 return -1;
1857 }
1858 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1859 }
1860 }
1861 if (mark)
1862 addattr32(&req.n, sizeof(req), RTA_MARK, mark);
1863
1864 if (req.r.rtm_family == AF_UNSPEC)
1865 req.r.rtm_family = AF_INET;
1866
1867 req.r.rtm_flags |= RTM_F_LOOKUP_TABLE;
1868 if (fib_match)
1869 req.r.rtm_flags |= RTM_F_FIB_MATCH;
1870
1871 if (rtnl_talk(&rth, &req.n, &answer) < 0)
1872 return -2;
1873
1874 if (connected && !from_ok) {
1875 struct rtmsg *r = NLMSG_DATA(answer);
1876 int len = answer->nlmsg_len;
1877 struct rtattr *tb[RTA_MAX+1];
1878
1879 if (print_route(NULL, answer, (void *)stdout) < 0) {
1880 fprintf(stderr, "An error :-)\n");
1881 free(answer);
1882 return -1;
1883 }
1884
1885 if (answer->nlmsg_type != RTM_NEWROUTE) {
1886 fprintf(stderr, "Not a route?\n");
1887 free(answer);
1888 return -1;
1889 }
1890 len -= NLMSG_LENGTH(sizeof(*r));
1891 if (len < 0) {
1892 fprintf(stderr, "Wrong len %d\n", len);
1893 free(answer);
1894 return -1;
1895 }
1896
1897 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1898
1899 if (tb[RTA_PREFSRC]) {
1900 tb[RTA_PREFSRC]->rta_type = RTA_SRC;
1901 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
1902 } else if (!tb[RTA_SRC]) {
1903 fprintf(stderr, "Failed to connect the route\n");
1904 free(answer);
1905 return -1;
1906 }
1907 if (!odev && tb[RTA_OIF])
1908 tb[RTA_OIF]->rta_type = 0;
1909 if (tb[RTA_GATEWAY])
1910 tb[RTA_GATEWAY]->rta_type = 0;
1911 if (tb[RTA_VIA])
1912 tb[RTA_VIA]->rta_type = 0;
1913 if (!idev && tb[RTA_IIF])
1914 tb[RTA_IIF]->rta_type = 0;
1915 req.n.nlmsg_flags = NLM_F_REQUEST;
1916 req.n.nlmsg_type = RTM_GETROUTE;
1917
1918 free(answer);
1919 if (rtnl_talk(&rth, &req.n, &answer) < 0)
1920 return -2;
1921 }
1922
1923 if (print_route(NULL, answer, (void *)stdout) < 0) {
1924 fprintf(stderr, "An error :-)\n");
1925 free(answer);
1926 return -1;
1927 }
1928
1929 free(answer);
1930 return 0;
1931 }
1932
1933 static int rtattr_cmp(const struct rtattr *rta1, const struct rtattr *rta2)
1934 {
1935 if (!rta1 || !rta2 || rta1->rta_len != rta2->rta_len)
1936 return 1;
1937
1938 return memcmp(RTA_DATA(rta1), RTA_DATA(rta2), RTA_PAYLOAD(rta1));
1939 }
1940
1941 static int restore_handler(const struct sockaddr_nl *nl,
1942 struct rtnl_ctrl_data *ctrl,
1943 struct nlmsghdr *n, void *arg)
1944 {
1945 struct rtmsg *r = NLMSG_DATA(n);
1946 struct rtattr *tb[RTA_MAX+1];
1947 int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
1948 int ret, prio = *(int *)arg;
1949
1950 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1951
1952 /* Restore routes in correct order:
1953 * 0. ones for local addresses,
1954 * 1. ones for local networks,
1955 * 2. others (remote networks/hosts).
1956 */
1957 if (!prio && !tb[RTA_GATEWAY] && (!tb[RTA_PREFSRC] ||
1958 !rtattr_cmp(tb[RTA_PREFSRC], tb[RTA_DST])))
1959 goto restore;
1960 else if (prio == 1 && !tb[RTA_GATEWAY] && tb[RTA_PREFSRC] &&
1961 rtattr_cmp(tb[RTA_PREFSRC], tb[RTA_DST]))
1962 goto restore;
1963 else if (prio == 2 && tb[RTA_GATEWAY])
1964 goto restore;
1965
1966 return 0;
1967
1968 restore:
1969 n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
1970
1971 ll_init_map(&rth);
1972
1973 ret = rtnl_talk(&rth, n, NULL);
1974 if ((ret < 0) && (errno == EEXIST))
1975 ret = 0;
1976
1977 return ret;
1978 }
1979
1980 static int route_dump_check_magic(void)
1981 {
1982 int ret;
1983 __u32 magic = 0;
1984
1985 if (isatty(STDIN_FILENO)) {
1986 fprintf(stderr, "Can't restore route dump from a terminal\n");
1987 return -1;
1988 }
1989
1990 ret = fread(&magic, sizeof(magic), 1, stdin);
1991 if (magic != route_dump_magic) {
1992 fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n", ret, magic);
1993 return -1;
1994 }
1995
1996 return 0;
1997 }
1998
1999 static int iproute_restore(void)
2000 {
2001 int pos, prio;
2002
2003 if (route_dump_check_magic())
2004 return -1;
2005
2006 pos = ftell(stdin);
2007 if (pos == -1) {
2008 perror("Failed to restore: ftell");
2009 return -1;
2010 }
2011
2012 for (prio = 0; prio < 3; prio++) {
2013 int err;
2014
2015 err = rtnl_from_file(stdin, &restore_handler, &prio);
2016 if (err)
2017 return -2;
2018
2019 if (fseek(stdin, pos, SEEK_SET) == -1) {
2020 perror("Failed to restore: fseek");
2021 return -1;
2022 }
2023 }
2024
2025 return 0;
2026 }
2027
2028 static int show_handler(const struct sockaddr_nl *nl,
2029 struct rtnl_ctrl_data *ctrl,
2030 struct nlmsghdr *n, void *arg)
2031 {
2032 print_route(nl, n, stdout);
2033 return 0;
2034 }
2035
2036 static int iproute_showdump(void)
2037 {
2038 if (route_dump_check_magic())
2039 return -1;
2040
2041 if (rtnl_from_file(stdin, &show_handler, NULL))
2042 return -2;
2043
2044 return 0;
2045 }
2046
2047 void iproute_reset_filter(int ifindex)
2048 {
2049 memset(&filter, 0, sizeof(filter));
2050 filter.mdst.bitlen = -1;
2051 filter.msrc.bitlen = -1;
2052 filter.oif = ifindex;
2053 if (filter.oif > 0)
2054 filter.oifmask = -1;
2055 }
2056
2057 int do_iproute(int argc, char **argv)
2058 {
2059 if (argc < 1)
2060 return iproute_list_flush_or_save(0, NULL, IPROUTE_LIST);
2061
2062 if (matches(*argv, "add") == 0)
2063 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL,
2064 argc-1, argv+1);
2065 if (matches(*argv, "change") == 0 || strcmp(*argv, "chg") == 0)
2066 return iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE,
2067 argc-1, argv+1);
2068 if (matches(*argv, "replace") == 0)
2069 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE,
2070 argc-1, argv+1);
2071 if (matches(*argv, "prepend") == 0)
2072 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE,
2073 argc-1, argv+1);
2074 if (matches(*argv, "append") == 0)
2075 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_APPEND,
2076 argc-1, argv+1);
2077 if (matches(*argv, "test") == 0)
2078 return iproute_modify(RTM_NEWROUTE, NLM_F_EXCL,
2079 argc-1, argv+1);
2080 if (matches(*argv, "delete") == 0)
2081 return iproute_modify(RTM_DELROUTE, 0,
2082 argc-1, argv+1);
2083 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
2084 || matches(*argv, "lst") == 0)
2085 return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_LIST);
2086 if (matches(*argv, "get") == 0)
2087 return iproute_get(argc-1, argv+1);
2088 if (matches(*argv, "flush") == 0)
2089 return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_FLUSH);
2090 if (matches(*argv, "save") == 0)
2091 return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_SAVE);
2092 if (matches(*argv, "restore") == 0)
2093 return iproute_restore();
2094 if (matches(*argv, "showdump") == 0)
2095 return iproute_showdump();
2096 if (matches(*argv, "help") == 0)
2097 usage();
2098 fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
2099 exit(-1);
2100 }