]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iproute_lwtunnel.c
Merge branch 'hdrs-for-dump-req' into iproute2-next
[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"
b15f440e 25#include "bpf_util.h"
f7af0dc5
SP
26#include "utils.h"
27#include "ip_common.h"
010260a7 28#include "ila_common.h"
1e529305 29
e4319590
DL
30#include <linux/seg6.h>
31#include <linux/seg6_iptunnel.h>
32#include <linux/seg6_hmac.h>
8db158b9
DL
33#include <linux/seg6_local.h>
34#include <net/if.h>
e4319590 35
1e529305
RP
36static 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";
5866bddd
TH
45 case LWTUNNEL_ENCAP_ILA:
46 return "ila";
b15f440e
TG
47 case LWTUNNEL_ENCAP_BPF:
48 return "bpf";
e8493916
DL
49 case LWTUNNEL_ENCAP_SEG6:
50 return "seg6";
8db158b9
DL
51 case LWTUNNEL_ENCAP_SEG6_LOCAL:
52 return "seg6local";
1e529305
RP
53 default:
54 return "unknown";
55 }
56}
57
b15f440e
TG
58static 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
71static 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;
e8493916
DL
83 else if (strcmp(name, "seg6") == 0)
84 return LWTUNNEL_ENCAP_SEG6;
8db158b9
DL
85 else if (strcmp(name, "seg6local") == 0)
86 return LWTUNNEL_ENCAP_SEG6_LOCAL;
b15f440e
TG
87 else if (strcmp(name, "help") == 0)
88 encap_type_usage();
89
90 return LWTUNNEL_ENCAP_NONE;
91}
92
00e76d4d 93static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh)
e8493916 94{
e8493916
DL
95 int i;
96
663c3cb2
SH
97 if (is_json_context())
98 open_json_array(PRINT_JSON, "segs");
99 else
100 fprintf(fp, "segs %d [ ", srh->first_segment + 1);
e8493916
DL
101
102 for (i = srh->first_segment; i >= 0; i--)
663c3cb2
SH
103 print_color_string(PRINT_ANY, COLOR_INET6,
104 NULL, "%s ",
105 rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
e8493916 106
663c3cb2
SH
107 if (is_json_context())
108 close_json_array(PRINT_JSON, NULL);
109 else
110 fprintf(fp, "] ");
e8493916
DL
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);
663c3cb2
SH
117 print_0xhex(PRINT_ANY, "hmac",
118 "hmac 0x%X ", ntohl(tlv->hmackeyid));
e8493916
DL
119 }
120}
121
cf87da41
DL
122static 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
128static 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
136static 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
00e76d4d
DL
148static 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]);
663c3cb2
SH
159 print_string(PRINT_ANY, "mode",
160 "mode %s ", format_seg6mode_type(tuninfo->mode));
00e76d4d
DL
161
162 print_srh(fp, tuninfo->srh);
163}
164
8db158b9
DL
165static 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",
04cb3c0d 180 [SEG6_LOCAL_ACTION_END_BPF] = "End.BPF",
8db158b9
DL
181};
182
183static 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
191static 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
04cb3c0d
MX
206static 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
8db158b9
DL
227static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
228{
229 struct rtattr *tb[SEG6_LOCAL_MAX + 1];
8db158b9
DL
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
663c3cb2
SH
239 print_string(PRINT_ANY, "action",
240 "action %s ", format_action_type(action));
8db158b9
DL
241
242 if (tb[SEG6_LOCAL_SRH]) {
663c3cb2 243 open_json_object("srh");
8db158b9 244 print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH]));
663c3cb2 245 close_json_object();
8db158b9
DL
246 }
247
248 if (tb[SEG6_LOCAL_TABLE])
663c3cb2
SH
249 print_uint(PRINT_ANY, "table",
250 "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
8db158b9
DL
251
252 if (tb[SEG6_LOCAL_NH4]) {
663c3cb2
SH
253 print_string(PRINT_ANY, "nh4",
254 "nh4 %s ", rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4]));
8db158b9
DL
255 }
256
257 if (tb[SEG6_LOCAL_NH6]) {
663c3cb2
SH
258 print_string(PRINT_ANY, "nh6",
259 "nh6 %s ", rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6]));
8db158b9
DL
260 }
261
262 if (tb[SEG6_LOCAL_IIF]) {
263 int iif = rta_getattr_u32(tb[SEG6_LOCAL_IIF]);
264
663c3cb2
SH
265 print_string(PRINT_ANY, "iif",
266 "iif %s ", ll_index_to_name(iif));
8db158b9
DL
267 }
268
269 if (tb[SEG6_LOCAL_OIF]) {
270 int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]);
271
663c3cb2
SH
272 print_string(PRINT_ANY, "oif",
273 "oif %s ", ll_index_to_name(oif));
8db158b9 274 }
04cb3c0d
MX
275
276 if (tb[SEG6_LOCAL_BPF])
277 print_encap_bpf_prog(fp, tb[SEG6_LOCAL_BPF], "endpoint");
8db158b9
DL
278}
279
1e529305
RP
280static void print_encap_mpls(FILE *fp, struct rtattr *encap)
281{
282 struct rtattr *tb[MPLS_IPTUNNEL_MAX+1];
1e529305
RP
283
284 parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
285
286 if (tb[MPLS_IPTUNNEL_DST])
663c3cb2 287 print_string(PRINT_ANY, "dst", " %s ",
b723368c 288 format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST]));
9688cf3b 289 if (tb[MPLS_IPTUNNEL_TTL])
663c3cb2 290 print_uint(PRINT_ANY, "ttl", "ttl %u ",
9688cf3b 291 rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
1e529305
RP
292}
293
294static void print_encap_ip(FILE *fp, struct rtattr *encap)
295{
296 struct rtattr *tb[LWTUNNEL_IP_MAX+1];
1e529305
RP
297
298 parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
299
300 if (tb[LWTUNNEL_IP_ID])
4db2ff0d 301 print_u64(PRINT_ANY, "id", "id %llu ",
663c3cb2 302 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
1e529305
RP
303
304 if (tb[LWTUNNEL_IP_SRC])
663c3cb2
SH
305 print_color_string(PRINT_ANY, COLOR_INET,
306 "src", "src %s ",
307 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
1e529305
RP
308
309 if (tb[LWTUNNEL_IP_DST])
663c3cb2
SH
310 print_color_string(PRINT_ANY, COLOR_INET,
311 "dst", "dst %s ",
312 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
1e529305
RP
313
314 if (tb[LWTUNNEL_IP_TTL])
663c3cb2
SH
315 print_uint(PRINT_ANY, "ttl",
316 "ttl %u ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
1e529305
RP
317
318 if (tb[LWTUNNEL_IP_TOS])
663c3cb2
SH
319 print_uint(PRINT_ANY, "tos",
320 "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
1e529305
RP
321}
322
5866bddd
TH
323static 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
9f1370c0 332 addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
5866bddd 333 abuf, sizeof(abuf));
663c3cb2
SH
334 print_string(PRINT_ANY, "locator",
335 " %s ", abuf);
5866bddd 336 }
ed67f838
TH
337
338 if (tb[ILA_ATTR_CSUM_MODE])
663c3cb2
SH
339 print_string(PRINT_ANY, "csum_mode",
340 " csum-mode %s ",
341 ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE])));
86905c8f
TH
342
343 if (tb[ILA_ATTR_IDENT_TYPE])
663c3cb2
SH
344 print_string(PRINT_ANY, "ident_type",
345 " ident-type %s ",
346 ila_ident_type2name(rta_getattr_u8(tb[ILA_ATTR_IDENT_TYPE])));
86905c8f
TH
347
348 if (tb[ILA_ATTR_HOOK_TYPE])
663c3cb2
SH
349 print_string(PRINT_ANY, "hook_type",
350 " hook-type %s ",
351 ila_hook_type2name(rta_getattr_u8(tb[ILA_ATTR_HOOK_TYPE])));
5866bddd
TH
352}
353
d95cdcf5
PA
354static void print_encap_ip6(FILE *fp, struct rtattr *encap)
355{
356 struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
d95cdcf5
PA
357
358 parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
359
360 if (tb[LWTUNNEL_IP6_ID])
4db2ff0d 361 print_u64(PRINT_ANY, "id", "id %llu ",
663c3cb2 362 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
d95cdcf5
PA
363
364 if (tb[LWTUNNEL_IP6_SRC])
663c3cb2
SH
365 print_color_string(PRINT_ANY, COLOR_INET6,
366 "src", "src %s ",
367 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
d95cdcf5
PA
368
369 if (tb[LWTUNNEL_IP6_DST])
663c3cb2
SH
370 print_color_string(PRINT_ANY, COLOR_INET6,
371 "dst", "dst %s ",
372 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
d95cdcf5
PA
373
374 if (tb[LWTUNNEL_IP6_HOPLIMIT])
4db2ff0d 375 print_u64(PRINT_ANY, "hoplimit",
663c3cb2
SH
376 "hoplimit %u ",
377 rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
d95cdcf5
PA
378
379 if (tb[LWTUNNEL_IP6_TC])
663c3cb2
SH
380 print_uint(PRINT_ANY, "tc",
381 "tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
d95cdcf5
PA
382}
383
b15f440e
TG
384static 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])
663c3cb2
SH
397 print_uint(PRINT_ANY, "headroom",
398 " %u ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
b15f440e
TG
399}
400
1e529305
RP
401void 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
663c3cb2 411 print_string(PRINT_ANY, "encap", " encap %s ", format_encap_type(et));
1e529305
RP
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;
5866bddd
TH
420 case LWTUNNEL_ENCAP_ILA:
421 print_encap_ila(fp, encap);
422 break;
d95cdcf5
PA
423 case LWTUNNEL_ENCAP_IP6:
424 print_encap_ip6(fp, encap);
425 break;
b15f440e
TG
426 case LWTUNNEL_ENCAP_BPF:
427 print_encap_bpf(fp, encap);
428 break;
e8493916
DL
429 case LWTUNNEL_ENCAP_SEG6:
430 print_encap_seg6(fp, encap);
431 break;
8db158b9
DL
432 case LWTUNNEL_ENCAP_SEG6_LOCAL:
433 print_encap_seg6local(fp, encap);
434 break;
e8493916
DL
435 }
436}
437
00e76d4d
DL
438static 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, ",")) {
6caad8f5
SP
471 inet_prefix addr;
472
473 get_addr(&addr, s, AF_INET6);
474 memcpy(&srh->segments[i], addr.data, sizeof(struct in6_addr));
00e76d4d
DL
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
e8493916
DL
490static 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;
e8493916 501 int srhlen;
e8493916
DL
502
503 while (argc > 0) {
504 if (strcmp(*argv, "mode") == 0) {
505 NEXT_ARG();
506 if (mode_ok++)
507 duparg2("mode", *argv);
cf87da41
DL
508 encap = read_seg6mode_type(*argv);
509 if (encap < 0)
e8493916
DL
510 invarg("\"mode\" value is invalid\n", *argv);
511 } else if (strcmp(*argv, "segs") == 0) {
512 NEXT_ARG();
513 if (segs_ok++)
514 duparg2("segs", *argv);
515 if (encap == -1)
516 invarg("\"segs\" provided before \"mode\"\n",
517 *argv);
518
18f156bf 519 strlcpy(segbuf, *argv, 1024);
e8493916
DL
520 } else if (strcmp(*argv, "hmac") == 0) {
521 NEXT_ARG();
522 if (hmac_ok++)
523 duparg2("hmac", *argv);
524 get_u32(&hmac, *argv, 0);
525 } else {
526 break;
527 }
528 argc--; argv++;
529 }
530
00e76d4d
DL
531 srh = parse_srh(segbuf, hmac, encap);
532 srhlen = (srh->hdrlen + 1) << 3;
e8493916
DL
533
534 tuninfo = malloc(sizeof(*tuninfo) + srhlen);
535 memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
536
cf87da41 537 tuninfo->mode = encap;
e8493916 538
00e76d4d 539 memcpy(tuninfo->srh, srh, srhlen);
e8493916 540
bd59e5b1
PS
541 if (rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
542 sizeof(*tuninfo) + srhlen))
543 return -1;
00e76d4d 544
e8493916 545 free(tuninfo);
00e76d4d 546 free(srh);
e8493916
DL
547
548 *argcp = argc + 1;
549 *argvp = argv - 1;
550
551 return 0;
1e529305
RP
552}
553
04cb3c0d
MX
554struct lwt_x {
555 struct rtattr *rta;
556 size_t len;
557};
558
559static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation)
560{
561 struct lwt_x *x = lwt_ptr;
562
563 rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd);
564 rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation,
565 strlen(annotation) + 1);
566}
567
568static const struct bpf_cfg_ops bpf_cb_ops = {
569 .ebpf_cb = bpf_lwt_cb,
570};
571
572static int lwt_parse_bpf(struct rtattr *rta, size_t len,
573 int *argcp, char ***argvp,
574 int attr, const enum bpf_prog_type bpf_type)
575{
576 struct bpf_cfg_in cfg = {
577 .type = bpf_type,
578 .argc = *argcp,
579 .argv = *argvp,
580 };
581 struct lwt_x x = {
582 .rta = rta,
583 .len = len,
584 };
585 struct rtattr *nest;
586 int err;
587
588 nest = rta_nest(rta, len, attr);
589 err = bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &x);
590 if (err < 0) {
591 fprintf(stderr, "Failed to parse eBPF program: %s\n",
592 strerror(-err));
593 return -1;
594 }
595 rta_nest_end(rta, nest);
596
597 *argcp = cfg.argc;
598 *argvp = cfg.argv;
599
600 return 0;
601}
602
8db158b9
DL
603static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
604 char ***argvp)
605{
606 int segs_ok = 0, hmac_ok = 0, table_ok = 0, nh4_ok = 0, nh6_ok = 0;
04cb3c0d 607 int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0, bpf_ok = 0;
8db158b9
DL
608 __u32 action = 0, table, iif, oif;
609 struct ipv6_sr_hdr *srh;
610 char **argv = *argvp;
611 int argc = *argcp;
612 char segbuf[1024];
613 inet_prefix addr;
614 __u32 hmac = 0;
bd59e5b1 615 int ret = 0;
8db158b9
DL
616
617 while (argc > 0) {
618 if (strcmp(*argv, "action") == 0) {
619 NEXT_ARG();
620 if (action_ok++)
621 duparg2("action", *argv);
622 action = read_action_type(*argv);
623 if (!action)
624 invarg("\"action\" value is invalid\n", *argv);
bd59e5b1
PS
625 ret = rta_addattr32(rta, len, SEG6_LOCAL_ACTION,
626 action);
8db158b9
DL
627 } else if (strcmp(*argv, "table") == 0) {
628 NEXT_ARG();
629 if (table_ok++)
630 duparg2("table", *argv);
631 get_u32(&table, *argv, 0);
bd59e5b1 632 ret = rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
8db158b9
DL
633 } else if (strcmp(*argv, "nh4") == 0) {
634 NEXT_ARG();
635 if (nh4_ok++)
636 duparg2("nh4", *argv);
637 get_addr(&addr, *argv, AF_INET);
bd59e5b1
PS
638 ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH4,
639 &addr.data, addr.bytelen);
8db158b9
DL
640 } else if (strcmp(*argv, "nh6") == 0) {
641 NEXT_ARG();
642 if (nh6_ok++)
643 duparg2("nh6", *argv);
644 get_addr(&addr, *argv, AF_INET6);
bd59e5b1
PS
645 ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH6,
646 &addr.data, addr.bytelen);
8db158b9
DL
647 } else if (strcmp(*argv, "iif") == 0) {
648 NEXT_ARG();
649 if (iif_ok++)
650 duparg2("iif", *argv);
7a14358b 651 iif = ll_name_to_index(*argv);
8db158b9 652 if (!iif)
fe99adbc 653 exit(nodev(*argv));
bd59e5b1 654 ret = rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
8db158b9
DL
655 } else if (strcmp(*argv, "oif") == 0) {
656 NEXT_ARG();
657 if (oif_ok++)
658 duparg2("oif", *argv);
7a14358b 659 oif = ll_name_to_index(*argv);
8db158b9 660 if (!oif)
fe99adbc 661 exit(nodev(*argv));
bd59e5b1 662 ret = rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
8db158b9
DL
663 } else if (strcmp(*argv, "srh") == 0) {
664 NEXT_ARG();
665 if (srh_ok++)
666 duparg2("srh", *argv);
667 if (strcmp(*argv, "segs") != 0)
668 invarg("missing \"segs\" attribute for srh\n",
669 *argv);
670 NEXT_ARG();
671 if (segs_ok++)
672 duparg2("segs", *argv);
673 strncpy(segbuf, *argv, 1024);
674 segbuf[1023] = 0;
675 if (!NEXT_ARG_OK())
676 break;
677 NEXT_ARG();
678 if (strcmp(*argv, "hmac") == 0) {
679 NEXT_ARG();
680 if (hmac_ok++)
681 duparg2("hmac", *argv);
682 get_u32(&hmac, *argv, 0);
683 } else {
684 continue;
685 }
04cb3c0d
MX
686 } else if (strcmp(*argv, "endpoint") == 0) {
687 NEXT_ARG();
688 if (bpf_ok++)
689 duparg2("endpoint", *argv);
690
691 if (lwt_parse_bpf(rta, len, &argc, &argv, SEG6_LOCAL_BPF,
692 BPF_PROG_TYPE_LWT_SEG6LOCAL) < 0)
693 exit(-1);
8db158b9
DL
694 } else {
695 break;
696 }
bd59e5b1
PS
697 if (ret)
698 return ret;
8db158b9
DL
699 argc--; argv++;
700 }
701
702 if (!action) {
703 fprintf(stderr, "Missing action type\n");
704 exit(-1);
705 }
706
707 if (srh_ok) {
708 int srhlen;
709
710 srh = parse_srh(segbuf, hmac,
711 action == SEG6_LOCAL_ACTION_END_B6_ENCAP);
712 srhlen = (srh->hdrlen + 1) << 3;
bd59e5b1 713 ret = rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
8db158b9
DL
714 free(srh);
715 }
716
717 *argcp = argc + 1;
718 *argvp = argv - 1;
719
bd59e5b1 720 return ret;
8db158b9
DL
721}
722
b723368c
SH
723static int parse_encap_mpls(struct rtattr *rta, size_t len,
724 int *argcp, char ***argvp)
1e529305
RP
725{
726 inet_prefix addr;
727 int argc = *argcp;
728 char **argv = *argvp;
9688cf3b 729 int ttl_ok = 0;
1e529305
RP
730
731 if (get_addr(&addr, *argv, AF_MPLS)) {
b723368c
SH
732 fprintf(stderr,
733 "Error: an inet address is expected rather than \"%s\".\n",
734 *argv);
1e529305
RP
735 exit(1);
736 }
737
bd59e5b1
PS
738 if (rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST,
739 &addr.data, addr.bytelen))
740 return -1;
1e529305 741
9688cf3b
RS
742 argc--;
743 argv++;
744
745 while (argc > 0) {
746 if (strcmp(*argv, "ttl") == 0) {
747 __u8 ttl;
748
749 NEXT_ARG();
750 if (ttl_ok++)
751 duparg2("ttl", *argv);
752 if (get_u8(&ttl, *argv, 0))
753 invarg("\"ttl\" value is invalid\n", *argv);
bd59e5b1
PS
754 if (rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl))
755 return -1;
9688cf3b
RS
756 } else {
757 break;
758 }
759 argc--; argv++;
760 }
761
762 /* argv is currently the first unparsed argument,
763 * but the lwt_parse_encap() caller will move to the next,
764 * so step back
765 */
766 *argcp = argc + 1;
767 *argvp = argv - 1;
1e529305
RP
768
769 return 0;
770}
771
b723368c
SH
772static int parse_encap_ip(struct rtattr *rta, size_t len,
773 int *argcp, char ***argvp)
1e529305 774{
94a8722f 775 int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
1e529305
RP
776 char **argv = *argvp;
777 int argc = *argcp;
bd59e5b1 778 int ret = 0;
1e529305
RP
779
780 while (argc > 0) {
781 if (strcmp(*argv, "id") == 0) {
782 __u64 id;
56f5daac 783
1e529305
RP
784 NEXT_ARG();
785 if (id_ok++)
786 duparg2("id", *argv);
9f7401fa 787 if (get_be64(&id, *argv, 0))
1e529305 788 invarg("\"id\" value is invalid\n", *argv);
bd59e5b1 789 ret = rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
1e529305
RP
790 } else if (strcmp(*argv, "dst") == 0) {
791 inet_prefix addr;
56f5daac 792
1e529305
RP
793 NEXT_ARG();
794 if (dst_ok++)
795 duparg2("dst", *argv);
796 get_addr(&addr, *argv, AF_INET);
bd59e5b1
PS
797 ret = rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
798 &addr.data, addr.bytelen);
94a8722f
SL
799 } else if (strcmp(*argv, "src") == 0) {
800 inet_prefix addr;
801
802 NEXT_ARG();
803 if (src_ok++)
804 duparg2("src", *argv);
805 get_addr(&addr, *argv, AF_INET);
34212c73
DA
806 ret = rta_addattr_l(rta, len, LWTUNNEL_IP_SRC,
807 &addr.data, addr.bytelen);
1e529305
RP
808 } else if (strcmp(*argv, "tos") == 0) {
809 __u32 tos;
56f5daac 810
1e529305
RP
811 NEXT_ARG();
812 if (tos_ok++)
813 duparg2("tos", *argv);
814 if (rtnl_dsfield_a2n(&tos, *argv))
815 invarg("\"tos\" value is invalid\n", *argv);
bd59e5b1 816 ret = rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
1e529305
RP
817 } else if (strcmp(*argv, "ttl") == 0) {
818 __u8 ttl;
56f5daac 819
1e529305
RP
820 NEXT_ARG();
821 if (ttl_ok++)
822 duparg2("ttl", *argv);
823 if (get_u8(&ttl, *argv, 0))
824 invarg("\"ttl\" value is invalid\n", *argv);
bd59e5b1 825 ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
1e529305
RP
826 } else {
827 break;
828 }
bd59e5b1
PS
829 if (ret)
830 break;
f0df4081 831 argc--; argv++;
1e529305
RP
832 }
833
f0df4081
PA
834 /* argv is currently the first unparsed argument,
835 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
836 * so step back
837 */
f0df4081
PA
838 *argcp = argc + 1;
839 *argvp = argv - 1;
1e529305 840
bd59e5b1 841 return ret;
1e529305
RP
842}
843
5866bddd
TH
844static int parse_encap_ila(struct rtattr *rta, size_t len,
845 int *argcp, char ***argvp)
846{
847 __u64 locator;
848 int argc = *argcp;
849 char **argv = *argvp;
bd59e5b1 850 int ret = 0;
5866bddd
TH
851
852 if (get_addr64(&locator, *argv) < 0) {
853 fprintf(stderr, "Bad locator: %s\n", *argv);
854 exit(1);
855 }
856
ed67f838
TH
857 argc--; argv++;
858
bd59e5b1
PS
859 if (rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator))
860 return -1;
5866bddd 861
ed67f838
TH
862 while (argc > 0) {
863 if (strcmp(*argv, "csum-mode") == 0) {
08806fb0 864 int csum_mode;
ed67f838
TH
865
866 NEXT_ARG();
867
868 csum_mode = ila_csum_name2mode(*argv);
869 if (csum_mode < 0)
b723368c
SH
870 invarg("\"csum-mode\" value is invalid\n",
871 *argv);
ed67f838 872
bd59e5b1
PS
873 ret = rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
874 (__u8)csum_mode);
ed67f838 875
86905c8f
TH
876 argc--; argv++;
877 } else if (strcmp(*argv, "ident-type") == 0) {
878 int ident_type;
879
880 NEXT_ARG();
881
882 ident_type = ila_ident_name2type(*argv);
883 if (ident_type < 0)
884 invarg("\"ident-type\" value is invalid\n",
885 *argv);
886
bd59e5b1
PS
887 ret = rta_addattr8(rta, 1024, ILA_ATTR_IDENT_TYPE,
888 (__u8)ident_type);
86905c8f
TH
889
890 argc--; argv++;
891 } else if (strcmp(*argv, "hook-type") == 0) {
892 int hook_type;
893
894 NEXT_ARG();
895
896 hook_type = ila_hook_name2type(*argv);
897 if (hook_type < 0)
898 invarg("\"hook-type\" value is invalid\n",
899 *argv);
900
bd59e5b1
PS
901 ret = rta_addattr8(rta, 1024, ILA_ATTR_HOOK_TYPE,
902 (__u8)hook_type);
86905c8f 903
ed67f838
TH
904 argc--; argv++;
905 } else {
906 break;
907 }
bd59e5b1
PS
908 if (ret)
909 break;
ed67f838
TH
910 }
911
912 /* argv is currently the first unparsed argument,
913 * but the lwt_parse_encap() caller will move to the next,
914 * so step back
915 */
916 *argcp = argc + 1;
917 *argvp = argv - 1;
5866bddd 918
bd59e5b1 919 return ret;
5866bddd 920}
1e529305 921
b723368c
SH
922static int parse_encap_ip6(struct rtattr *rta, size_t len,
923 int *argcp, char ***argvp)
d95cdcf5 924{
94a8722f 925 int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
d95cdcf5
PA
926 char **argv = *argvp;
927 int argc = *argcp;
bd59e5b1 928 int ret = 0;
d95cdcf5
PA
929
930 while (argc > 0) {
931 if (strcmp(*argv, "id") == 0) {
932 __u64 id;
56f5daac 933
d95cdcf5
PA
934 NEXT_ARG();
935 if (id_ok++)
936 duparg2("id", *argv);
9f7401fa 937 if (get_be64(&id, *argv, 0))
d95cdcf5 938 invarg("\"id\" value is invalid\n", *argv);
bd59e5b1 939 ret = rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
d95cdcf5
PA
940 } else if (strcmp(*argv, "dst") == 0) {
941 inet_prefix addr;
56f5daac 942
d95cdcf5
PA
943 NEXT_ARG();
944 if (dst_ok++)
945 duparg2("dst", *argv);
946 get_addr(&addr, *argv, AF_INET6);
bd59e5b1
PS
947 ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
948 &addr.data, addr.bytelen);
94a8722f
SL
949 } else if (strcmp(*argv, "src") == 0) {
950 inet_prefix addr;
951
952 NEXT_ARG();
953 if (src_ok++)
954 duparg2("src", *argv);
955 get_addr(&addr, *argv, AF_INET6);
34212c73
DA
956 ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_SRC,
957 &addr.data, addr.bytelen);
d95cdcf5
PA
958 } else if (strcmp(*argv, "tc") == 0) {
959 __u32 tc;
56f5daac 960
d95cdcf5
PA
961 NEXT_ARG();
962 if (tos_ok++)
963 duparg2("tc", *argv);
964 if (rtnl_dsfield_a2n(&tc, *argv))
965 invarg("\"tc\" value is invalid\n", *argv);
bd59e5b1 966 ret = rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
d95cdcf5
PA
967 } else if (strcmp(*argv, "hoplimit") == 0) {
968 __u8 hoplimit;
56f5daac 969
d95cdcf5
PA
970 NEXT_ARG();
971 if (ttl_ok++)
972 duparg2("hoplimit", *argv);
973 if (get_u8(&hoplimit, *argv, 0))
b723368c
SH
974 invarg("\"hoplimit\" value is invalid\n",
975 *argv);
bd59e5b1
PS
976 ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
977 hoplimit);
d95cdcf5
PA
978 } else {
979 break;
980 }
bd59e5b1
PS
981 if (ret)
982 break;
d95cdcf5
PA
983 argc--; argv++;
984 }
985
986 /* argv is currently the first unparsed argument,
987 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
988 * so step back
989 */
d95cdcf5
PA
990 *argcp = argc + 1;
991 *argvp = argv - 1;
992
bd59e5b1 993 return ret;
d95cdcf5
PA
994}
995
b15f440e
TG
996static void lwt_bpf_usage(void)
997{
998 fprintf(stderr, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
999 fprintf(stderr, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
1000 exit(-1);
1001}
1002
1003static int parse_encap_bpf(struct rtattr *rta, size_t len, int *argcp,
1004 char ***argvp)
1005{
1006 char **argv = *argvp;
1007 int argc = *argcp;
1008 int headroom_set = 0;
1009
1010 while (argc > 0) {
1011 if (strcmp(*argv, "in") == 0) {
1012 NEXT_ARG();
1013 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_IN,
1014 BPF_PROG_TYPE_LWT_IN) < 0)
1015 return -1;
1016 } else if (strcmp(*argv, "out") == 0) {
1017 NEXT_ARG();
1018 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_OUT,
1019 BPF_PROG_TYPE_LWT_OUT) < 0)
1020 return -1;
1021 } else if (strcmp(*argv, "xmit") == 0) {
1022 NEXT_ARG();
1023 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_XMIT,
1024 BPF_PROG_TYPE_LWT_XMIT) < 0)
1025 return -1;
1026 } else if (strcmp(*argv, "headroom") == 0) {
1027 unsigned int headroom;
1028
1029 NEXT_ARG();
1030 if (get_unsigned(&headroom, *argv, 0) || headroom == 0)
1031 invarg("headroom is invalid\n", *argv);
1032 if (!headroom_set)
1033 rta_addattr32(rta, 1024, LWT_BPF_XMIT_HEADROOM,
1034 headroom);
1035 headroom_set = 1;
1036 } else if (strcmp(*argv, "help") == 0) {
1037 lwt_bpf_usage();
1038 } else {
1039 break;
1040 }
1041 NEXT_ARG_FWD();
1042 }
1043
1044 /* argv is currently the first unparsed argument,
1045 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
1046 * so step back
1047 */
b15f440e
TG
1048 *argcp = argc + 1;
1049 *argvp = argv - 1;
1050
1051 return 0;
1052}
1053
1e529305
RP
1054int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
1055{
1056 struct rtattr *nest;
1057 int argc = *argcp;
1058 char **argv = *argvp;
1059 __u16 type;
bd59e5b1 1060 int ret = 0;
1e529305
RP
1061
1062 NEXT_ARG();
1063 type = read_encap_type(*argv);
1064 if (!type)
1065 invarg("\"encap type\" value is invalid\n", *argv);
1066
1067 NEXT_ARG();
1068 if (argc <= 1) {
b723368c
SH
1069 fprintf(stderr,
1070 "Error: unexpected end of line after \"encap\"\n");
1e529305
RP
1071 exit(-1);
1072 }
1073
1074 nest = rta_nest(rta, 1024, RTA_ENCAP);
1075 switch (type) {
1076 case LWTUNNEL_ENCAP_MPLS:
bd59e5b1 1077 ret = parse_encap_mpls(rta, len, &argc, &argv);
1e529305
RP
1078 break;
1079 case LWTUNNEL_ENCAP_IP:
bd59e5b1 1080 ret = parse_encap_ip(rta, len, &argc, &argv);
1e529305 1081 break;
5866bddd 1082 case LWTUNNEL_ENCAP_ILA:
bd59e5b1 1083 ret = parse_encap_ila(rta, len, &argc, &argv);
5866bddd 1084 break;
d95cdcf5 1085 case LWTUNNEL_ENCAP_IP6:
bd59e5b1 1086 ret = parse_encap_ip6(rta, len, &argc, &argv);
d95cdcf5 1087 break;
b15f440e
TG
1088 case LWTUNNEL_ENCAP_BPF:
1089 if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
1090 exit(-1);
1091 break;
e8493916 1092 case LWTUNNEL_ENCAP_SEG6:
bd59e5b1 1093 ret = parse_encap_seg6(rta, len, &argc, &argv);
e8493916 1094 break;
8db158b9 1095 case LWTUNNEL_ENCAP_SEG6_LOCAL:
bd59e5b1 1096 ret = parse_encap_seg6local(rta, len, &argc, &argv);
8db158b9 1097 break;
1e529305
RP
1098 default:
1099 fprintf(stderr, "Error: unsupported encap type\n");
1100 break;
1101 }
bd59e5b1
PS
1102 if (ret)
1103 return ret;
1104
1e529305
RP
1105 rta_nest_end(rta, nest);
1106
bd59e5b1 1107 ret = rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
1e529305
RP
1108
1109 *argcp = argc;
1110 *argvp = argv;
1111
bd59e5b1 1112 return ret;
1e529305 1113}