]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iproute_lwtunnel.c
Merge branch 'iproute2-master' into iproute2-next
[mirror_iproute2.git] / ip / iproute_lwtunnel.c
1 /*
2 * iproute_lwtunnel.c
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: Roopa Prabhu, <roopa@cumulusnetworks.com>
10 * Thomas Graf <tgraf@suug.ch>
11 *
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #ifdef HAVE_LIBBSD
20 #include <bsd/string.h>
21 #endif
22 #include <linux/ila.h>
23 #include <linux/lwtunnel.h>
24 #include <linux/mpls_iptunnel.h>
25 #include <errno.h>
26
27 #include "rt_names.h"
28 #include "bpf_util.h"
29 #include "utils.h"
30 #include "ip_common.h"
31 #include "ila_common.h"
32
33 #include <linux/seg6.h>
34 #include <linux/seg6_iptunnel.h>
35 #include <linux/seg6_hmac.h>
36 #include <linux/seg6_local.h>
37 #include <net/if.h>
38
39 static const char *format_encap_type(int type)
40 {
41 switch (type) {
42 case LWTUNNEL_ENCAP_MPLS:
43 return "mpls";
44 case LWTUNNEL_ENCAP_IP:
45 return "ip";
46 case LWTUNNEL_ENCAP_IP6:
47 return "ip6";
48 case LWTUNNEL_ENCAP_ILA:
49 return "ila";
50 case LWTUNNEL_ENCAP_BPF:
51 return "bpf";
52 case LWTUNNEL_ENCAP_SEG6:
53 return "seg6";
54 case LWTUNNEL_ENCAP_SEG6_LOCAL:
55 return "seg6local";
56 default:
57 return "unknown";
58 }
59 }
60
61 static void encap_type_usage(void)
62 {
63 int i;
64
65 fprintf(stderr, "Usage: ip route ... encap TYPE [ OPTIONS ] [...]\n");
66
67 for (i = 1; i <= LWTUNNEL_ENCAP_MAX; i++)
68 fprintf(stderr, "%s %s\n", format_encap_type(i),
69 i == 1 ? "TYPE := " : " ");
70
71 exit(-1);
72 }
73
74 static int read_encap_type(const char *name)
75 {
76 if (strcmp(name, "mpls") == 0)
77 return LWTUNNEL_ENCAP_MPLS;
78 else if (strcmp(name, "ip") == 0)
79 return LWTUNNEL_ENCAP_IP;
80 else if (strcmp(name, "ip6") == 0)
81 return LWTUNNEL_ENCAP_IP6;
82 else if (strcmp(name, "ila") == 0)
83 return LWTUNNEL_ENCAP_ILA;
84 else if (strcmp(name, "bpf") == 0)
85 return LWTUNNEL_ENCAP_BPF;
86 else if (strcmp(name, "seg6") == 0)
87 return LWTUNNEL_ENCAP_SEG6;
88 else if (strcmp(name, "seg6local") == 0)
89 return LWTUNNEL_ENCAP_SEG6_LOCAL;
90 else if (strcmp(name, "help") == 0)
91 encap_type_usage();
92
93 return LWTUNNEL_ENCAP_NONE;
94 }
95
96 static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh)
97 {
98 int i;
99
100 if (is_json_context())
101 open_json_array(PRINT_JSON, "segs");
102 else
103 fprintf(fp, "segs %d [ ", srh->first_segment + 1);
104
105 for (i = srh->first_segment; i >= 0; i--)
106 print_color_string(PRINT_ANY, COLOR_INET6,
107 NULL, "%s ",
108 rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
109
110 if (is_json_context())
111 close_json_array(PRINT_JSON, NULL);
112 else
113 fprintf(fp, "] ");
114
115 if (sr_has_hmac(srh)) {
116 unsigned int offset = ((srh->hdrlen + 1) << 3) - 40;
117 struct sr6_tlv_hmac *tlv;
118
119 tlv = (struct sr6_tlv_hmac *)((char *)srh + offset);
120 print_0xhex(PRINT_ANY, "hmac",
121 "hmac 0x%X ", ntohl(tlv->hmackeyid));
122 }
123 }
124
125 static const char *seg6_mode_types[] = {
126 [SEG6_IPTUN_MODE_INLINE] = "inline",
127 [SEG6_IPTUN_MODE_ENCAP] = "encap",
128 [SEG6_IPTUN_MODE_L2ENCAP] = "l2encap",
129 };
130
131 static const char *format_seg6mode_type(int mode)
132 {
133 if (mode < 0 || mode > ARRAY_SIZE(seg6_mode_types))
134 return "<unknown>";
135
136 return seg6_mode_types[mode];
137 }
138
139 static int read_seg6mode_type(const char *mode)
140 {
141 int i;
142
143 for (i = 0; i < ARRAY_SIZE(seg6_mode_types); i++) {
144 if (strcmp(mode, seg6_mode_types[i]) == 0)
145 return i;
146 }
147
148 return -1;
149 }
150
151 static void print_encap_seg6(FILE *fp, struct rtattr *encap)
152 {
153 struct rtattr *tb[SEG6_IPTUNNEL_MAX+1];
154 struct seg6_iptunnel_encap *tuninfo;
155
156 parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap);
157
158 if (!tb[SEG6_IPTUNNEL_SRH])
159 return;
160
161 tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]);
162 print_string(PRINT_ANY, "mode",
163 "mode %s ", format_seg6mode_type(tuninfo->mode));
164
165 print_srh(fp, tuninfo->srh);
166 }
167
168 static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = {
169 [SEG6_LOCAL_ACTION_END] = "End",
170 [SEG6_LOCAL_ACTION_END_X] = "End.X",
171 [SEG6_LOCAL_ACTION_END_T] = "End.T",
172 [SEG6_LOCAL_ACTION_END_DX2] = "End.DX2",
173 [SEG6_LOCAL_ACTION_END_DX6] = "End.DX6",
174 [SEG6_LOCAL_ACTION_END_DX4] = "End.DX4",
175 [SEG6_LOCAL_ACTION_END_DT6] = "End.DT6",
176 [SEG6_LOCAL_ACTION_END_DT4] = "End.DT4",
177 [SEG6_LOCAL_ACTION_END_B6] = "End.B6",
178 [SEG6_LOCAL_ACTION_END_B6_ENCAP] = "End.B6.Encaps",
179 [SEG6_LOCAL_ACTION_END_BM] = "End.BM",
180 [SEG6_LOCAL_ACTION_END_S] = "End.S",
181 [SEG6_LOCAL_ACTION_END_AS] = "End.AS",
182 [SEG6_LOCAL_ACTION_END_AM] = "End.AM",
183 [SEG6_LOCAL_ACTION_END_BPF] = "End.BPF",
184 };
185
186 static const char *format_action_type(int action)
187 {
188 if (action < 0 || action > SEG6_LOCAL_ACTION_MAX)
189 return "<invalid>";
190
191 return seg6_action_names[action] ?: "<unknown>";
192 }
193
194 static int read_action_type(const char *name)
195 {
196 int i;
197
198 for (i = 0; i < SEG6_LOCAL_ACTION_MAX + 1; i++) {
199 if (!seg6_action_names[i])
200 continue;
201
202 if (strcmp(seg6_action_names[i], name) == 0)
203 return i;
204 }
205
206 return SEG6_LOCAL_ACTION_UNSPEC;
207 }
208
209 static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
210 const char *str)
211 {
212 struct rtattr *tb[LWT_BPF_PROG_MAX+1];
213 const char *progname = NULL;
214
215 parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
216
217 if (tb[LWT_BPF_PROG_NAME])
218 progname = rta_getattr_str(tb[LWT_BPF_PROG_NAME]);
219
220 if (is_json_context())
221 print_string(PRINT_JSON, str, NULL,
222 progname ? : "<unknown>");
223 else {
224 fprintf(fp, "%s ", str);
225 if (progname)
226 fprintf(fp, "%s ", progname);
227 }
228 }
229
230 static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
231 {
232 struct rtattr *tb[SEG6_LOCAL_MAX + 1];
233 int action;
234
235 parse_rtattr_nested(tb, SEG6_LOCAL_MAX, encap);
236
237 if (!tb[SEG6_LOCAL_ACTION])
238 return;
239
240 action = rta_getattr_u32(tb[SEG6_LOCAL_ACTION]);
241
242 print_string(PRINT_ANY, "action",
243 "action %s ", format_action_type(action));
244
245 if (tb[SEG6_LOCAL_SRH]) {
246 open_json_object("srh");
247 print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH]));
248 close_json_object();
249 }
250
251 if (tb[SEG6_LOCAL_TABLE])
252 print_uint(PRINT_ANY, "table",
253 "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
254
255 if (tb[SEG6_LOCAL_NH4]) {
256 print_string(PRINT_ANY, "nh4",
257 "nh4 %s ", rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4]));
258 }
259
260 if (tb[SEG6_LOCAL_NH6]) {
261 print_string(PRINT_ANY, "nh6",
262 "nh6 %s ", rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6]));
263 }
264
265 if (tb[SEG6_LOCAL_IIF]) {
266 int iif = rta_getattr_u32(tb[SEG6_LOCAL_IIF]);
267
268 print_string(PRINT_ANY, "iif",
269 "iif %s ", ll_index_to_name(iif));
270 }
271
272 if (tb[SEG6_LOCAL_OIF]) {
273 int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]);
274
275 print_string(PRINT_ANY, "oif",
276 "oif %s ", ll_index_to_name(oif));
277 }
278
279 if (tb[SEG6_LOCAL_BPF])
280 print_encap_bpf_prog(fp, tb[SEG6_LOCAL_BPF], "endpoint");
281 }
282
283 static void print_encap_mpls(FILE *fp, struct rtattr *encap)
284 {
285 struct rtattr *tb[MPLS_IPTUNNEL_MAX+1];
286
287 parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
288
289 if (tb[MPLS_IPTUNNEL_DST])
290 print_string(PRINT_ANY, "dst", " %s ",
291 format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST]));
292 if (tb[MPLS_IPTUNNEL_TTL])
293 print_uint(PRINT_ANY, "ttl", "ttl %u ",
294 rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
295 }
296
297 static void print_encap_ip(FILE *fp, struct rtattr *encap)
298 {
299 struct rtattr *tb[LWTUNNEL_IP_MAX+1];
300
301 parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
302
303 if (tb[LWTUNNEL_IP_ID])
304 print_u64(PRINT_ANY, "id", "id %llu ",
305 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
306
307 if (tb[LWTUNNEL_IP_SRC])
308 print_color_string(PRINT_ANY, COLOR_INET,
309 "src", "src %s ",
310 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
311
312 if (tb[LWTUNNEL_IP_DST])
313 print_color_string(PRINT_ANY, COLOR_INET,
314 "dst", "dst %s ",
315 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
316
317 if (tb[LWTUNNEL_IP_TTL])
318 print_uint(PRINT_ANY, "ttl",
319 "ttl %u ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
320
321 if (tb[LWTUNNEL_IP_TOS])
322 print_uint(PRINT_ANY, "tos",
323 "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
324 }
325
326 static void print_encap_ila(FILE *fp, struct rtattr *encap)
327 {
328 struct rtattr *tb[ILA_ATTR_MAX+1];
329
330 parse_rtattr_nested(tb, ILA_ATTR_MAX, encap);
331
332 if (tb[ILA_ATTR_LOCATOR]) {
333 char abuf[ADDR64_BUF_SIZE];
334
335 addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
336 abuf, sizeof(abuf));
337 print_string(PRINT_ANY, "locator",
338 " %s ", abuf);
339 }
340
341 if (tb[ILA_ATTR_CSUM_MODE])
342 print_string(PRINT_ANY, "csum_mode",
343 " csum-mode %s ",
344 ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE])));
345
346 if (tb[ILA_ATTR_IDENT_TYPE])
347 print_string(PRINT_ANY, "ident_type",
348 " ident-type %s ",
349 ila_ident_type2name(rta_getattr_u8(tb[ILA_ATTR_IDENT_TYPE])));
350
351 if (tb[ILA_ATTR_HOOK_TYPE])
352 print_string(PRINT_ANY, "hook_type",
353 " hook-type %s ",
354 ila_hook_type2name(rta_getattr_u8(tb[ILA_ATTR_HOOK_TYPE])));
355 }
356
357 static void print_encap_ip6(FILE *fp, struct rtattr *encap)
358 {
359 struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
360
361 parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
362
363 if (tb[LWTUNNEL_IP6_ID])
364 print_u64(PRINT_ANY, "id", "id %llu ",
365 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
366
367 if (tb[LWTUNNEL_IP6_SRC])
368 print_color_string(PRINT_ANY, COLOR_INET6,
369 "src", "src %s ",
370 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
371
372 if (tb[LWTUNNEL_IP6_DST])
373 print_color_string(PRINT_ANY, COLOR_INET6,
374 "dst", "dst %s ",
375 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
376
377 if (tb[LWTUNNEL_IP6_HOPLIMIT])
378 print_u64(PRINT_ANY, "hoplimit",
379 "hoplimit %u ",
380 rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
381
382 if (tb[LWTUNNEL_IP6_TC])
383 print_uint(PRINT_ANY, "tc",
384 "tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
385 }
386
387 static void print_encap_bpf(FILE *fp, struct rtattr *encap)
388 {
389 struct rtattr *tb[LWT_BPF_MAX+1];
390
391 parse_rtattr_nested(tb, LWT_BPF_MAX, encap);
392
393 if (tb[LWT_BPF_IN])
394 print_encap_bpf_prog(fp, tb[LWT_BPF_IN], "in");
395 if (tb[LWT_BPF_OUT])
396 print_encap_bpf_prog(fp, tb[LWT_BPF_OUT], "out");
397 if (tb[LWT_BPF_XMIT])
398 print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit");
399 if (tb[LWT_BPF_XMIT_HEADROOM])
400 print_uint(PRINT_ANY, "headroom",
401 " %u ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
402 }
403
404 void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
405 struct rtattr *encap)
406 {
407 int et;
408
409 if (!encap_type)
410 return;
411
412 et = rta_getattr_u16(encap_type);
413
414 print_string(PRINT_ANY, "encap", " encap %s ", format_encap_type(et));
415
416 switch (et) {
417 case LWTUNNEL_ENCAP_MPLS:
418 print_encap_mpls(fp, encap);
419 break;
420 case LWTUNNEL_ENCAP_IP:
421 print_encap_ip(fp, encap);
422 break;
423 case LWTUNNEL_ENCAP_ILA:
424 print_encap_ila(fp, encap);
425 break;
426 case LWTUNNEL_ENCAP_IP6:
427 print_encap_ip6(fp, encap);
428 break;
429 case LWTUNNEL_ENCAP_BPF:
430 print_encap_bpf(fp, encap);
431 break;
432 case LWTUNNEL_ENCAP_SEG6:
433 print_encap_seg6(fp, encap);
434 break;
435 case LWTUNNEL_ENCAP_SEG6_LOCAL:
436 print_encap_seg6local(fp, encap);
437 break;
438 }
439 }
440
441 static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap)
442 {
443 struct ipv6_sr_hdr *srh;
444 int nsegs = 0;
445 int srhlen;
446 char *s;
447 int i;
448
449 s = segbuf;
450 for (i = 0; *s; *s++ == ',' ? i++ : *s);
451 nsegs = i + 1;
452
453 if (!encap)
454 nsegs++;
455
456 srhlen = 8 + 16*nsegs;
457
458 if (hmac)
459 srhlen += 40;
460
461 srh = malloc(srhlen);
462 memset(srh, 0, srhlen);
463
464 srh->hdrlen = (srhlen >> 3) - 1;
465 srh->type = 4;
466 srh->segments_left = nsegs - 1;
467 srh->first_segment = nsegs - 1;
468
469 if (hmac)
470 srh->flags |= SR6_FLAG1_HMAC;
471
472 i = srh->first_segment;
473 for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
474 inet_prefix addr;
475
476 get_addr(&addr, s, AF_INET6);
477 memcpy(&srh->segments[i], addr.data, sizeof(struct in6_addr));
478 i--;
479 }
480
481 if (hmac) {
482 struct sr6_tlv_hmac *tlv;
483
484 tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40);
485 tlv->tlvhdr.type = SR6_TLV_HMAC;
486 tlv->tlvhdr.len = 38;
487 tlv->hmackeyid = htonl(hmac);
488 }
489
490 return srh;
491 }
492
493 static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
494 char ***argvp)
495 {
496 int mode_ok = 0, segs_ok = 0, hmac_ok = 0;
497 struct seg6_iptunnel_encap *tuninfo;
498 struct ipv6_sr_hdr *srh;
499 char **argv = *argvp;
500 char segbuf[1024] = "";
501 int argc = *argcp;
502 int encap = -1;
503 __u32 hmac = 0;
504 int ret = 0;
505 int srhlen;
506
507 while (argc > 0) {
508 if (strcmp(*argv, "mode") == 0) {
509 NEXT_ARG();
510 if (mode_ok++)
511 duparg2("mode", *argv);
512 encap = read_seg6mode_type(*argv);
513 if (encap < 0)
514 invarg("\"mode\" value is invalid\n", *argv);
515 } else if (strcmp(*argv, "segs") == 0) {
516 NEXT_ARG();
517 if (segs_ok++)
518 duparg2("segs", *argv);
519 if (encap == -1)
520 invarg("\"segs\" provided before \"mode\"\n",
521 *argv);
522
523 strlcpy(segbuf, *argv, 1024);
524 } else if (strcmp(*argv, "hmac") == 0) {
525 NEXT_ARG();
526 if (hmac_ok++)
527 duparg2("hmac", *argv);
528 get_u32(&hmac, *argv, 0);
529 } else {
530 break;
531 }
532 argc--; argv++;
533 }
534
535 srh = parse_srh(segbuf, hmac, encap);
536 srhlen = (srh->hdrlen + 1) << 3;
537
538 tuninfo = malloc(sizeof(*tuninfo) + srhlen);
539 memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
540
541 tuninfo->mode = encap;
542
543 memcpy(tuninfo->srh, srh, srhlen);
544
545 if (rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
546 sizeof(*tuninfo) + srhlen)) {
547 ret = -1;
548 goto out;
549 }
550
551 *argcp = argc + 1;
552 *argvp = argv - 1;
553
554 out:
555 free(tuninfo);
556 free(srh);
557
558 return ret;
559 }
560
561 struct lwt_x {
562 struct rtattr *rta;
563 size_t len;
564 };
565
566 static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation)
567 {
568 struct lwt_x *x = lwt_ptr;
569
570 rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd);
571 rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation,
572 strlen(annotation) + 1);
573 }
574
575 static const struct bpf_cfg_ops bpf_cb_ops = {
576 .ebpf_cb = bpf_lwt_cb,
577 };
578
579 static int lwt_parse_bpf(struct rtattr *rta, size_t len,
580 int *argcp, char ***argvp,
581 int attr, const enum bpf_prog_type bpf_type)
582 {
583 struct bpf_cfg_in cfg = {
584 .type = bpf_type,
585 .argc = *argcp,
586 .argv = *argvp,
587 };
588 struct lwt_x x = {
589 .rta = rta,
590 .len = len,
591 };
592 struct rtattr *nest;
593 int err;
594
595 nest = rta_nest(rta, len, attr);
596 err = bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &x);
597 if (err < 0) {
598 fprintf(stderr, "Failed to parse eBPF program: %s\n",
599 strerror(-err));
600 return -1;
601 }
602 rta_nest_end(rta, nest);
603
604 *argcp = cfg.argc;
605 *argvp = cfg.argv;
606
607 return 0;
608 }
609
610 static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
611 char ***argvp)
612 {
613 int segs_ok = 0, hmac_ok = 0, table_ok = 0, nh4_ok = 0, nh6_ok = 0;
614 int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0, bpf_ok = 0;
615 __u32 action = 0, table, iif, oif;
616 struct ipv6_sr_hdr *srh;
617 char **argv = *argvp;
618 int argc = *argcp;
619 char segbuf[1024];
620 inet_prefix addr;
621 __u32 hmac = 0;
622 int ret = 0;
623
624 while (argc > 0) {
625 if (strcmp(*argv, "action") == 0) {
626 NEXT_ARG();
627 if (action_ok++)
628 duparg2("action", *argv);
629 action = read_action_type(*argv);
630 if (!action)
631 invarg("\"action\" value is invalid\n", *argv);
632 ret = rta_addattr32(rta, len, SEG6_LOCAL_ACTION,
633 action);
634 } else if (strcmp(*argv, "table") == 0) {
635 NEXT_ARG();
636 if (table_ok++)
637 duparg2("table", *argv);
638 get_u32(&table, *argv, 0);
639 ret = rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
640 } else if (strcmp(*argv, "nh4") == 0) {
641 NEXT_ARG();
642 if (nh4_ok++)
643 duparg2("nh4", *argv);
644 get_addr(&addr, *argv, AF_INET);
645 ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH4,
646 &addr.data, addr.bytelen);
647 } else if (strcmp(*argv, "nh6") == 0) {
648 NEXT_ARG();
649 if (nh6_ok++)
650 duparg2("nh6", *argv);
651 get_addr(&addr, *argv, AF_INET6);
652 ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH6,
653 &addr.data, addr.bytelen);
654 } else if (strcmp(*argv, "iif") == 0) {
655 NEXT_ARG();
656 if (iif_ok++)
657 duparg2("iif", *argv);
658 iif = ll_name_to_index(*argv);
659 if (!iif)
660 exit(nodev(*argv));
661 ret = rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
662 } else if (strcmp(*argv, "oif") == 0) {
663 NEXT_ARG();
664 if (oif_ok++)
665 duparg2("oif", *argv);
666 oif = ll_name_to_index(*argv);
667 if (!oif)
668 exit(nodev(*argv));
669 ret = rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
670 } else if (strcmp(*argv, "srh") == 0) {
671 NEXT_ARG();
672 if (srh_ok++)
673 duparg2("srh", *argv);
674 if (strcmp(*argv, "segs") != 0)
675 invarg("missing \"segs\" attribute for srh\n",
676 *argv);
677 NEXT_ARG();
678 if (segs_ok++)
679 duparg2("segs", *argv);
680 strncpy(segbuf, *argv, 1024);
681 segbuf[1023] = 0;
682 if (!NEXT_ARG_OK())
683 break;
684 NEXT_ARG();
685 if (strcmp(*argv, "hmac") == 0) {
686 NEXT_ARG();
687 if (hmac_ok++)
688 duparg2("hmac", *argv);
689 get_u32(&hmac, *argv, 0);
690 } else {
691 continue;
692 }
693 } else if (strcmp(*argv, "endpoint") == 0) {
694 NEXT_ARG();
695 if (bpf_ok++)
696 duparg2("endpoint", *argv);
697
698 if (lwt_parse_bpf(rta, len, &argc, &argv, SEG6_LOCAL_BPF,
699 BPF_PROG_TYPE_LWT_SEG6LOCAL) < 0)
700 exit(-1);
701 } else {
702 break;
703 }
704 if (ret)
705 return ret;
706 argc--; argv++;
707 }
708
709 if (!action) {
710 fprintf(stderr, "Missing action type\n");
711 exit(-1);
712 }
713
714 if (srh_ok) {
715 int srhlen;
716
717 srh = parse_srh(segbuf, hmac,
718 action == SEG6_LOCAL_ACTION_END_B6_ENCAP);
719 srhlen = (srh->hdrlen + 1) << 3;
720 ret = rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
721 free(srh);
722 }
723
724 *argcp = argc + 1;
725 *argvp = argv - 1;
726
727 return ret;
728 }
729
730 static int parse_encap_mpls(struct rtattr *rta, size_t len,
731 int *argcp, char ***argvp)
732 {
733 inet_prefix addr;
734 int argc = *argcp;
735 char **argv = *argvp;
736 int ttl_ok = 0;
737
738 if (get_addr(&addr, *argv, AF_MPLS)) {
739 fprintf(stderr,
740 "Error: an inet address is expected rather than \"%s\".\n",
741 *argv);
742 exit(1);
743 }
744
745 if (rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST,
746 &addr.data, addr.bytelen))
747 return -1;
748
749 argc--;
750 argv++;
751
752 while (argc > 0) {
753 if (strcmp(*argv, "ttl") == 0) {
754 __u8 ttl;
755
756 NEXT_ARG();
757 if (ttl_ok++)
758 duparg2("ttl", *argv);
759 if (get_u8(&ttl, *argv, 0))
760 invarg("\"ttl\" value is invalid\n", *argv);
761 if (rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl))
762 return -1;
763 } else {
764 break;
765 }
766 argc--; argv++;
767 }
768
769 /* argv is currently the first unparsed argument,
770 * but the lwt_parse_encap() caller will move to the next,
771 * so step back
772 */
773 *argcp = argc + 1;
774 *argvp = argv - 1;
775
776 return 0;
777 }
778
779 static int parse_encap_ip(struct rtattr *rta, size_t len,
780 int *argcp, char ***argvp)
781 {
782 int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
783 char **argv = *argvp;
784 int argc = *argcp;
785 int ret = 0;
786
787 while (argc > 0) {
788 if (strcmp(*argv, "id") == 0) {
789 __u64 id;
790
791 NEXT_ARG();
792 if (id_ok++)
793 duparg2("id", *argv);
794 if (get_be64(&id, *argv, 0))
795 invarg("\"id\" value is invalid\n", *argv);
796 ret = rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
797 } else if (strcmp(*argv, "dst") == 0) {
798 inet_prefix addr;
799
800 NEXT_ARG();
801 if (dst_ok++)
802 duparg2("dst", *argv);
803 get_addr(&addr, *argv, AF_INET);
804 ret = rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
805 &addr.data, addr.bytelen);
806 } else if (strcmp(*argv, "src") == 0) {
807 inet_prefix addr;
808
809 NEXT_ARG();
810 if (src_ok++)
811 duparg2("src", *argv);
812 get_addr(&addr, *argv, AF_INET);
813 ret = rta_addattr_l(rta, len, LWTUNNEL_IP_SRC,
814 &addr.data, addr.bytelen);
815 } else if (strcmp(*argv, "tos") == 0) {
816 __u32 tos;
817
818 NEXT_ARG();
819 if (tos_ok++)
820 duparg2("tos", *argv);
821 if (rtnl_dsfield_a2n(&tos, *argv))
822 invarg("\"tos\" value is invalid\n", *argv);
823 ret = rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
824 } else if (strcmp(*argv, "ttl") == 0) {
825 __u8 ttl;
826
827 NEXT_ARG();
828 if (ttl_ok++)
829 duparg2("ttl", *argv);
830 if (get_u8(&ttl, *argv, 0))
831 invarg("\"ttl\" value is invalid\n", *argv);
832 ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
833 } else {
834 break;
835 }
836 if (ret)
837 break;
838 argc--; argv++;
839 }
840
841 /* argv is currently the first unparsed argument,
842 * but the lwt_parse_encap() caller will move to the next,
843 * so step back
844 */
845 *argcp = argc + 1;
846 *argvp = argv - 1;
847
848 return ret;
849 }
850
851 static int parse_encap_ila(struct rtattr *rta, size_t len,
852 int *argcp, char ***argvp)
853 {
854 __u64 locator;
855 int argc = *argcp;
856 char **argv = *argvp;
857 int ret = 0;
858
859 if (get_addr64(&locator, *argv) < 0) {
860 fprintf(stderr, "Bad locator: %s\n", *argv);
861 exit(1);
862 }
863
864 argc--; argv++;
865
866 if (rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator))
867 return -1;
868
869 while (argc > 0) {
870 if (strcmp(*argv, "csum-mode") == 0) {
871 int csum_mode;
872
873 NEXT_ARG();
874
875 csum_mode = ila_csum_name2mode(*argv);
876 if (csum_mode < 0)
877 invarg("\"csum-mode\" value is invalid\n",
878 *argv);
879
880 ret = rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
881 (__u8)csum_mode);
882
883 argc--; argv++;
884 } else if (strcmp(*argv, "ident-type") == 0) {
885 int ident_type;
886
887 NEXT_ARG();
888
889 ident_type = ila_ident_name2type(*argv);
890 if (ident_type < 0)
891 invarg("\"ident-type\" value is invalid\n",
892 *argv);
893
894 ret = rta_addattr8(rta, 1024, ILA_ATTR_IDENT_TYPE,
895 (__u8)ident_type);
896
897 argc--; argv++;
898 } else if (strcmp(*argv, "hook-type") == 0) {
899 int hook_type;
900
901 NEXT_ARG();
902
903 hook_type = ila_hook_name2type(*argv);
904 if (hook_type < 0)
905 invarg("\"hook-type\" value is invalid\n",
906 *argv);
907
908 ret = rta_addattr8(rta, 1024, ILA_ATTR_HOOK_TYPE,
909 (__u8)hook_type);
910
911 argc--; argv++;
912 } else {
913 break;
914 }
915 if (ret)
916 break;
917 }
918
919 /* argv is currently the first unparsed argument,
920 * but the lwt_parse_encap() caller will move to the next,
921 * so step back
922 */
923 *argcp = argc + 1;
924 *argvp = argv - 1;
925
926 return ret;
927 }
928
929 static int parse_encap_ip6(struct rtattr *rta, size_t len,
930 int *argcp, char ***argvp)
931 {
932 int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
933 char **argv = *argvp;
934 int argc = *argcp;
935 int ret = 0;
936
937 while (argc > 0) {
938 if (strcmp(*argv, "id") == 0) {
939 __u64 id;
940
941 NEXT_ARG();
942 if (id_ok++)
943 duparg2("id", *argv);
944 if (get_be64(&id, *argv, 0))
945 invarg("\"id\" value is invalid\n", *argv);
946 ret = rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
947 } else if (strcmp(*argv, "dst") == 0) {
948 inet_prefix addr;
949
950 NEXT_ARG();
951 if (dst_ok++)
952 duparg2("dst", *argv);
953 get_addr(&addr, *argv, AF_INET6);
954 ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
955 &addr.data, addr.bytelen);
956 } else if (strcmp(*argv, "src") == 0) {
957 inet_prefix addr;
958
959 NEXT_ARG();
960 if (src_ok++)
961 duparg2("src", *argv);
962 get_addr(&addr, *argv, AF_INET6);
963 ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_SRC,
964 &addr.data, addr.bytelen);
965 } else if (strcmp(*argv, "tc") == 0) {
966 __u32 tc;
967
968 NEXT_ARG();
969 if (tos_ok++)
970 duparg2("tc", *argv);
971 if (rtnl_dsfield_a2n(&tc, *argv))
972 invarg("\"tc\" value is invalid\n", *argv);
973 ret = rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
974 } else if (strcmp(*argv, "hoplimit") == 0) {
975 __u8 hoplimit;
976
977 NEXT_ARG();
978 if (ttl_ok++)
979 duparg2("hoplimit", *argv);
980 if (get_u8(&hoplimit, *argv, 0))
981 invarg("\"hoplimit\" value is invalid\n",
982 *argv);
983 ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
984 hoplimit);
985 } else {
986 break;
987 }
988 if (ret)
989 break;
990 argc--; argv++;
991 }
992
993 /* argv is currently the first unparsed argument,
994 * but the lwt_parse_encap() caller will move to the next,
995 * so step back
996 */
997 *argcp = argc + 1;
998 *argvp = argv - 1;
999
1000 return ret;
1001 }
1002
1003 static void lwt_bpf_usage(void)
1004 {
1005 fprintf(stderr, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
1006 fprintf(stderr, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
1007 exit(-1);
1008 }
1009
1010 static int parse_encap_bpf(struct rtattr *rta, size_t len, int *argcp,
1011 char ***argvp)
1012 {
1013 char **argv = *argvp;
1014 int argc = *argcp;
1015 int headroom_set = 0;
1016
1017 while (argc > 0) {
1018 if (strcmp(*argv, "in") == 0) {
1019 NEXT_ARG();
1020 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_IN,
1021 BPF_PROG_TYPE_LWT_IN) < 0)
1022 return -1;
1023 } else if (strcmp(*argv, "out") == 0) {
1024 NEXT_ARG();
1025 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_OUT,
1026 BPF_PROG_TYPE_LWT_OUT) < 0)
1027 return -1;
1028 } else if (strcmp(*argv, "xmit") == 0) {
1029 NEXT_ARG();
1030 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_XMIT,
1031 BPF_PROG_TYPE_LWT_XMIT) < 0)
1032 return -1;
1033 } else if (strcmp(*argv, "headroom") == 0) {
1034 unsigned int headroom;
1035
1036 NEXT_ARG();
1037 if (get_unsigned(&headroom, *argv, 0) || headroom == 0)
1038 invarg("headroom is invalid\n", *argv);
1039 if (!headroom_set)
1040 rta_addattr32(rta, 1024, LWT_BPF_XMIT_HEADROOM,
1041 headroom);
1042 headroom_set = 1;
1043 } else if (strcmp(*argv, "help") == 0) {
1044 lwt_bpf_usage();
1045 } else {
1046 break;
1047 }
1048 NEXT_ARG_FWD();
1049 }
1050
1051 /* argv is currently the first unparsed argument,
1052 * but the lwt_parse_encap() caller will move to the next,
1053 * so step back
1054 */
1055 *argcp = argc + 1;
1056 *argvp = argv - 1;
1057
1058 return 0;
1059 }
1060
1061 int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
1062 {
1063 struct rtattr *nest;
1064 int argc = *argcp;
1065 char **argv = *argvp;
1066 __u16 type;
1067 int ret = 0;
1068
1069 NEXT_ARG();
1070 type = read_encap_type(*argv);
1071 if (!type)
1072 invarg("\"encap type\" value is invalid\n", *argv);
1073
1074 NEXT_ARG();
1075 if (argc <= 1) {
1076 fprintf(stderr,
1077 "Error: unexpected end of line after \"encap\"\n");
1078 exit(-1);
1079 }
1080
1081 nest = rta_nest(rta, 1024, RTA_ENCAP);
1082 switch (type) {
1083 case LWTUNNEL_ENCAP_MPLS:
1084 ret = parse_encap_mpls(rta, len, &argc, &argv);
1085 break;
1086 case LWTUNNEL_ENCAP_IP:
1087 ret = parse_encap_ip(rta, len, &argc, &argv);
1088 break;
1089 case LWTUNNEL_ENCAP_ILA:
1090 ret = parse_encap_ila(rta, len, &argc, &argv);
1091 break;
1092 case LWTUNNEL_ENCAP_IP6:
1093 ret = parse_encap_ip6(rta, len, &argc, &argv);
1094 break;
1095 case LWTUNNEL_ENCAP_BPF:
1096 if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
1097 exit(-1);
1098 break;
1099 case LWTUNNEL_ENCAP_SEG6:
1100 ret = parse_encap_seg6(rta, len, &argc, &argv);
1101 break;
1102 case LWTUNNEL_ENCAP_SEG6_LOCAL:
1103 ret = parse_encap_seg6local(rta, len, &argc, &argv);
1104 break;
1105 default:
1106 fprintf(stderr, "Error: unsupported encap type\n");
1107 break;
1108 }
1109 if (ret)
1110 return ret;
1111
1112 rta_nest_end(rta, nest);
1113
1114 ret = rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
1115
1116 *argcp = argc;
1117 *argvp = argv;
1118
1119 return ret;
1120 }