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