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