]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iproute_lwtunnel.c
include: add pfkeyv2.h drop ipv6.h
[mirror_iproute2.git] / ip / iproute_lwtunnel.c
CommitLineData
1e529305
RP
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>
56f5daac 10 * Thomas Graf <tgraf@suug.ch>
1e529305
RP
11 *
12 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <fcntl.h>
18#include <string.h>
5866bddd 19#include <linux/ila.h>
1e529305
RP
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"
b15f440e 27#include "bpf_util.h"
1e529305 28
e4319590
DL
29#include <linux/seg6.h>
30#include <linux/seg6_iptunnel.h>
31#include <linux/seg6_hmac.h>
32
1e529305
RP
33static 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";
5866bddd
TH
42 case LWTUNNEL_ENCAP_ILA:
43 return "ila";
b15f440e
TG
44 case LWTUNNEL_ENCAP_BPF:
45 return "bpf";
e8493916
DL
46 case LWTUNNEL_ENCAP_SEG6:
47 return "seg6";
1e529305
RP
48 default:
49 return "unknown";
50 }
51}
52
b15f440e
TG
53static 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
66static 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;
e8493916
DL
78 else if (strcmp(name, "seg6") == 0)
79 return LWTUNNEL_ENCAP_SEG6;
b15f440e
TG
80 else if (strcmp(name, "help") == 0)
81 encap_type_usage();
82
83 return LWTUNNEL_ENCAP_NONE;
84}
85
e8493916
DL
86static 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
1e529305
RP
121static void print_encap_mpls(FILE *fp, struct rtattr *encap)
122{
123 struct rtattr *tb[MPLS_IPTUNNEL_MAX+1];
1e529305
RP
124
125 parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
126
127 if (tb[MPLS_IPTUNNEL_DST])
d49f934c 128 fprintf(fp, " %s ",
b723368c 129 format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST]));
9688cf3b
RS
130 if (tb[MPLS_IPTUNNEL_TTL])
131 fprintf(fp, "ttl %u ",
132 rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
1e529305
RP
133}
134
135static void print_encap_ip(FILE *fp, struct rtattr *encap)
136{
137 struct rtattr *tb[LWTUNNEL_IP_MAX+1];
1e529305
RP
138
139 parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
140
141 if (tb[LWTUNNEL_IP_ID])
b723368c
SH
142 fprintf(fp, "id %llu ",
143 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
1e529305
RP
144
145 if (tb[LWTUNNEL_IP_SRC])
146 fprintf(fp, "src %s ",
7faf1588 147 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
1e529305
RP
148
149 if (tb[LWTUNNEL_IP_DST])
150 fprintf(fp, "dst %s ",
7faf1588 151 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
1e529305
RP
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
ed67f838
TH
160static 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
174static __u8 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
5866bddd
TH
186static 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
9f1370c0 195 addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
5866bddd
TH
196 abuf, sizeof(abuf));
197 fprintf(fp, " %s ", abuf);
198 }
ed67f838
TH
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])));
5866bddd
TH
203}
204
d95cdcf5
PA
205static void print_encap_ip6(FILE *fp, struct rtattr *encap)
206{
207 struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
d95cdcf5
PA
208
209 parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
210
211 if (tb[LWTUNNEL_IP6_ID])
b723368c
SH
212 fprintf(fp, "id %llu ",
213 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
d95cdcf5
PA
214
215 if (tb[LWTUNNEL_IP6_SRC])
216 fprintf(fp, "src %s ",
7faf1588 217 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
d95cdcf5
PA
218
219 if (tb[LWTUNNEL_IP6_DST])
220 fprintf(fp, "dst %s ",
7faf1588 221 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
d95cdcf5
PA
222
223 if (tb[LWTUNNEL_IP6_HOPLIMIT])
b723368c
SH
224 fprintf(fp, "hoplimit %d ",
225 rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
d95cdcf5
PA
226
227 if (tb[LWTUNNEL_IP6_TC])
228 fprintf(fp, "tc %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
229}
230
b15f440e
TG
231static 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
243static 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
1e529305
RP
259void 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
d95cdcf5 269 fprintf(fp, " encap %s ", format_encap_type(et));
1e529305
RP
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;
5866bddd
TH
278 case LWTUNNEL_ENCAP_ILA:
279 print_encap_ila(fp, encap);
280 break;
d95cdcf5
PA
281 case LWTUNNEL_ENCAP_IP6:
282 print_encap_ip6(fp, encap);
283 break;
b15f440e
TG
284 case LWTUNNEL_ENCAP_BPF:
285 print_encap_bpf(fp, encap);
286 break;
e8493916
DL
287 case LWTUNNEL_ENCAP_SEG6:
288 print_encap_seg6(fp, encap);
289 break;
290 }
291}
292
293static 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);
1e529305 383 }
e8493916
DL
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;
1e529305
RP
393}
394
b723368c
SH
395static int parse_encap_mpls(struct rtattr *rta, size_t len,
396 int *argcp, char ***argvp)
1e529305
RP
397{
398 inet_prefix addr;
399 int argc = *argcp;
400 char **argv = *argvp;
9688cf3b 401 int ttl_ok = 0;
1e529305
RP
402
403 if (get_addr(&addr, *argv, AF_MPLS)) {
b723368c
SH
404 fprintf(stderr,
405 "Error: an inet address is expected rather than \"%s\".\n",
406 *argv);
1e529305
RP
407 exit(1);
408 }
409
410 rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data,
411 addr.bytelen);
412
9688cf3b
RS
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;
1e529305
RP
438
439 return 0;
440}
441
b723368c
SH
442static int parse_encap_ip(struct rtattr *rta, size_t len,
443 int *argcp, char ***argvp)
1e529305
RP
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;
56f5daac 452
1e529305
RP
453 NEXT_ARG();
454 if (id_ok++)
455 duparg2("id", *argv);
9f7401fa 456 if (get_be64(&id, *argv, 0))
1e529305 457 invarg("\"id\" value is invalid\n", *argv);
9f7401fa 458 rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
1e529305
RP
459 } else if (strcmp(*argv, "dst") == 0) {
460 inet_prefix addr;
56f5daac 461
1e529305
RP
462 NEXT_ARG();
463 if (dst_ok++)
464 duparg2("dst", *argv);
465 get_addr(&addr, *argv, AF_INET);
b723368c
SH
466 rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
467 &addr.data, addr.bytelen);
1e529305
RP
468 } else if (strcmp(*argv, "tos") == 0) {
469 __u32 tos;
56f5daac 470
1e529305
RP
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;
56f5daac 479
1e529305
RP
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 }
f0df4081 489 argc--; argv++;
1e529305
RP
490 }
491
f0df4081
PA
492 /* argv is currently the first unparsed argument,
493 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
494 * so step back
495 */
f0df4081
PA
496 *argcp = argc + 1;
497 *argvp = argv - 1;
1e529305
RP
498
499 return 0;
500}
501
5866bddd
TH
502static 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
ed67f838
TH
514 argc--; argv++;
515
5866bddd
TH
516 rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator);
517
ed67f838
TH
518 while (argc > 0) {
519 if (strcmp(*argv, "csum-mode") == 0) {
520 __u8 csum_mode;
521
522 NEXT_ARG();
523
524 csum_mode = ila_csum_name2mode(*argv);
525 if (csum_mode < 0)
b723368c
SH
526 invarg("\"csum-mode\" value is invalid\n",
527 *argv);
ed67f838
TH
528
529 rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE, csum_mode);
530
531 argc--; argv++;
532 } else {
533 break;
534 }
535 }
536
537 /* argv is currently the first unparsed argument,
538 * but the lwt_parse_encap() caller will move to the next,
539 * so step back
540 */
541 *argcp = argc + 1;
542 *argvp = argv - 1;
5866bddd
TH
543
544 return 0;
545}
1e529305 546
b723368c
SH
547static int parse_encap_ip6(struct rtattr *rta, size_t len,
548 int *argcp, char ***argvp)
d95cdcf5
PA
549{
550 int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
551 char **argv = *argvp;
552 int argc = *argcp;
553
554 while (argc > 0) {
555 if (strcmp(*argv, "id") == 0) {
556 __u64 id;
56f5daac 557
d95cdcf5
PA
558 NEXT_ARG();
559 if (id_ok++)
560 duparg2("id", *argv);
9f7401fa 561 if (get_be64(&id, *argv, 0))
d95cdcf5 562 invarg("\"id\" value is invalid\n", *argv);
9f7401fa 563 rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
d95cdcf5
PA
564 } else if (strcmp(*argv, "dst") == 0) {
565 inet_prefix addr;
56f5daac 566
d95cdcf5
PA
567 NEXT_ARG();
568 if (dst_ok++)
569 duparg2("dst", *argv);
570 get_addr(&addr, *argv, AF_INET6);
b723368c
SH
571 rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
572 &addr.data, addr.bytelen);
d95cdcf5
PA
573 } else if (strcmp(*argv, "tc") == 0) {
574 __u32 tc;
56f5daac 575
d95cdcf5
PA
576 NEXT_ARG();
577 if (tos_ok++)
578 duparg2("tc", *argv);
579 if (rtnl_dsfield_a2n(&tc, *argv))
580 invarg("\"tc\" value is invalid\n", *argv);
581 rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
582 } else if (strcmp(*argv, "hoplimit") == 0) {
583 __u8 hoplimit;
56f5daac 584
d95cdcf5
PA
585 NEXT_ARG();
586 if (ttl_ok++)
587 duparg2("hoplimit", *argv);
588 if (get_u8(&hoplimit, *argv, 0))
b723368c
SH
589 invarg("\"hoplimit\" value is invalid\n",
590 *argv);
d95cdcf5
PA
591 rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit);
592 } else {
593 break;
594 }
595 argc--; argv++;
596 }
597
598 /* argv is currently the first unparsed argument,
599 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
600 * so step back
601 */
d95cdcf5
PA
602 *argcp = argc + 1;
603 *argvp = argv - 1;
604
605 return 0;
606}
607
b15f440e
TG
608struct lwt_x {
609 struct rtattr *rta;
610 size_t len;
611};
612
613static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation)
614{
615 struct lwt_x *x = lwt_ptr;
616
617 rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd);
618 rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation,
619 strlen(annotation) + 1);
620}
621
622static const struct bpf_cfg_ops bpf_cb_ops = {
623 .ebpf_cb = bpf_lwt_cb,
624};
625
b723368c
SH
626static int lwt_parse_bpf(struct rtattr *rta, size_t len,
627 int *argcp, char ***argvp,
b15f440e
TG
628 int attr, const enum bpf_prog_type bpf_type)
629{
630 struct bpf_cfg_in cfg = {
631 .argc = *argcp,
632 .argv = *argvp,
633 };
634 struct lwt_x x = {
635 .rta = rta,
636 .len = len,
637 };
638 struct rtattr *nest;
639 int err;
640
641 nest = rta_nest(rta, len, attr);
642 err = bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, &x);
643 if (err < 0) {
b723368c
SH
644 fprintf(stderr, "Failed to parse eBPF program: %s\n",
645 strerror(err));
b15f440e
TG
646 return -1;
647 }
648 rta_nest_end(rta, nest);
649
650 *argcp = cfg.argc;
651 *argvp = cfg.argv;
652
653 return 0;
654}
655
656static void lwt_bpf_usage(void)
657{
658 fprintf(stderr, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
659 fprintf(stderr, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
660 exit(-1);
661}
662
663static int parse_encap_bpf(struct rtattr *rta, size_t len, int *argcp,
664 char ***argvp)
665{
666 char **argv = *argvp;
667 int argc = *argcp;
668 int headroom_set = 0;
669
670 while (argc > 0) {
671 if (strcmp(*argv, "in") == 0) {
672 NEXT_ARG();
673 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_IN,
674 BPF_PROG_TYPE_LWT_IN) < 0)
675 return -1;
676 } else if (strcmp(*argv, "out") == 0) {
677 NEXT_ARG();
678 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_OUT,
679 BPF_PROG_TYPE_LWT_OUT) < 0)
680 return -1;
681 } else if (strcmp(*argv, "xmit") == 0) {
682 NEXT_ARG();
683 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_XMIT,
684 BPF_PROG_TYPE_LWT_XMIT) < 0)
685 return -1;
686 } else if (strcmp(*argv, "headroom") == 0) {
687 unsigned int headroom;
688
689 NEXT_ARG();
690 if (get_unsigned(&headroom, *argv, 0) || headroom == 0)
691 invarg("headroom is invalid\n", *argv);
692 if (!headroom_set)
693 rta_addattr32(rta, 1024, LWT_BPF_XMIT_HEADROOM,
694 headroom);
695 headroom_set = 1;
696 } else if (strcmp(*argv, "help") == 0) {
697 lwt_bpf_usage();
698 } else {
699 break;
700 }
701 NEXT_ARG_FWD();
702 }
703
704 /* argv is currently the first unparsed argument,
705 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
706 * so step back
707 */
b15f440e
TG
708 *argcp = argc + 1;
709 *argvp = argv - 1;
710
711 return 0;
712}
713
1e529305
RP
714int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
715{
716 struct rtattr *nest;
717 int argc = *argcp;
718 char **argv = *argvp;
719 __u16 type;
720
721 NEXT_ARG();
722 type = read_encap_type(*argv);
723 if (!type)
724 invarg("\"encap type\" value is invalid\n", *argv);
725
726 NEXT_ARG();
727 if (argc <= 1) {
b723368c
SH
728 fprintf(stderr,
729 "Error: unexpected end of line after \"encap\"\n");
1e529305
RP
730 exit(-1);
731 }
732
733 nest = rta_nest(rta, 1024, RTA_ENCAP);
734 switch (type) {
735 case LWTUNNEL_ENCAP_MPLS:
736 parse_encap_mpls(rta, len, &argc, &argv);
737 break;
738 case LWTUNNEL_ENCAP_IP:
739 parse_encap_ip(rta, len, &argc, &argv);
740 break;
5866bddd
TH
741 case LWTUNNEL_ENCAP_ILA:
742 parse_encap_ila(rta, len, &argc, &argv);
743 break;
d95cdcf5
PA
744 case LWTUNNEL_ENCAP_IP6:
745 parse_encap_ip6(rta, len, &argc, &argv);
746 break;
b15f440e
TG
747 case LWTUNNEL_ENCAP_BPF:
748 if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
749 exit(-1);
750 break;
e8493916
DL
751 case LWTUNNEL_ENCAP_SEG6:
752 parse_encap_seg6(rta, len, &argc, &argv);
753 break;
1e529305
RP
754 default:
755 fprintf(stderr, "Error: unsupported encap type\n");
756 break;
757 }
758 rta_nest_end(rta, nest);
759
760 rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
761
762 *argcp = argc;
763 *argvp = argv;
764
765 return 0;
766}