]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iproute_lwtunnel.c
5.10.0
[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>
9f91f1b7
AA
32#include <linux/rpl.h>
33#include <linux/rpl_iptunnel.h>
e4319590 34#include <linux/seg6_hmac.h>
8db158b9 35#include <linux/seg6_local.h>
3d65cefb 36#include <linux/if_tunnel.h>
e4319590 37
1e529305
RP
38static const char *format_encap_type(int type)
39{
40 switch (type) {
41 case LWTUNNEL_ENCAP_MPLS:
42 return "mpls";
43 case LWTUNNEL_ENCAP_IP:
44 return "ip";
45 case LWTUNNEL_ENCAP_IP6:
46 return "ip6";
5866bddd
TH
47 case LWTUNNEL_ENCAP_ILA:
48 return "ila";
b15f440e
TG
49 case LWTUNNEL_ENCAP_BPF:
50 return "bpf";
e8493916
DL
51 case LWTUNNEL_ENCAP_SEG6:
52 return "seg6";
8db158b9
DL
53 case LWTUNNEL_ENCAP_SEG6_LOCAL:
54 return "seg6local";
9f91f1b7
AA
55 case LWTUNNEL_ENCAP_RPL:
56 return "rpl";
1e529305
RP
57 default:
58 return "unknown";
59 }
60}
61
b15f440e
TG
62static void encap_type_usage(void)
63{
64 int i;
65
66 fprintf(stderr, "Usage: ip route ... encap TYPE [ OPTIONS ] [...]\n");
67
68 for (i = 1; i <= LWTUNNEL_ENCAP_MAX; i++)
69 fprintf(stderr, "%s %s\n", format_encap_type(i),
70 i == 1 ? "TYPE := " : " ");
71
72 exit(-1);
73}
74
75static int read_encap_type(const char *name)
76{
77 if (strcmp(name, "mpls") == 0)
78 return LWTUNNEL_ENCAP_MPLS;
79 else if (strcmp(name, "ip") == 0)
80 return LWTUNNEL_ENCAP_IP;
81 else if (strcmp(name, "ip6") == 0)
82 return LWTUNNEL_ENCAP_IP6;
83 else if (strcmp(name, "ila") == 0)
84 return LWTUNNEL_ENCAP_ILA;
85 else if (strcmp(name, "bpf") == 0)
86 return LWTUNNEL_ENCAP_BPF;
e8493916
DL
87 else if (strcmp(name, "seg6") == 0)
88 return LWTUNNEL_ENCAP_SEG6;
8db158b9
DL
89 else if (strcmp(name, "seg6local") == 0)
90 return LWTUNNEL_ENCAP_SEG6_LOCAL;
9f91f1b7
AA
91 else if (strcmp(name, "rpl") == 0)
92 return LWTUNNEL_ENCAP_RPL;
b15f440e
TG
93 else if (strcmp(name, "help") == 0)
94 encap_type_usage();
95
96 return LWTUNNEL_ENCAP_NONE;
97}
98
00e76d4d 99static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh)
e8493916 100{
e8493916
DL
101 int i;
102
663c3cb2
SH
103 if (is_json_context())
104 open_json_array(PRINT_JSON, "segs");
105 else
106 fprintf(fp, "segs %d [ ", srh->first_segment + 1);
e8493916
DL
107
108 for (i = srh->first_segment; i >= 0; i--)
663c3cb2
SH
109 print_color_string(PRINT_ANY, COLOR_INET6,
110 NULL, "%s ",
111 rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
e8493916 112
663c3cb2
SH
113 if (is_json_context())
114 close_json_array(PRINT_JSON, NULL);
115 else
116 fprintf(fp, "] ");
e8493916
DL
117
118 if (sr_has_hmac(srh)) {
119 unsigned int offset = ((srh->hdrlen + 1) << 3) - 40;
120 struct sr6_tlv_hmac *tlv;
121
122 tlv = (struct sr6_tlv_hmac *)((char *)srh + offset);
663c3cb2 123 print_0xhex(PRINT_ANY, "hmac",
90c5c969 124 "hmac %llX ", ntohl(tlv->hmackeyid));
e8493916
DL
125 }
126}
127
cf87da41
DL
128static const char *seg6_mode_types[] = {
129 [SEG6_IPTUN_MODE_INLINE] = "inline",
130 [SEG6_IPTUN_MODE_ENCAP] = "encap",
131 [SEG6_IPTUN_MODE_L2ENCAP] = "l2encap",
132};
133
134static const char *format_seg6mode_type(int mode)
135{
136 if (mode < 0 || mode > ARRAY_SIZE(seg6_mode_types))
137 return "<unknown>";
138
139 return seg6_mode_types[mode];
140}
141
142static int read_seg6mode_type(const char *mode)
143{
144 int i;
145
146 for (i = 0; i < ARRAY_SIZE(seg6_mode_types); i++) {
147 if (strcmp(mode, seg6_mode_types[i]) == 0)
148 return i;
149 }
150
151 return -1;
152}
153
00e76d4d
DL
154static void print_encap_seg6(FILE *fp, struct rtattr *encap)
155{
156 struct rtattr *tb[SEG6_IPTUNNEL_MAX+1];
157 struct seg6_iptunnel_encap *tuninfo;
158
159 parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap);
160
161 if (!tb[SEG6_IPTUNNEL_SRH])
162 return;
163
164 tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]);
663c3cb2
SH
165 print_string(PRINT_ANY, "mode",
166 "mode %s ", format_seg6mode_type(tuninfo->mode));
00e76d4d
DL
167
168 print_srh(fp, tuninfo->srh);
169}
170
9f91f1b7
AA
171static void print_rpl_srh(FILE *fp, struct ipv6_rpl_sr_hdr *srh)
172{
173 int i;
174
175 if (is_json_context())
176 open_json_array(PRINT_JSON, "segs");
177 else
178 fprintf(fp, "segs %d [ ", srh->segments_left);
179
180 for (i = srh->segments_left - 1; i >= 0; i--) {
181 print_color_string(PRINT_ANY, COLOR_INET6,
182 NULL, "%s ",
183 rt_addr_n2a(AF_INET6, 16, &srh->rpl_segaddr[i]));
184 }
185
186 if (is_json_context())
187 close_json_array(PRINT_JSON, NULL);
188 else
189 fprintf(fp, "] ");
190}
191
192static void print_encap_rpl(FILE *fp, struct rtattr *encap)
193{
194 struct rtattr *tb[RPL_IPTUNNEL_MAX + 1];
195 struct ipv6_rpl_sr_hdr *srh;
196
197 parse_rtattr_nested(tb, RPL_IPTUNNEL_MAX, encap);
198
199 if (!tb[RPL_IPTUNNEL_SRH])
200 return;
201
202 srh = RTA_DATA(tb[RPL_IPTUNNEL_SRH]);
203
204 print_rpl_srh(fp, srh);
205}
206
8db158b9
DL
207static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = {
208 [SEG6_LOCAL_ACTION_END] = "End",
209 [SEG6_LOCAL_ACTION_END_X] = "End.X",
210 [SEG6_LOCAL_ACTION_END_T] = "End.T",
211 [SEG6_LOCAL_ACTION_END_DX2] = "End.DX2",
212 [SEG6_LOCAL_ACTION_END_DX6] = "End.DX6",
213 [SEG6_LOCAL_ACTION_END_DX4] = "End.DX4",
214 [SEG6_LOCAL_ACTION_END_DT6] = "End.DT6",
215 [SEG6_LOCAL_ACTION_END_DT4] = "End.DT4",
216 [SEG6_LOCAL_ACTION_END_B6] = "End.B6",
217 [SEG6_LOCAL_ACTION_END_B6_ENCAP] = "End.B6.Encaps",
218 [SEG6_LOCAL_ACTION_END_BM] = "End.BM",
219 [SEG6_LOCAL_ACTION_END_S] = "End.S",
220 [SEG6_LOCAL_ACTION_END_AS] = "End.AS",
221 [SEG6_LOCAL_ACTION_END_AM] = "End.AM",
04cb3c0d 222 [SEG6_LOCAL_ACTION_END_BPF] = "End.BPF",
8db158b9
DL
223};
224
225static const char *format_action_type(int action)
226{
227 if (action < 0 || action > SEG6_LOCAL_ACTION_MAX)
228 return "<invalid>";
229
230 return seg6_action_names[action] ?: "<unknown>";
231}
232
233static int read_action_type(const char *name)
234{
235 int i;
236
237 for (i = 0; i < SEG6_LOCAL_ACTION_MAX + 1; i++) {
238 if (!seg6_action_names[i])
239 continue;
240
241 if (strcmp(seg6_action_names[i], name) == 0)
242 return i;
243 }
244
245 return SEG6_LOCAL_ACTION_UNSPEC;
246}
247
04cb3c0d
MX
248static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
249 const char *str)
250{
251 struct rtattr *tb[LWT_BPF_PROG_MAX+1];
252 const char *progname = NULL;
253
254 parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
255
256 if (tb[LWT_BPF_PROG_NAME])
257 progname = rta_getattr_str(tb[LWT_BPF_PROG_NAME]);
258
259 if (is_json_context())
260 print_string(PRINT_JSON, str, NULL,
261 progname ? : "<unknown>");
262 else {
263 fprintf(fp, "%s ", str);
264 if (progname)
265 fprintf(fp, "%s ", progname);
266 }
267}
268
8db158b9
DL
269static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
270{
271 struct rtattr *tb[SEG6_LOCAL_MAX + 1];
8db158b9
DL
272 int action;
273
0486388a
PL
274 SPRINT_BUF(b1);
275
8db158b9
DL
276 parse_rtattr_nested(tb, SEG6_LOCAL_MAX, encap);
277
278 if (!tb[SEG6_LOCAL_ACTION])
279 return;
280
281 action = rta_getattr_u32(tb[SEG6_LOCAL_ACTION]);
282
663c3cb2
SH
283 print_string(PRINT_ANY, "action",
284 "action %s ", format_action_type(action));
8db158b9
DL
285
286 if (tb[SEG6_LOCAL_SRH]) {
663c3cb2 287 open_json_object("srh");
8db158b9 288 print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH]));
663c3cb2 289 close_json_object();
8db158b9
DL
290 }
291
292 if (tb[SEG6_LOCAL_TABLE])
0486388a
PL
293 print_string(PRINT_ANY, "table", "table %s ",
294 rtnl_rttable_n2a(rta_getattr_u32(tb[SEG6_LOCAL_TABLE]),
295 b1, sizeof(b1)));
8db158b9
DL
296
297 if (tb[SEG6_LOCAL_NH4]) {
663c3cb2
SH
298 print_string(PRINT_ANY, "nh4",
299 "nh4 %s ", rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4]));
8db158b9
DL
300 }
301
302 if (tb[SEG6_LOCAL_NH6]) {
663c3cb2
SH
303 print_string(PRINT_ANY, "nh6",
304 "nh6 %s ", rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6]));
8db158b9
DL
305 }
306
307 if (tb[SEG6_LOCAL_IIF]) {
308 int iif = rta_getattr_u32(tb[SEG6_LOCAL_IIF]);
309
663c3cb2
SH
310 print_string(PRINT_ANY, "iif",
311 "iif %s ", ll_index_to_name(iif));
8db158b9
DL
312 }
313
314 if (tb[SEG6_LOCAL_OIF]) {
315 int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]);
316
663c3cb2
SH
317 print_string(PRINT_ANY, "oif",
318 "oif %s ", ll_index_to_name(oif));
8db158b9 319 }
04cb3c0d
MX
320
321 if (tb[SEG6_LOCAL_BPF])
322 print_encap_bpf_prog(fp, tb[SEG6_LOCAL_BPF], "endpoint");
8db158b9
DL
323}
324
1e529305
RP
325static void print_encap_mpls(FILE *fp, struct rtattr *encap)
326{
327 struct rtattr *tb[MPLS_IPTUNNEL_MAX+1];
1e529305
RP
328
329 parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
330
331 if (tb[MPLS_IPTUNNEL_DST])
663c3cb2 332 print_string(PRINT_ANY, "dst", " %s ",
b723368c 333 format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST]));
9688cf3b 334 if (tb[MPLS_IPTUNNEL_TTL])
663c3cb2 335 print_uint(PRINT_ANY, "ttl", "ttl %u ",
9688cf3b 336 rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
1e529305
RP
337}
338
ca7614d4
XL
339static void lwtunnel_print_geneve_opts(struct rtattr *attr)
340{
341 struct rtattr *tb[LWTUNNEL_IP_OPT_GENEVE_MAX + 1];
342 struct rtattr *i = RTA_DATA(attr);
343 int rem = RTA_PAYLOAD(attr);
344 char *name = "geneve_opts";
345 int data_len, offset = 0;
346 char data[rem * 2 + 1];
347 __u16 class;
348 __u8 type;
349
350 print_nl();
351 print_string(PRINT_FP, name, "\t%s ", name);
352 open_json_array(PRINT_JSON, name);
353
354 while (rem) {
355 parse_rtattr(tb, LWTUNNEL_IP_OPT_GENEVE_MAX, i, rem);
356 class = rta_getattr_be16(tb[LWTUNNEL_IP_OPT_GENEVE_CLASS]);
357 type = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_GENEVE_TYPE]);
358 data_len = RTA_PAYLOAD(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]);
359 hexstring_n2a(RTA_DATA(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]),
360 data_len, data, sizeof(data));
361 offset += data_len + 20;
362 rem -= data_len + 20;
363 i = RTA_DATA(attr) + offset;
364
365 open_json_object(NULL);
366 print_uint(PRINT_ANY, "class", "%u", class);
367 print_uint(PRINT_ANY, "type", ":%u", type);
368 if (rem)
369 print_string(PRINT_ANY, "data", ":%s,", data);
370 else
371 print_string(PRINT_ANY, "data", ":%s ", data);
372 close_json_object();
373 }
374
375 close_json_array(PRINT_JSON, name);
376}
377
b1bc0f38
XL
378static void lwtunnel_print_vxlan_opts(struct rtattr *attr)
379{
380 struct rtattr *tb[LWTUNNEL_IP_OPT_VXLAN_MAX + 1];
381 struct rtattr *i = RTA_DATA(attr);
382 int rem = RTA_PAYLOAD(attr);
383 char *name = "vxlan_opts";
384 __u32 gbp;
385
386 parse_rtattr(tb, LWTUNNEL_IP_OPT_VXLAN_MAX, i, rem);
387 gbp = rta_getattr_u32(tb[LWTUNNEL_IP_OPT_VXLAN_GBP]);
388
389 print_nl();
390 print_string(PRINT_FP, name, "\t%s ", name);
391 open_json_array(PRINT_JSON, name);
392 open_json_object(NULL);
393 print_uint(PRINT_ANY, "gbp", "%u ", gbp);
394 close_json_object();
395 close_json_array(PRINT_JSON, name);
396}
397
39fa0479
XL
398static void lwtunnel_print_erspan_opts(struct rtattr *attr)
399{
400 struct rtattr *tb[LWTUNNEL_IP_OPT_ERSPAN_MAX + 1];
401 struct rtattr *i = RTA_DATA(attr);
402 char *name = "erspan_opts";
403 __u8 ver, hwid, dir;
404 __u32 idx;
405
406 parse_rtattr(tb, LWTUNNEL_IP_OPT_ERSPAN_MAX, i, RTA_PAYLOAD(attr));
407 ver = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_VER]);
408 if (ver == 1) {
409 idx = rta_getattr_be32(tb[LWTUNNEL_IP_OPT_ERSPAN_INDEX]);
410 dir = 0;
411 hwid = 0;
412 } else {
413 idx = 0;
414 dir = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_DIR]);
415 hwid = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_HWID]);
416 }
417
418 print_nl();
419 print_string(PRINT_FP, name, "\t%s ", name);
420 open_json_array(PRINT_JSON, name);
421 open_json_object(NULL);
422 print_uint(PRINT_ANY, "ver", "%u", ver);
423 print_uint(PRINT_ANY, "index", ":%u", idx);
424 print_uint(PRINT_ANY, "dir", ":%u", dir);
425 print_uint(PRINT_ANY, "hwid", ":%u ", hwid);
426 close_json_object();
427 close_json_array(PRINT_JSON, name);
428}
429
ca7614d4
XL
430static void lwtunnel_print_opts(struct rtattr *attr)
431{
432 struct rtattr *tb_opt[LWTUNNEL_IP_OPTS_MAX + 1];
433
434 parse_rtattr_nested(tb_opt, LWTUNNEL_IP_OPTS_MAX, attr);
435 if (tb_opt[LWTUNNEL_IP_OPTS_GENEVE])
436 lwtunnel_print_geneve_opts(tb_opt[LWTUNNEL_IP_OPTS_GENEVE]);
b1bc0f38
XL
437 else if (tb_opt[LWTUNNEL_IP_OPTS_VXLAN])
438 lwtunnel_print_vxlan_opts(tb_opt[LWTUNNEL_IP_OPTS_VXLAN]);
39fa0479
XL
439 else if (tb_opt[LWTUNNEL_IP_OPTS_ERSPAN])
440 lwtunnel_print_erspan_opts(tb_opt[LWTUNNEL_IP_OPTS_ERSPAN]);
ca7614d4
XL
441}
442
1e529305
RP
443static void print_encap_ip(FILE *fp, struct rtattr *encap)
444{
445 struct rtattr *tb[LWTUNNEL_IP_MAX+1];
3d65cefb 446 __u16 flags;
1e529305
RP
447
448 parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
449
450 if (tb[LWTUNNEL_IP_ID])
4db2ff0d 451 print_u64(PRINT_ANY, "id", "id %llu ",
663c3cb2 452 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
1e529305
RP
453
454 if (tb[LWTUNNEL_IP_SRC])
663c3cb2
SH
455 print_color_string(PRINT_ANY, COLOR_INET,
456 "src", "src %s ",
457 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
1e529305
RP
458
459 if (tb[LWTUNNEL_IP_DST])
663c3cb2
SH
460 print_color_string(PRINT_ANY, COLOR_INET,
461 "dst", "dst %s ",
462 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
1e529305
RP
463
464 if (tb[LWTUNNEL_IP_TTL])
663c3cb2
SH
465 print_uint(PRINT_ANY, "ttl",
466 "ttl %u ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
1e529305
RP
467
468 if (tb[LWTUNNEL_IP_TOS])
663c3cb2
SH
469 print_uint(PRINT_ANY, "tos",
470 "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
3d65cefb 471
472 if (tb[LWTUNNEL_IP_FLAGS]) {
473 flags = rta_getattr_u16(tb[LWTUNNEL_IP_FLAGS]);
474 if (flags & TUNNEL_KEY)
475 print_bool(PRINT_ANY, "key", "key ", true);
476 if (flags & TUNNEL_CSUM)
477 print_bool(PRINT_ANY, "csum", "csum ", true);
478 if (flags & TUNNEL_SEQ)
479 print_bool(PRINT_ANY, "seq", "seq ", true);
480 }
ca7614d4
XL
481
482 if (tb[LWTUNNEL_IP_OPTS])
483 lwtunnel_print_opts(tb[LWTUNNEL_IP_OPTS]);
1e529305
RP
484}
485
5866bddd
TH
486static void print_encap_ila(FILE *fp, struct rtattr *encap)
487{
488 struct rtattr *tb[ILA_ATTR_MAX+1];
489
490 parse_rtattr_nested(tb, ILA_ATTR_MAX, encap);
491
492 if (tb[ILA_ATTR_LOCATOR]) {
493 char abuf[ADDR64_BUF_SIZE];
494
9f1370c0 495 addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
5866bddd 496 abuf, sizeof(abuf));
663c3cb2
SH
497 print_string(PRINT_ANY, "locator",
498 " %s ", abuf);
5866bddd 499 }
ed67f838
TH
500
501 if (tb[ILA_ATTR_CSUM_MODE])
663c3cb2
SH
502 print_string(PRINT_ANY, "csum_mode",
503 " csum-mode %s ",
504 ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE])));
86905c8f
TH
505
506 if (tb[ILA_ATTR_IDENT_TYPE])
663c3cb2
SH
507 print_string(PRINT_ANY, "ident_type",
508 " ident-type %s ",
509 ila_ident_type2name(rta_getattr_u8(tb[ILA_ATTR_IDENT_TYPE])));
86905c8f
TH
510
511 if (tb[ILA_ATTR_HOOK_TYPE])
663c3cb2
SH
512 print_string(PRINT_ANY, "hook_type",
513 " hook-type %s ",
514 ila_hook_type2name(rta_getattr_u8(tb[ILA_ATTR_HOOK_TYPE])));
5866bddd
TH
515}
516
d95cdcf5
PA
517static void print_encap_ip6(FILE *fp, struct rtattr *encap)
518{
519 struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
3d65cefb 520 __u16 flags;
d95cdcf5
PA
521
522 parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
523
524 if (tb[LWTUNNEL_IP6_ID])
4db2ff0d 525 print_u64(PRINT_ANY, "id", "id %llu ",
663c3cb2 526 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
d95cdcf5
PA
527
528 if (tb[LWTUNNEL_IP6_SRC])
663c3cb2
SH
529 print_color_string(PRINT_ANY, COLOR_INET6,
530 "src", "src %s ",
531 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
d95cdcf5
PA
532
533 if (tb[LWTUNNEL_IP6_DST])
663c3cb2
SH
534 print_color_string(PRINT_ANY, COLOR_INET6,
535 "dst", "dst %s ",
536 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
d95cdcf5
PA
537
538 if (tb[LWTUNNEL_IP6_HOPLIMIT])
4db2ff0d 539 print_u64(PRINT_ANY, "hoplimit",
663c3cb2
SH
540 "hoplimit %u ",
541 rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
d95cdcf5
PA
542
543 if (tb[LWTUNNEL_IP6_TC])
663c3cb2
SH
544 print_uint(PRINT_ANY, "tc",
545 "tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
3d65cefb 546
547 if (tb[LWTUNNEL_IP6_FLAGS]) {
548 flags = rta_getattr_u16(tb[LWTUNNEL_IP6_FLAGS]);
549 if (flags & TUNNEL_KEY)
550 print_bool(PRINT_ANY, "key", "key ", true);
551 if (flags & TUNNEL_CSUM)
552 print_bool(PRINT_ANY, "csum", "csum ", true);
553 if (flags & TUNNEL_SEQ)
554 print_bool(PRINT_ANY, "seq", "seq ", true);
555 }
ca7614d4
XL
556
557 if (tb[LWTUNNEL_IP6_OPTS])
558 lwtunnel_print_opts(tb[LWTUNNEL_IP6_OPTS]);
d95cdcf5
PA
559}
560
b15f440e
TG
561static void print_encap_bpf(FILE *fp, struct rtattr *encap)
562{
563 struct rtattr *tb[LWT_BPF_MAX+1];
564
565 parse_rtattr_nested(tb, LWT_BPF_MAX, encap);
566
567 if (tb[LWT_BPF_IN])
568 print_encap_bpf_prog(fp, tb[LWT_BPF_IN], "in");
569 if (tb[LWT_BPF_OUT])
570 print_encap_bpf_prog(fp, tb[LWT_BPF_OUT], "out");
571 if (tb[LWT_BPF_XMIT])
572 print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit");
573 if (tb[LWT_BPF_XMIT_HEADROOM])
663c3cb2
SH
574 print_uint(PRINT_ANY, "headroom",
575 " %u ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
b15f440e
TG
576}
577
1e529305
RP
578void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
579 struct rtattr *encap)
580{
581 int et;
582
583 if (!encap_type)
584 return;
585
586 et = rta_getattr_u16(encap_type);
587
663c3cb2 588 print_string(PRINT_ANY, "encap", " encap %s ", format_encap_type(et));
1e529305
RP
589
590 switch (et) {
591 case LWTUNNEL_ENCAP_MPLS:
592 print_encap_mpls(fp, encap);
593 break;
594 case LWTUNNEL_ENCAP_IP:
595 print_encap_ip(fp, encap);
596 break;
5866bddd
TH
597 case LWTUNNEL_ENCAP_ILA:
598 print_encap_ila(fp, encap);
599 break;
d95cdcf5
PA
600 case LWTUNNEL_ENCAP_IP6:
601 print_encap_ip6(fp, encap);
602 break;
b15f440e
TG
603 case LWTUNNEL_ENCAP_BPF:
604 print_encap_bpf(fp, encap);
605 break;
e8493916
DL
606 case LWTUNNEL_ENCAP_SEG6:
607 print_encap_seg6(fp, encap);
608 break;
8db158b9
DL
609 case LWTUNNEL_ENCAP_SEG6_LOCAL:
610 print_encap_seg6local(fp, encap);
611 break;
9f91f1b7
AA
612 case LWTUNNEL_ENCAP_RPL:
613 print_encap_rpl(fp, encap);
614 break;
e8493916
DL
615 }
616}
617
00e76d4d
DL
618static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap)
619{
620 struct ipv6_sr_hdr *srh;
621 int nsegs = 0;
622 int srhlen;
623 char *s;
624 int i;
625
626 s = segbuf;
627 for (i = 0; *s; *s++ == ',' ? i++ : *s);
628 nsegs = i + 1;
629
630 if (!encap)
631 nsegs++;
632
633 srhlen = 8 + 16*nsegs;
634
635 if (hmac)
636 srhlen += 40;
637
638 srh = malloc(srhlen);
639 memset(srh, 0, srhlen);
640
641 srh->hdrlen = (srhlen >> 3) - 1;
642 srh->type = 4;
643 srh->segments_left = nsegs - 1;
644 srh->first_segment = nsegs - 1;
645
646 if (hmac)
647 srh->flags |= SR6_FLAG1_HMAC;
648
649 i = srh->first_segment;
650 for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
6caad8f5
SP
651 inet_prefix addr;
652
653 get_addr(&addr, s, AF_INET6);
654 memcpy(&srh->segments[i], addr.data, sizeof(struct in6_addr));
00e76d4d
DL
655 i--;
656 }
657
658 if (hmac) {
659 struct sr6_tlv_hmac *tlv;
660
661 tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40);
662 tlv->tlvhdr.type = SR6_TLV_HMAC;
663 tlv->tlvhdr.len = 38;
664 tlv->hmackeyid = htonl(hmac);
665 }
666
667 return srh;
668}
669
e8493916
DL
670static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
671 char ***argvp)
672{
673 int mode_ok = 0, segs_ok = 0, hmac_ok = 0;
674 struct seg6_iptunnel_encap *tuninfo;
675 struct ipv6_sr_hdr *srh;
676 char **argv = *argvp;
3b5c5ef0 677 char segbuf[1024] = "";
e8493916
DL
678 int argc = *argcp;
679 int encap = -1;
680 __u32 hmac = 0;
e5da392f 681 int ret = 0;
e8493916 682 int srhlen;
e8493916
DL
683
684 while (argc > 0) {
685 if (strcmp(*argv, "mode") == 0) {
686 NEXT_ARG();
687 if (mode_ok++)
688 duparg2("mode", *argv);
cf87da41
DL
689 encap = read_seg6mode_type(*argv);
690 if (encap < 0)
e8493916
DL
691 invarg("\"mode\" value is invalid\n", *argv);
692 } else if (strcmp(*argv, "segs") == 0) {
693 NEXT_ARG();
694 if (segs_ok++)
695 duparg2("segs", *argv);
696 if (encap == -1)
697 invarg("\"segs\" provided before \"mode\"\n",
698 *argv);
699
18f156bf 700 strlcpy(segbuf, *argv, 1024);
e8493916
DL
701 } else if (strcmp(*argv, "hmac") == 0) {
702 NEXT_ARG();
703 if (hmac_ok++)
704 duparg2("hmac", *argv);
705 get_u32(&hmac, *argv, 0);
706 } else {
707 break;
708 }
709 argc--; argv++;
710 }
711
00e76d4d
DL
712 srh = parse_srh(segbuf, hmac, encap);
713 srhlen = (srh->hdrlen + 1) << 3;
e8493916
DL
714
715 tuninfo = malloc(sizeof(*tuninfo) + srhlen);
716 memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
717
cf87da41 718 tuninfo->mode = encap;
e8493916 719
00e76d4d 720 memcpy(tuninfo->srh, srh, srhlen);
e8493916 721
bd59e5b1 722 if (rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
e5da392f
PS
723 sizeof(*tuninfo) + srhlen)) {
724 ret = -1;
725 goto out;
726 }
e8493916
DL
727
728 *argcp = argc + 1;
729 *argvp = argv - 1;
730
e5da392f
PS
731out:
732 free(tuninfo);
733 free(srh);
734
735 return ret;
1e529305
RP
736}
737
9f91f1b7
AA
738static struct ipv6_rpl_sr_hdr *parse_rpl_srh(char *segbuf)
739{
740 struct ipv6_rpl_sr_hdr *srh;
741 int nsegs = 0;
742 int srhlen;
743 char *s;
744 int i;
745
746 s = segbuf;
747 for (i = 0; *s; *s++ == ',' ? i++ : *s);
748 nsegs = i + 1;
749
750 srhlen = 8 + 16 * nsegs;
751
752 srh = calloc(1, srhlen);
753
754 srh->hdrlen = (srhlen >> 3) - 1;
755 srh->type = 3;
756 srh->segments_left = nsegs;
757
758 for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
759 inet_prefix addr;
760
761 get_addr(&addr, s, AF_INET6);
762 memcpy(&srh->rpl_segaddr[i], addr.data, sizeof(struct in6_addr));
763 i--;
764 }
765
766 return srh;
767}
768
769static int parse_encap_rpl(struct rtattr *rta, size_t len, int *argcp,
770 char ***argvp)
771{
772 struct ipv6_rpl_sr_hdr *srh;
773 char **argv = *argvp;
774 char segbuf[1024] = "";
775 int argc = *argcp;
776 int segs_ok = 0;
777 int ret = 0;
778 int srhlen;
779
780 while (argc > 0) {
781 if (strcmp(*argv, "segs") == 0) {
782 NEXT_ARG();
783 if (segs_ok++)
784 duparg2("segs", *argv);
785
786 strlcpy(segbuf, *argv, 1024);
787 } else {
788 break;
789 }
790 argc--; argv++;
791 }
792
793 srh = parse_rpl_srh(segbuf);
794 srhlen = (srh->hdrlen + 1) << 3;
795
796 if (rta_addattr_l(rta, len, RPL_IPTUNNEL_SRH, srh,
797 srhlen)) {
798 ret = -1;
799 goto out;
800 }
801
802 *argcp = argc + 1;
803 *argvp = argv - 1;
804
805out:
806 free(srh);
807
808 return ret;
809}
810
04cb3c0d
MX
811struct lwt_x {
812 struct rtattr *rta;
813 size_t len;
814};
815
816static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation)
817{
818 struct lwt_x *x = lwt_ptr;
819
820 rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd);
821 rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation,
822 strlen(annotation) + 1);
823}
824
825static const struct bpf_cfg_ops bpf_cb_ops = {
826 .ebpf_cb = bpf_lwt_cb,
827};
828
829static int lwt_parse_bpf(struct rtattr *rta, size_t len,
830 int *argcp, char ***argvp,
831 int attr, const enum bpf_prog_type bpf_type)
832{
833 struct bpf_cfg_in cfg = {
834 .type = bpf_type,
835 .argc = *argcp,
836 .argv = *argvp,
837 };
838 struct lwt_x x = {
839 .rta = rta,
840 .len = len,
841 };
842 struct rtattr *nest;
843 int err;
844
845 nest = rta_nest(rta, len, attr);
846 err = bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &x);
847 if (err < 0) {
848 fprintf(stderr, "Failed to parse eBPF program: %s\n",
849 strerror(-err));
850 return -1;
851 }
852 rta_nest_end(rta, nest);
853
854 *argcp = cfg.argc;
855 *argvp = cfg.argv;
856
857 return 0;
858}
859
8db158b9
DL
860static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
861 char ***argvp)
862{
863 int segs_ok = 0, hmac_ok = 0, table_ok = 0, nh4_ok = 0, nh6_ok = 0;
04cb3c0d 864 int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0, bpf_ok = 0;
8db158b9
DL
865 __u32 action = 0, table, iif, oif;
866 struct ipv6_sr_hdr *srh;
867 char **argv = *argvp;
868 int argc = *argcp;
869 char segbuf[1024];
870 inet_prefix addr;
871 __u32 hmac = 0;
bd59e5b1 872 int ret = 0;
8db158b9
DL
873
874 while (argc > 0) {
875 if (strcmp(*argv, "action") == 0) {
876 NEXT_ARG();
877 if (action_ok++)
878 duparg2("action", *argv);
879 action = read_action_type(*argv);
880 if (!action)
881 invarg("\"action\" value is invalid\n", *argv);
bd59e5b1
PS
882 ret = rta_addattr32(rta, len, SEG6_LOCAL_ACTION,
883 action);
8db158b9
DL
884 } else if (strcmp(*argv, "table") == 0) {
885 NEXT_ARG();
886 if (table_ok++)
887 duparg2("table", *argv);
0486388a 888 rtnl_rttable_a2n(&table, *argv);
bd59e5b1 889 ret = rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
8db158b9
DL
890 } else if (strcmp(*argv, "nh4") == 0) {
891 NEXT_ARG();
892 if (nh4_ok++)
893 duparg2("nh4", *argv);
894 get_addr(&addr, *argv, AF_INET);
bd59e5b1
PS
895 ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH4,
896 &addr.data, addr.bytelen);
8db158b9
DL
897 } else if (strcmp(*argv, "nh6") == 0) {
898 NEXT_ARG();
899 if (nh6_ok++)
900 duparg2("nh6", *argv);
901 get_addr(&addr, *argv, AF_INET6);
bd59e5b1
PS
902 ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH6,
903 &addr.data, addr.bytelen);
8db158b9
DL
904 } else if (strcmp(*argv, "iif") == 0) {
905 NEXT_ARG();
906 if (iif_ok++)
907 duparg2("iif", *argv);
7a14358b 908 iif = ll_name_to_index(*argv);
8db158b9 909 if (!iif)
fe99adbc 910 exit(nodev(*argv));
bd59e5b1 911 ret = rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
8db158b9
DL
912 } else if (strcmp(*argv, "oif") == 0) {
913 NEXT_ARG();
914 if (oif_ok++)
915 duparg2("oif", *argv);
7a14358b 916 oif = ll_name_to_index(*argv);
8db158b9 917 if (!oif)
fe99adbc 918 exit(nodev(*argv));
bd59e5b1 919 ret = rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
8db158b9
DL
920 } else if (strcmp(*argv, "srh") == 0) {
921 NEXT_ARG();
922 if (srh_ok++)
923 duparg2("srh", *argv);
924 if (strcmp(*argv, "segs") != 0)
925 invarg("missing \"segs\" attribute for srh\n",
926 *argv);
927 NEXT_ARG();
928 if (segs_ok++)
929 duparg2("segs", *argv);
930 strncpy(segbuf, *argv, 1024);
931 segbuf[1023] = 0;
932 if (!NEXT_ARG_OK())
933 break;
934 NEXT_ARG();
935 if (strcmp(*argv, "hmac") == 0) {
936 NEXT_ARG();
937 if (hmac_ok++)
938 duparg2("hmac", *argv);
939 get_u32(&hmac, *argv, 0);
940 } else {
941 continue;
942 }
04cb3c0d
MX
943 } else if (strcmp(*argv, "endpoint") == 0) {
944 NEXT_ARG();
945 if (bpf_ok++)
946 duparg2("endpoint", *argv);
947
948 if (lwt_parse_bpf(rta, len, &argc, &argv, SEG6_LOCAL_BPF,
949 BPF_PROG_TYPE_LWT_SEG6LOCAL) < 0)
950 exit(-1);
8db158b9
DL
951 } else {
952 break;
953 }
bd59e5b1
PS
954 if (ret)
955 return ret;
8db158b9
DL
956 argc--; argv++;
957 }
958
959 if (!action) {
960 fprintf(stderr, "Missing action type\n");
961 exit(-1);
962 }
963
964 if (srh_ok) {
965 int srhlen;
966
967 srh = parse_srh(segbuf, hmac,
968 action == SEG6_LOCAL_ACTION_END_B6_ENCAP);
969 srhlen = (srh->hdrlen + 1) << 3;
bd59e5b1 970 ret = rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
8db158b9
DL
971 free(srh);
972 }
973
974 *argcp = argc + 1;
975 *argvp = argv - 1;
976
bd59e5b1 977 return ret;
8db158b9
DL
978}
979
b723368c
SH
980static int parse_encap_mpls(struct rtattr *rta, size_t len,
981 int *argcp, char ***argvp)
1e529305
RP
982{
983 inet_prefix addr;
984 int argc = *argcp;
985 char **argv = *argvp;
9688cf3b 986 int ttl_ok = 0;
1e529305
RP
987
988 if (get_addr(&addr, *argv, AF_MPLS)) {
b723368c
SH
989 fprintf(stderr,
990 "Error: an inet address is expected rather than \"%s\".\n",
991 *argv);
1e529305
RP
992 exit(1);
993 }
994
bd59e5b1
PS
995 if (rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST,
996 &addr.data, addr.bytelen))
997 return -1;
1e529305 998
9688cf3b
RS
999 argc--;
1000 argv++;
1001
1002 while (argc > 0) {
1003 if (strcmp(*argv, "ttl") == 0) {
1004 __u8 ttl;
1005
1006 NEXT_ARG();
1007 if (ttl_ok++)
1008 duparg2("ttl", *argv);
1009 if (get_u8(&ttl, *argv, 0))
1010 invarg("\"ttl\" value is invalid\n", *argv);
bd59e5b1
PS
1011 if (rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl))
1012 return -1;
9688cf3b
RS
1013 } else {
1014 break;
1015 }
1016 argc--; argv++;
1017 }
1018
1019 /* argv is currently the first unparsed argument,
1020 * but the lwt_parse_encap() caller will move to the next,
1021 * so step back
1022 */
1023 *argcp = argc + 1;
1024 *argvp = argv - 1;
1e529305
RP
1025
1026 return 0;
1027}
1028
ca7614d4
XL
1029static int lwtunnel_parse_geneve_opt(char *str, size_t len, struct rtattr *rta)
1030{
1031 struct rtattr *nest;
1032 char *token;
1033 int i, err;
1034
1035 nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_GENEVE | NLA_F_NESTED);
1036 i = 1;
1037 token = strsep(&str, ":");
1038 while (token) {
1039 switch (i) {
1040 case LWTUNNEL_IP_OPT_GENEVE_CLASS:
1041 {
1042 __be16 opt_class;
1043
1044 if (!strlen(token))
1045 break;
1046 err = get_be16(&opt_class, token, 0);
1047 if (err)
1048 return err;
1049
1050 rta_addattr16(rta, len, i, opt_class);
1051 break;
1052 }
1053 case LWTUNNEL_IP_OPT_GENEVE_TYPE:
1054 {
1055 __u8 opt_type;
1056
1057 if (!strlen(token))
1058 break;
1059 err = get_u8(&opt_type, token, 0);
1060 if (err)
1061 return err;
1062
1063 rta_addattr8(rta, len, i, opt_type);
1064 break;
1065 }
1066 case LWTUNNEL_IP_OPT_GENEVE_DATA:
1067 {
1068 size_t token_len = strlen(token);
1069 __u8 *opts;
1070
1071 if (!token_len)
1072 break;
1073 opts = malloc(token_len / 2);
1074 if (!opts)
1075 return -1;
1076 if (hex2mem(token, opts, token_len / 2) < 0) {
1077 free(opts);
1078 return -1;
1079 }
1080 rta_addattr_l(rta, len, i, opts, token_len / 2);
1081 free(opts);
1082
1083 break;
1084 }
1085 default:
1086 fprintf(stderr, "Unknown \"geneve_opts\" type\n");
1087 return -1;
1088 }
1089
1090 token = strsep(&str, ":");
1091 i++;
1092 }
1093 rta_nest_end(rta, nest);
1094
1095 return 0;
1096}
1097
1098static int lwtunnel_parse_geneve_opts(char *str, size_t len, struct rtattr *rta)
1099{
1100 char *token;
1101 int err;
1102
1103 token = strsep(&str, ",");
1104 while (token) {
1105 err = lwtunnel_parse_geneve_opt(token, len, rta);
1106 if (err)
1107 return err;
1108
1109 token = strsep(&str, ",");
1110 }
1111
1112 return 0;
1113}
1114
b1bc0f38
XL
1115static int lwtunnel_parse_vxlan_opts(char *str, size_t len, struct rtattr *rta)
1116{
1117 struct rtattr *nest;
1118 __u32 gbp;
1119 int err;
1120
1121 nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_VXLAN | NLA_F_NESTED);
1122 err = get_u32(&gbp, str, 0);
1123 if (err)
1124 return err;
1125 rta_addattr32(rta, len, LWTUNNEL_IP_OPT_VXLAN_GBP, gbp);
1126
1127 rta_nest_end(rta, nest);
1128 return 0;
1129}
1130
39fa0479
XL
1131static int lwtunnel_parse_erspan_opts(char *str, size_t len, struct rtattr *rta)
1132{
1133 struct rtattr *nest;
1134 char *token;
1135 int i, err;
1136
1137 nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_ERSPAN | NLA_F_NESTED);
1138 i = 1;
1139 token = strsep(&str, ":");
1140 while (token) {
1141 switch (i) {
1142 case LWTUNNEL_IP_OPT_ERSPAN_VER:
1143 {
1144 __u8 opt_type;
1145
1146 if (!strlen(token))
1147 break;
1148 err = get_u8(&opt_type, token, 0);
1149 if (err)
1150 return err;
1151
1152 rta_addattr8(rta, len, i, opt_type);
1153 break;
1154 }
1155 case LWTUNNEL_IP_OPT_ERSPAN_INDEX:
1156 {
1157 __be32 opt_class;
1158
1159 if (!strlen(token))
1160 break;
1161 err = get_be32(&opt_class, token, 0);
1162 if (err)
1163 return err;
1164
1165 rta_addattr32(rta, len, i, opt_class);
1166 break;
1167 }
1168 case LWTUNNEL_IP_OPT_ERSPAN_DIR:
1169 {
1170 __u8 opt_type;
1171
1172 if (!strlen(token))
1173 break;
1174 err = get_u8(&opt_type, token, 0);
1175 if (err)
1176 return err;
1177
1178 rta_addattr8(rta, len, i, opt_type);
1179 break;
1180 }
1181 case LWTUNNEL_IP_OPT_ERSPAN_HWID:
1182 {
1183 __u8 opt_type;
1184
1185 if (!strlen(token))
1186 break;
1187 err = get_u8(&opt_type, token, 0);
1188 if (err)
1189 return err;
1190
1191 rta_addattr8(rta, len, i, opt_type);
1192 break;
1193 }
1194 default:
1195 fprintf(stderr, "Unknown \"geneve_opts\" type\n");
1196 return -1;
1197 }
1198
1199 token = strsep(&str, ":");
1200 i++;
1201 }
1202
1203 rta_nest_end(rta, nest);
1204 return 0;
1205}
1206
b723368c
SH
1207static int parse_encap_ip(struct rtattr *rta, size_t len,
1208 int *argcp, char ***argvp)
1e529305 1209{
94a8722f 1210 int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
ca7614d4 1211 int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0;
1e529305
RP
1212 char **argv = *argvp;
1213 int argc = *argcp;
bd59e5b1 1214 int ret = 0;
3d65cefb 1215 __u16 flags = 0;
1e529305
RP
1216
1217 while (argc > 0) {
1218 if (strcmp(*argv, "id") == 0) {
1219 __u64 id;
56f5daac 1220
1e529305
RP
1221 NEXT_ARG();
1222 if (id_ok++)
1223 duparg2("id", *argv);
9f7401fa 1224 if (get_be64(&id, *argv, 0))
1e529305 1225 invarg("\"id\" value is invalid\n", *argv);
bd59e5b1 1226 ret = rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
1e529305
RP
1227 } else if (strcmp(*argv, "dst") == 0) {
1228 inet_prefix addr;
56f5daac 1229
1e529305
RP
1230 NEXT_ARG();
1231 if (dst_ok++)
1232 duparg2("dst", *argv);
1233 get_addr(&addr, *argv, AF_INET);
bd59e5b1
PS
1234 ret = rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
1235 &addr.data, addr.bytelen);
94a8722f
SL
1236 } else if (strcmp(*argv, "src") == 0) {
1237 inet_prefix addr;
1238
1239 NEXT_ARG();
1240 if (src_ok++)
1241 duparg2("src", *argv);
1242 get_addr(&addr, *argv, AF_INET);
34212c73
DA
1243 ret = rta_addattr_l(rta, len, LWTUNNEL_IP_SRC,
1244 &addr.data, addr.bytelen);
1e529305
RP
1245 } else if (strcmp(*argv, "tos") == 0) {
1246 __u32 tos;
56f5daac 1247
1e529305
RP
1248 NEXT_ARG();
1249 if (tos_ok++)
1250 duparg2("tos", *argv);
1251 if (rtnl_dsfield_a2n(&tos, *argv))
1252 invarg("\"tos\" value is invalid\n", *argv);
bd59e5b1 1253 ret = rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
1e529305
RP
1254 } else if (strcmp(*argv, "ttl") == 0) {
1255 __u8 ttl;
56f5daac 1256
1e529305
RP
1257 NEXT_ARG();
1258 if (ttl_ok++)
1259 duparg2("ttl", *argv);
1260 if (get_u8(&ttl, *argv, 0))
1261 invarg("\"ttl\" value is invalid\n", *argv);
bd59e5b1 1262 ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
ca7614d4
XL
1263 } else if (strcmp(*argv, "geneve_opts") == 0) {
1264 struct rtattr *nest;
1265
1266 if (opts_ok++)
1267 duparg2("opts", *argv);
1268
1269 NEXT_ARG();
1270
1271 nest = rta_nest(rta, len,
1272 LWTUNNEL_IP_OPTS | NLA_F_NESTED);
1273 ret = lwtunnel_parse_geneve_opts(*argv, len, rta);
1274 if (ret)
1275 invarg("\"geneve_opts\" value is invalid\n",
1276 *argv);
1277 rta_nest_end(rta, nest);
b1bc0f38
XL
1278 } else if (strcmp(*argv, "vxlan_opts") == 0) {
1279 struct rtattr *nest;
1280
1281 if (opts_ok++)
1282 duparg2("opts", *argv);
1283
1284 NEXT_ARG();
1285
1286 nest = rta_nest(rta, len,
1287 LWTUNNEL_IP_OPTS | NLA_F_NESTED);
1288 ret = lwtunnel_parse_vxlan_opts(*argv, len, rta);
1289 if (ret)
1290 invarg("\"vxlan_opts\" value is invalid\n",
1291 *argv);
1292 rta_nest_end(rta, nest);
39fa0479
XL
1293 } else if (strcmp(*argv, "erspan_opts") == 0) {
1294 struct rtattr *nest;
1295
1296 if (opts_ok++)
1297 duparg2("opts", *argv);
1298
1299 NEXT_ARG();
1300
1301 nest = rta_nest(rta, len,
1302 LWTUNNEL_IP_OPTS | NLA_F_NESTED);
1303 ret = lwtunnel_parse_erspan_opts(*argv, len, rta);
1304 if (ret)
1305 invarg("\"erspan_opts\" value is invalid\n",
1306 *argv);
1307 rta_nest_end(rta, nest);
3d65cefb 1308 } else if (strcmp(*argv, "key") == 0) {
1309 if (key_ok++)
1310 duparg2("key", *argv);
1311 flags |= TUNNEL_KEY;
1312 } else if (strcmp(*argv, "csum") == 0) {
1313 if (csum_ok++)
1314 duparg2("csum", *argv);
1315 flags |= TUNNEL_CSUM;
1316 } else if (strcmp(*argv, "seq") == 0) {
1317 if (seq_ok++)
1318 duparg2("seq", *argv);
1319 flags |= TUNNEL_SEQ;
1e529305
RP
1320 } else {
1321 break;
1322 }
bd59e5b1
PS
1323 if (ret)
1324 break;
f0df4081 1325 argc--; argv++;
1e529305
RP
1326 }
1327
3d65cefb 1328 if (flags)
1329 ret = rta_addattr16(rta, len, LWTUNNEL_IP_FLAGS, flags);
1330
f0df4081
PA
1331 /* argv is currently the first unparsed argument,
1332 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
1333 * so step back
1334 */
f0df4081
PA
1335 *argcp = argc + 1;
1336 *argvp = argv - 1;
1e529305 1337
bd59e5b1 1338 return ret;
1e529305
RP
1339}
1340
5866bddd
TH
1341static int parse_encap_ila(struct rtattr *rta, size_t len,
1342 int *argcp, char ***argvp)
1343{
1344 __u64 locator;
1345 int argc = *argcp;
1346 char **argv = *argvp;
bd59e5b1 1347 int ret = 0;
5866bddd
TH
1348
1349 if (get_addr64(&locator, *argv) < 0) {
1350 fprintf(stderr, "Bad locator: %s\n", *argv);
1351 exit(1);
1352 }
1353
ed67f838
TH
1354 argc--; argv++;
1355
05d978e0 1356 if (rta_addattr64(rta, len, ILA_ATTR_LOCATOR, locator))
bd59e5b1 1357 return -1;
5866bddd 1358
ed67f838
TH
1359 while (argc > 0) {
1360 if (strcmp(*argv, "csum-mode") == 0) {
08806fb0 1361 int csum_mode;
ed67f838
TH
1362
1363 NEXT_ARG();
1364
1365 csum_mode = ila_csum_name2mode(*argv);
1366 if (csum_mode < 0)
b723368c
SH
1367 invarg("\"csum-mode\" value is invalid\n",
1368 *argv);
ed67f838 1369
05d978e0 1370 ret = rta_addattr8(rta, len, ILA_ATTR_CSUM_MODE,
bd59e5b1 1371 (__u8)csum_mode);
ed67f838 1372
86905c8f
TH
1373 argc--; argv++;
1374 } else if (strcmp(*argv, "ident-type") == 0) {
1375 int ident_type;
1376
1377 NEXT_ARG();
1378
1379 ident_type = ila_ident_name2type(*argv);
1380 if (ident_type < 0)
1381 invarg("\"ident-type\" value is invalid\n",
1382 *argv);
1383
05d978e0 1384 ret = rta_addattr8(rta, len, ILA_ATTR_IDENT_TYPE,
bd59e5b1 1385 (__u8)ident_type);
86905c8f
TH
1386
1387 argc--; argv++;
1388 } else if (strcmp(*argv, "hook-type") == 0) {
1389 int hook_type;
1390
1391 NEXT_ARG();
1392
1393 hook_type = ila_hook_name2type(*argv);
1394 if (hook_type < 0)
1395 invarg("\"hook-type\" value is invalid\n",
1396 *argv);
1397
05d978e0 1398 ret = rta_addattr8(rta, len, ILA_ATTR_HOOK_TYPE,
bd59e5b1 1399 (__u8)hook_type);
86905c8f 1400
ed67f838
TH
1401 argc--; argv++;
1402 } else {
1403 break;
1404 }
bd59e5b1
PS
1405 if (ret)
1406 break;
ed67f838
TH
1407 }
1408
1409 /* argv is currently the first unparsed argument,
1410 * but the lwt_parse_encap() caller will move to the next,
1411 * so step back
1412 */
1413 *argcp = argc + 1;
1414 *argvp = argv - 1;
5866bddd 1415
bd59e5b1 1416 return ret;
5866bddd 1417}
1e529305 1418
b723368c
SH
1419static int parse_encap_ip6(struct rtattr *rta, size_t len,
1420 int *argcp, char ***argvp)
d95cdcf5 1421{
94a8722f 1422 int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
ca7614d4 1423 int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0;
d95cdcf5
PA
1424 char **argv = *argvp;
1425 int argc = *argcp;
bd59e5b1 1426 int ret = 0;
3d65cefb 1427 __u16 flags = 0;
d95cdcf5
PA
1428
1429 while (argc > 0) {
1430 if (strcmp(*argv, "id") == 0) {
1431 __u64 id;
56f5daac 1432
d95cdcf5
PA
1433 NEXT_ARG();
1434 if (id_ok++)
1435 duparg2("id", *argv);
9f7401fa 1436 if (get_be64(&id, *argv, 0))
d95cdcf5 1437 invarg("\"id\" value is invalid\n", *argv);
bd59e5b1 1438 ret = rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
d95cdcf5
PA
1439 } else if (strcmp(*argv, "dst") == 0) {
1440 inet_prefix addr;
56f5daac 1441
d95cdcf5
PA
1442 NEXT_ARG();
1443 if (dst_ok++)
1444 duparg2("dst", *argv);
1445 get_addr(&addr, *argv, AF_INET6);
bd59e5b1
PS
1446 ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
1447 &addr.data, addr.bytelen);
94a8722f
SL
1448 } else if (strcmp(*argv, "src") == 0) {
1449 inet_prefix addr;
1450
1451 NEXT_ARG();
1452 if (src_ok++)
1453 duparg2("src", *argv);
1454 get_addr(&addr, *argv, AF_INET6);
34212c73
DA
1455 ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_SRC,
1456 &addr.data, addr.bytelen);
d95cdcf5
PA
1457 } else if (strcmp(*argv, "tc") == 0) {
1458 __u32 tc;
56f5daac 1459
d95cdcf5
PA
1460 NEXT_ARG();
1461 if (tos_ok++)
1462 duparg2("tc", *argv);
1463 if (rtnl_dsfield_a2n(&tc, *argv))
1464 invarg("\"tc\" value is invalid\n", *argv);
bd59e5b1 1465 ret = rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
d95cdcf5
PA
1466 } else if (strcmp(*argv, "hoplimit") == 0) {
1467 __u8 hoplimit;
56f5daac 1468
d95cdcf5
PA
1469 NEXT_ARG();
1470 if (ttl_ok++)
1471 duparg2("hoplimit", *argv);
1472 if (get_u8(&hoplimit, *argv, 0))
b723368c
SH
1473 invarg("\"hoplimit\" value is invalid\n",
1474 *argv);
bd59e5b1
PS
1475 ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
1476 hoplimit);
ca7614d4
XL
1477 } else if (strcmp(*argv, "geneve_opts") == 0) {
1478 struct rtattr *nest;
1479
1480 if (opts_ok++)
1481 duparg2("opts", *argv);
1482
1483 NEXT_ARG();
1484
1485 nest = rta_nest(rta, len,
1486 LWTUNNEL_IP_OPTS | NLA_F_NESTED);
1487 ret = lwtunnel_parse_geneve_opts(*argv, len, rta);
1488 if (ret)
1489 invarg("\"geneve_opts\" value is invalid\n",
1490 *argv);
1491 rta_nest_end(rta, nest);
b1bc0f38
XL
1492 } else if (strcmp(*argv, "vxlan_opts") == 0) {
1493 struct rtattr *nest;
1494
1495 if (opts_ok++)
1496 duparg2("opts", *argv);
1497
1498 NEXT_ARG();
1499
1500 nest = rta_nest(rta, len,
1501 LWTUNNEL_IP_OPTS | NLA_F_NESTED);
1502 ret = lwtunnel_parse_vxlan_opts(*argv, len, rta);
1503 if (ret)
1504 invarg("\"vxlan_opts\" value is invalid\n",
1505 *argv);
1506 rta_nest_end(rta, nest);
39fa0479
XL
1507 } else if (strcmp(*argv, "erspan_opts") == 0) {
1508 struct rtattr *nest;
1509
1510 if (opts_ok++)
1511 duparg2("opts", *argv);
1512
1513 NEXT_ARG();
1514
1515 nest = rta_nest(rta, len,
1516 LWTUNNEL_IP_OPTS | NLA_F_NESTED);
1517 ret = lwtunnel_parse_erspan_opts(*argv, len, rta);
1518 if (ret)
1519 invarg("\"erspan_opts\" value is invalid\n",
1520 *argv);
1521 rta_nest_end(rta, nest);
3d65cefb 1522 } else if (strcmp(*argv, "key") == 0) {
1523 if (key_ok++)
1524 duparg2("key", *argv);
1525 flags |= TUNNEL_KEY;
1526 } else if (strcmp(*argv, "csum") == 0) {
1527 if (csum_ok++)
1528 duparg2("csum", *argv);
1529 flags |= TUNNEL_CSUM;
1530 } else if (strcmp(*argv, "seq") == 0) {
1531 if (seq_ok++)
1532 duparg2("seq", *argv);
1533 flags |= TUNNEL_SEQ;
d95cdcf5
PA
1534 } else {
1535 break;
1536 }
bd59e5b1
PS
1537 if (ret)
1538 break;
d95cdcf5
PA
1539 argc--; argv++;
1540 }
1541
3d65cefb 1542 if (flags)
1543 ret = rta_addattr16(rta, len, LWTUNNEL_IP6_FLAGS, flags);
1544
d95cdcf5
PA
1545 /* argv is currently the first unparsed argument,
1546 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
1547 * so step back
1548 */
d95cdcf5
PA
1549 *argcp = argc + 1;
1550 *argvp = argv - 1;
1551
bd59e5b1 1552 return ret;
d95cdcf5
PA
1553}
1554
b15f440e
TG
1555static void lwt_bpf_usage(void)
1556{
1557 fprintf(stderr, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
1558 fprintf(stderr, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
1559 exit(-1);
1560}
1561
1562static int parse_encap_bpf(struct rtattr *rta, size_t len, int *argcp,
1563 char ***argvp)
1564{
1565 char **argv = *argvp;
1566 int argc = *argcp;
1567 int headroom_set = 0;
1568
1569 while (argc > 0) {
1570 if (strcmp(*argv, "in") == 0) {
1571 NEXT_ARG();
1572 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_IN,
1573 BPF_PROG_TYPE_LWT_IN) < 0)
1574 return -1;
1575 } else if (strcmp(*argv, "out") == 0) {
1576 NEXT_ARG();
1577 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_OUT,
1578 BPF_PROG_TYPE_LWT_OUT) < 0)
1579 return -1;
1580 } else if (strcmp(*argv, "xmit") == 0) {
1581 NEXT_ARG();
1582 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_XMIT,
1583 BPF_PROG_TYPE_LWT_XMIT) < 0)
1584 return -1;
1585 } else if (strcmp(*argv, "headroom") == 0) {
1586 unsigned int headroom;
1587
1588 NEXT_ARG();
1589 if (get_unsigned(&headroom, *argv, 0) || headroom == 0)
1590 invarg("headroom is invalid\n", *argv);
1591 if (!headroom_set)
05d978e0 1592 rta_addattr32(rta, len, LWT_BPF_XMIT_HEADROOM,
b15f440e
TG
1593 headroom);
1594 headroom_set = 1;
1595 } else if (strcmp(*argv, "help") == 0) {
1596 lwt_bpf_usage();
1597 } else {
1598 break;
1599 }
1600 NEXT_ARG_FWD();
1601 }
1602
1603 /* argv is currently the first unparsed argument,
1604 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
1605 * so step back
1606 */
b15f440e
TG
1607 *argcp = argc + 1;
1608 *argvp = argv - 1;
1609
1610 return 0;
1611}
1612
73924010
DA
1613int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp,
1614 int encap_attr, int encap_type_attr)
1e529305
RP
1615{
1616 struct rtattr *nest;
1617 int argc = *argcp;
1618 char **argv = *argvp;
1619 __u16 type;
bd59e5b1 1620 int ret = 0;
1e529305
RP
1621
1622 NEXT_ARG();
1623 type = read_encap_type(*argv);
1624 if (!type)
1625 invarg("\"encap type\" value is invalid\n", *argv);
1626
1627 NEXT_ARG();
1628 if (argc <= 1) {
b723368c
SH
1629 fprintf(stderr,
1630 "Error: unexpected end of line after \"encap\"\n");
1e529305
RP
1631 exit(-1);
1632 }
1633
73924010 1634 nest = rta_nest(rta, len, encap_attr);
1e529305
RP
1635 switch (type) {
1636 case LWTUNNEL_ENCAP_MPLS:
bd59e5b1 1637 ret = parse_encap_mpls(rta, len, &argc, &argv);
1e529305
RP
1638 break;
1639 case LWTUNNEL_ENCAP_IP:
bd59e5b1 1640 ret = parse_encap_ip(rta, len, &argc, &argv);
1e529305 1641 break;
5866bddd 1642 case LWTUNNEL_ENCAP_ILA:
bd59e5b1 1643 ret = parse_encap_ila(rta, len, &argc, &argv);
5866bddd 1644 break;
d95cdcf5 1645 case LWTUNNEL_ENCAP_IP6:
bd59e5b1 1646 ret = parse_encap_ip6(rta, len, &argc, &argv);
d95cdcf5 1647 break;
b15f440e
TG
1648 case LWTUNNEL_ENCAP_BPF:
1649 if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
1650 exit(-1);
1651 break;
e8493916 1652 case LWTUNNEL_ENCAP_SEG6:
bd59e5b1 1653 ret = parse_encap_seg6(rta, len, &argc, &argv);
e8493916 1654 break;
8db158b9 1655 case LWTUNNEL_ENCAP_SEG6_LOCAL:
bd59e5b1 1656 ret = parse_encap_seg6local(rta, len, &argc, &argv);
8db158b9 1657 break;
9f91f1b7
AA
1658 case LWTUNNEL_ENCAP_RPL:
1659 ret = parse_encap_rpl(rta, len, &argc, &argv);
1660 break;
1e529305
RP
1661 default:
1662 fprintf(stderr, "Error: unsupported encap type\n");
1663 break;
1664 }
bd59e5b1
PS
1665 if (ret)
1666 return ret;
1667
1e529305
RP
1668 rta_nest_end(rta, nest);
1669
73924010 1670 ret = rta_addattr16(rta, len, encap_type_attr, type);
1e529305
RP
1671
1672 *argcp = argc;
1673 *argvp = argv;
1674
bd59e5b1 1675 return ret;
1e529305 1676}