]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iproute_lwtunnel.c
tc/m_gact: Drop dead code
[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 "utils.h"
26 #include "iproute_lwtunnel.h"
27 #include "bpf_util.h"
28
29 #include <linux/seg6.h>
30 #include <linux/seg6_iptunnel.h>
31 #include <linux/seg6_hmac.h>
32
33 static const char *format_encap_type(int type)
34 {
35 switch (type) {
36 case LWTUNNEL_ENCAP_MPLS:
37 return "mpls";
38 case LWTUNNEL_ENCAP_IP:
39 return "ip";
40 case LWTUNNEL_ENCAP_IP6:
41 return "ip6";
42 case LWTUNNEL_ENCAP_ILA:
43 return "ila";
44 case LWTUNNEL_ENCAP_BPF:
45 return "bpf";
46 case LWTUNNEL_ENCAP_SEG6:
47 return "seg6";
48 default:
49 return "unknown";
50 }
51 }
52
53 static void encap_type_usage(void)
54 {
55 int i;
56
57 fprintf(stderr, "Usage: ip route ... encap TYPE [ OPTIONS ] [...]\n");
58
59 for (i = 1; i <= LWTUNNEL_ENCAP_MAX; i++)
60 fprintf(stderr, "%s %s\n", format_encap_type(i),
61 i == 1 ? "TYPE := " : " ");
62
63 exit(-1);
64 }
65
66 static int read_encap_type(const char *name)
67 {
68 if (strcmp(name, "mpls") == 0)
69 return LWTUNNEL_ENCAP_MPLS;
70 else if (strcmp(name, "ip") == 0)
71 return LWTUNNEL_ENCAP_IP;
72 else if (strcmp(name, "ip6") == 0)
73 return LWTUNNEL_ENCAP_IP6;
74 else if (strcmp(name, "ila") == 0)
75 return LWTUNNEL_ENCAP_ILA;
76 else if (strcmp(name, "bpf") == 0)
77 return LWTUNNEL_ENCAP_BPF;
78 else if (strcmp(name, "seg6") == 0)
79 return LWTUNNEL_ENCAP_SEG6;
80 else if (strcmp(name, "help") == 0)
81 encap_type_usage();
82
83 return LWTUNNEL_ENCAP_NONE;
84 }
85
86 static void print_encap_seg6(FILE *fp, struct rtattr *encap)
87 {
88 struct rtattr *tb[SEG6_IPTUNNEL_MAX+1];
89 struct seg6_iptunnel_encap *tuninfo;
90 struct ipv6_sr_hdr *srh;
91 int i;
92
93 parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap);
94
95 if (!tb[SEG6_IPTUNNEL_SRH])
96 return;
97
98 tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]);
99 fprintf(fp, "mode %s ",
100 (tuninfo->mode == SEG6_IPTUN_MODE_ENCAP) ? "encap" : "inline");
101
102 srh = tuninfo->srh;
103
104 fprintf(fp, "segs %d [ ", srh->first_segment + 1);
105
106 for (i = srh->first_segment; i >= 0; i--)
107 fprintf(fp, "%s ",
108 rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
109
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 fprintf(fp, "hmac 0x%X ", ntohl(tlv->hmackeyid));
118 }
119 }
120
121 static void print_encap_mpls(FILE *fp, struct rtattr *encap)
122 {
123 struct rtattr *tb[MPLS_IPTUNNEL_MAX+1];
124
125 parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
126
127 if (tb[MPLS_IPTUNNEL_DST])
128 fprintf(fp, " %s ",
129 format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST]));
130 if (tb[MPLS_IPTUNNEL_TTL])
131 fprintf(fp, "ttl %u ",
132 rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
133 }
134
135 static void print_encap_ip(FILE *fp, struct rtattr *encap)
136 {
137 struct rtattr *tb[LWTUNNEL_IP_MAX+1];
138
139 parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
140
141 if (tb[LWTUNNEL_IP_ID])
142 fprintf(fp, "id %llu ",
143 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
144
145 if (tb[LWTUNNEL_IP_SRC])
146 fprintf(fp, "src %s ",
147 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
148
149 if (tb[LWTUNNEL_IP_DST])
150 fprintf(fp, "dst %s ",
151 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
152
153 if (tb[LWTUNNEL_IP_TTL])
154 fprintf(fp, "ttl %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
155
156 if (tb[LWTUNNEL_IP_TOS])
157 fprintf(fp, "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
158 }
159
160 static char *ila_csum_mode2name(__u8 csum_mode)
161 {
162 switch (csum_mode) {
163 case ILA_CSUM_ADJUST_TRANSPORT:
164 return "adj-transport";
165 case ILA_CSUM_NEUTRAL_MAP:
166 return "neutral-map";
167 case ILA_CSUM_NO_ACTION:
168 return "no-action";
169 default:
170 return "unknown";
171 }
172 }
173
174 static int ila_csum_name2mode(char *name)
175 {
176 if (strcmp(name, "adj-transport") == 0)
177 return ILA_CSUM_ADJUST_TRANSPORT;
178 else if (strcmp(name, "neutral-map") == 0)
179 return ILA_CSUM_NEUTRAL_MAP;
180 else if (strcmp(name, "no-action") == 0)
181 return ILA_CSUM_NO_ACTION;
182 else
183 return -1;
184 }
185
186 static void print_encap_ila(FILE *fp, struct rtattr *encap)
187 {
188 struct rtattr *tb[ILA_ATTR_MAX+1];
189
190 parse_rtattr_nested(tb, ILA_ATTR_MAX, encap);
191
192 if (tb[ILA_ATTR_LOCATOR]) {
193 char abuf[ADDR64_BUF_SIZE];
194
195 addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
196 abuf, sizeof(abuf));
197 fprintf(fp, " %s ", abuf);
198 }
199
200 if (tb[ILA_ATTR_CSUM_MODE])
201 fprintf(fp, " csum-mode %s ",
202 ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE])));
203 }
204
205 static void print_encap_ip6(FILE *fp, struct rtattr *encap)
206 {
207 struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
208
209 parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
210
211 if (tb[LWTUNNEL_IP6_ID])
212 fprintf(fp, "id %llu ",
213 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
214
215 if (tb[LWTUNNEL_IP6_SRC])
216 fprintf(fp, "src %s ",
217 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
218
219 if (tb[LWTUNNEL_IP6_DST])
220 fprintf(fp, "dst %s ",
221 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
222
223 if (tb[LWTUNNEL_IP6_HOPLIMIT])
224 fprintf(fp, "hoplimit %d ",
225 rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
226
227 if (tb[LWTUNNEL_IP6_TC])
228 fprintf(fp, "tc %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
229 }
230
231 static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
232 const char *str)
233 {
234 struct rtattr *tb[LWT_BPF_PROG_MAX+1];
235
236 parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
237 fprintf(fp, "%s ", str);
238
239 if (tb[LWT_BPF_PROG_NAME])
240 fprintf(fp, "%s ", rta_getattr_str(tb[LWT_BPF_PROG_NAME]));
241 }
242
243 static void print_encap_bpf(FILE *fp, struct rtattr *encap)
244 {
245 struct rtattr *tb[LWT_BPF_MAX+1];
246
247 parse_rtattr_nested(tb, LWT_BPF_MAX, encap);
248
249 if (tb[LWT_BPF_IN])
250 print_encap_bpf_prog(fp, tb[LWT_BPF_IN], "in");
251 if (tb[LWT_BPF_OUT])
252 print_encap_bpf_prog(fp, tb[LWT_BPF_OUT], "out");
253 if (tb[LWT_BPF_XMIT])
254 print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit");
255 if (tb[LWT_BPF_XMIT_HEADROOM])
256 fprintf(fp, "%d ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
257 }
258
259 void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
260 struct rtattr *encap)
261 {
262 int et;
263
264 if (!encap_type)
265 return;
266
267 et = rta_getattr_u16(encap_type);
268
269 fprintf(fp, " encap %s ", format_encap_type(et));
270
271 switch (et) {
272 case LWTUNNEL_ENCAP_MPLS:
273 print_encap_mpls(fp, encap);
274 break;
275 case LWTUNNEL_ENCAP_IP:
276 print_encap_ip(fp, encap);
277 break;
278 case LWTUNNEL_ENCAP_ILA:
279 print_encap_ila(fp, encap);
280 break;
281 case LWTUNNEL_ENCAP_IP6:
282 print_encap_ip6(fp, encap);
283 break;
284 case LWTUNNEL_ENCAP_BPF:
285 print_encap_bpf(fp, encap);
286 break;
287 case LWTUNNEL_ENCAP_SEG6:
288 print_encap_seg6(fp, encap);
289 break;
290 }
291 }
292
293 static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
294 char ***argvp)
295 {
296 int mode_ok = 0, segs_ok = 0, hmac_ok = 0;
297 struct seg6_iptunnel_encap *tuninfo;
298 struct ipv6_sr_hdr *srh;
299 char **argv = *argvp;
300 char segbuf[1024];
301 int argc = *argcp;
302 int encap = -1;
303 __u32 hmac = 0;
304 int nsegs = 0;
305 int srhlen;
306 char *s;
307 int i;
308
309 while (argc > 0) {
310 if (strcmp(*argv, "mode") == 0) {
311 NEXT_ARG();
312 if (mode_ok++)
313 duparg2("mode", *argv);
314 if (strcmp(*argv, "encap") == 0)
315 encap = 1;
316 else if (strcmp(*argv, "inline") == 0)
317 encap = 0;
318 else
319 invarg("\"mode\" value is invalid\n", *argv);
320 } else if (strcmp(*argv, "segs") == 0) {
321 NEXT_ARG();
322 if (segs_ok++)
323 duparg2("segs", *argv);
324 if (encap == -1)
325 invarg("\"segs\" provided before \"mode\"\n",
326 *argv);
327
328 strncpy(segbuf, *argv, 1024);
329 segbuf[1023] = 0;
330 } else if (strcmp(*argv, "hmac") == 0) {
331 NEXT_ARG();
332 if (hmac_ok++)
333 duparg2("hmac", *argv);
334 get_u32(&hmac, *argv, 0);
335 } else {
336 break;
337 }
338 argc--; argv++;
339 }
340
341 s = segbuf;
342 for (i = 0; *s; *s++ == ',' ? i++ : *s);
343 nsegs = i + 1;
344
345 if (!encap)
346 nsegs++;
347
348 srhlen = 8 + 16*nsegs;
349
350 if (hmac)
351 srhlen += 40;
352
353 tuninfo = malloc(sizeof(*tuninfo) + srhlen);
354 memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
355
356 if (encap)
357 tuninfo->mode = SEG6_IPTUN_MODE_ENCAP;
358 else
359 tuninfo->mode = SEG6_IPTUN_MODE_INLINE;
360
361 srh = tuninfo->srh;
362 srh->hdrlen = (srhlen >> 3) - 1;
363 srh->type = 4;
364 srh->segments_left = nsegs - 1;
365 srh->first_segment = nsegs - 1;
366
367 if (hmac)
368 srh->flags |= SR6_FLAG1_HMAC;
369
370 i = srh->first_segment;
371 for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
372 inet_get_addr(s, NULL, &srh->segments[i]);
373 i--;
374 }
375
376 if (hmac) {
377 struct sr6_tlv_hmac *tlv;
378
379 tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40);
380 tlv->tlvhdr.type = SR6_TLV_HMAC;
381 tlv->tlvhdr.len = 38;
382 tlv->hmackeyid = htonl(hmac);
383 }
384
385 rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
386 sizeof(*tuninfo) + srhlen);
387 free(tuninfo);
388
389 *argcp = argc + 1;
390 *argvp = argv - 1;
391
392 return 0;
393 }
394
395 static int parse_encap_mpls(struct rtattr *rta, size_t len,
396 int *argcp, char ***argvp)
397 {
398 inet_prefix addr;
399 int argc = *argcp;
400 char **argv = *argvp;
401 int ttl_ok = 0;
402
403 if (get_addr(&addr, *argv, AF_MPLS)) {
404 fprintf(stderr,
405 "Error: an inet address is expected rather than \"%s\".\n",
406 *argv);
407 exit(1);
408 }
409
410 rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data,
411 addr.bytelen);
412
413 argc--;
414 argv++;
415
416 while (argc > 0) {
417 if (strcmp(*argv, "ttl") == 0) {
418 __u8 ttl;
419
420 NEXT_ARG();
421 if (ttl_ok++)
422 duparg2("ttl", *argv);
423 if (get_u8(&ttl, *argv, 0))
424 invarg("\"ttl\" value is invalid\n", *argv);
425 rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl);
426 } else {
427 break;
428 }
429 argc--; argv++;
430 }
431
432 /* argv is currently the first unparsed argument,
433 * but the lwt_parse_encap() caller will move to the next,
434 * so step back
435 */
436 *argcp = argc + 1;
437 *argvp = argv - 1;
438
439 return 0;
440 }
441
442 static int parse_encap_ip(struct rtattr *rta, size_t len,
443 int *argcp, char ***argvp)
444 {
445 int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
446 char **argv = *argvp;
447 int argc = *argcp;
448
449 while (argc > 0) {
450 if (strcmp(*argv, "id") == 0) {
451 __u64 id;
452
453 NEXT_ARG();
454 if (id_ok++)
455 duparg2("id", *argv);
456 if (get_be64(&id, *argv, 0))
457 invarg("\"id\" value is invalid\n", *argv);
458 rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
459 } else if (strcmp(*argv, "dst") == 0) {
460 inet_prefix addr;
461
462 NEXT_ARG();
463 if (dst_ok++)
464 duparg2("dst", *argv);
465 get_addr(&addr, *argv, AF_INET);
466 rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
467 &addr.data, addr.bytelen);
468 } else if (strcmp(*argv, "tos") == 0) {
469 __u32 tos;
470
471 NEXT_ARG();
472 if (tos_ok++)
473 duparg2("tos", *argv);
474 if (rtnl_dsfield_a2n(&tos, *argv))
475 invarg("\"tos\" value is invalid\n", *argv);
476 rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
477 } else if (strcmp(*argv, "ttl") == 0) {
478 __u8 ttl;
479
480 NEXT_ARG();
481 if (ttl_ok++)
482 duparg2("ttl", *argv);
483 if (get_u8(&ttl, *argv, 0))
484 invarg("\"ttl\" value is invalid\n", *argv);
485 rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
486 } else {
487 break;
488 }
489 argc--; argv++;
490 }
491
492 /* argv is currently the first unparsed argument,
493 * but the lwt_parse_encap() caller will move to the next,
494 * so step back
495 */
496 *argcp = argc + 1;
497 *argvp = argv - 1;
498
499 return 0;
500 }
501
502 static int parse_encap_ila(struct rtattr *rta, size_t len,
503 int *argcp, char ***argvp)
504 {
505 __u64 locator;
506 int argc = *argcp;
507 char **argv = *argvp;
508
509 if (get_addr64(&locator, *argv) < 0) {
510 fprintf(stderr, "Bad locator: %s\n", *argv);
511 exit(1);
512 }
513
514 argc--; argv++;
515
516 rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator);
517
518 while (argc > 0) {
519 if (strcmp(*argv, "csum-mode") == 0) {
520 int csum_mode;
521
522 NEXT_ARG();
523
524 csum_mode = ila_csum_name2mode(*argv);
525 if (csum_mode < 0)
526 invarg("\"csum-mode\" value is invalid\n",
527 *argv);
528
529 rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
530 (__u8)csum_mode);
531
532 argc--; argv++;
533 } else {
534 break;
535 }
536 }
537
538 /* argv is currently the first unparsed argument,
539 * but the lwt_parse_encap() caller will move to the next,
540 * so step back
541 */
542 *argcp = argc + 1;
543 *argvp = argv - 1;
544
545 return 0;
546 }
547
548 static int parse_encap_ip6(struct rtattr *rta, size_t len,
549 int *argcp, char ***argvp)
550 {
551 int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
552 char **argv = *argvp;
553 int argc = *argcp;
554
555 while (argc > 0) {
556 if (strcmp(*argv, "id") == 0) {
557 __u64 id;
558
559 NEXT_ARG();
560 if (id_ok++)
561 duparg2("id", *argv);
562 if (get_be64(&id, *argv, 0))
563 invarg("\"id\" value is invalid\n", *argv);
564 rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
565 } else if (strcmp(*argv, "dst") == 0) {
566 inet_prefix addr;
567
568 NEXT_ARG();
569 if (dst_ok++)
570 duparg2("dst", *argv);
571 get_addr(&addr, *argv, AF_INET6);
572 rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
573 &addr.data, addr.bytelen);
574 } else if (strcmp(*argv, "tc") == 0) {
575 __u32 tc;
576
577 NEXT_ARG();
578 if (tos_ok++)
579 duparg2("tc", *argv);
580 if (rtnl_dsfield_a2n(&tc, *argv))
581 invarg("\"tc\" value is invalid\n", *argv);
582 rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
583 } else if (strcmp(*argv, "hoplimit") == 0) {
584 __u8 hoplimit;
585
586 NEXT_ARG();
587 if (ttl_ok++)
588 duparg2("hoplimit", *argv);
589 if (get_u8(&hoplimit, *argv, 0))
590 invarg("\"hoplimit\" value is invalid\n",
591 *argv);
592 rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit);
593 } else {
594 break;
595 }
596 argc--; argv++;
597 }
598
599 /* argv is currently the first unparsed argument,
600 * but the lwt_parse_encap() caller will move to the next,
601 * so step back
602 */
603 *argcp = argc + 1;
604 *argvp = argv - 1;
605
606 return 0;
607 }
608
609 struct lwt_x {
610 struct rtattr *rta;
611 size_t len;
612 };
613
614 static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation)
615 {
616 struct lwt_x *x = lwt_ptr;
617
618 rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd);
619 rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation,
620 strlen(annotation) + 1);
621 }
622
623 static const struct bpf_cfg_ops bpf_cb_ops = {
624 .ebpf_cb = bpf_lwt_cb,
625 };
626
627 static int lwt_parse_bpf(struct rtattr *rta, size_t len,
628 int *argcp, char ***argvp,
629 int attr, const enum bpf_prog_type bpf_type)
630 {
631 struct bpf_cfg_in cfg = {
632 .argc = *argcp,
633 .argv = *argvp,
634 };
635 struct lwt_x x = {
636 .rta = rta,
637 .len = len,
638 };
639 struct rtattr *nest;
640 int err;
641
642 nest = rta_nest(rta, len, attr);
643 err = bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, &x);
644 if (err < 0) {
645 fprintf(stderr, "Failed to parse eBPF program: %s\n",
646 strerror(-err));
647 return -1;
648 }
649 rta_nest_end(rta, nest);
650
651 *argcp = cfg.argc;
652 *argvp = cfg.argv;
653
654 return 0;
655 }
656
657 static void lwt_bpf_usage(void)
658 {
659 fprintf(stderr, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
660 fprintf(stderr, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
661 exit(-1);
662 }
663
664 static int parse_encap_bpf(struct rtattr *rta, size_t len, int *argcp,
665 char ***argvp)
666 {
667 char **argv = *argvp;
668 int argc = *argcp;
669 int headroom_set = 0;
670
671 while (argc > 0) {
672 if (strcmp(*argv, "in") == 0) {
673 NEXT_ARG();
674 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_IN,
675 BPF_PROG_TYPE_LWT_IN) < 0)
676 return -1;
677 } else if (strcmp(*argv, "out") == 0) {
678 NEXT_ARG();
679 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_OUT,
680 BPF_PROG_TYPE_LWT_OUT) < 0)
681 return -1;
682 } else if (strcmp(*argv, "xmit") == 0) {
683 NEXT_ARG();
684 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_XMIT,
685 BPF_PROG_TYPE_LWT_XMIT) < 0)
686 return -1;
687 } else if (strcmp(*argv, "headroom") == 0) {
688 unsigned int headroom;
689
690 NEXT_ARG();
691 if (get_unsigned(&headroom, *argv, 0) || headroom == 0)
692 invarg("headroom is invalid\n", *argv);
693 if (!headroom_set)
694 rta_addattr32(rta, 1024, LWT_BPF_XMIT_HEADROOM,
695 headroom);
696 headroom_set = 1;
697 } else if (strcmp(*argv, "help") == 0) {
698 lwt_bpf_usage();
699 } else {
700 break;
701 }
702 NEXT_ARG_FWD();
703 }
704
705 /* argv is currently the first unparsed argument,
706 * but the lwt_parse_encap() caller will move to the next,
707 * so step back
708 */
709 *argcp = argc + 1;
710 *argvp = argv - 1;
711
712 return 0;
713 }
714
715 int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
716 {
717 struct rtattr *nest;
718 int argc = *argcp;
719 char **argv = *argvp;
720 __u16 type;
721
722 NEXT_ARG();
723 type = read_encap_type(*argv);
724 if (!type)
725 invarg("\"encap type\" value is invalid\n", *argv);
726
727 NEXT_ARG();
728 if (argc <= 1) {
729 fprintf(stderr,
730 "Error: unexpected end of line after \"encap\"\n");
731 exit(-1);
732 }
733
734 nest = rta_nest(rta, 1024, RTA_ENCAP);
735 switch (type) {
736 case LWTUNNEL_ENCAP_MPLS:
737 parse_encap_mpls(rta, len, &argc, &argv);
738 break;
739 case LWTUNNEL_ENCAP_IP:
740 parse_encap_ip(rta, len, &argc, &argv);
741 break;
742 case LWTUNNEL_ENCAP_ILA:
743 parse_encap_ila(rta, len, &argc, &argv);
744 break;
745 case LWTUNNEL_ENCAP_IP6:
746 parse_encap_ip6(rta, len, &argc, &argv);
747 break;
748 case LWTUNNEL_ENCAP_BPF:
749 if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
750 exit(-1);
751 break;
752 case LWTUNNEL_ENCAP_SEG6:
753 parse_encap_seg6(rta, len, &argc, &argv);
754 break;
755 default:
756 fprintf(stderr, "Error: unsupported encap type\n");
757 break;
758 }
759 rta_nest_end(rta, nest);
760
761 rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
762
763 *argcp = argc;
764 *argvp = argv;
765
766 return 0;
767 }