]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iproute_lwtunnel.c
ip route: get: allow zero-length subnet mask
[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 33#include <linux/seg6_local.h>
3d65cefb 34#include <linux/if_tunnel.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 117 print_0xhex(PRINT_ANY, "hmac",
90c5c969 118 "hmac %llX ", 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];
3d65cefb 297 __u16 flags;
1e529305
RP
298
299 parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
300
301 if (tb[LWTUNNEL_IP_ID])
4db2ff0d 302 print_u64(PRINT_ANY, "id", "id %llu ",
663c3cb2 303 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
1e529305
RP
304
305 if (tb[LWTUNNEL_IP_SRC])
663c3cb2
SH
306 print_color_string(PRINT_ANY, COLOR_INET,
307 "src", "src %s ",
308 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
1e529305
RP
309
310 if (tb[LWTUNNEL_IP_DST])
663c3cb2
SH
311 print_color_string(PRINT_ANY, COLOR_INET,
312 "dst", "dst %s ",
313 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
1e529305
RP
314
315 if (tb[LWTUNNEL_IP_TTL])
663c3cb2
SH
316 print_uint(PRINT_ANY, "ttl",
317 "ttl %u ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
1e529305
RP
318
319 if (tb[LWTUNNEL_IP_TOS])
663c3cb2
SH
320 print_uint(PRINT_ANY, "tos",
321 "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
3d65cefb 322
323 if (tb[LWTUNNEL_IP_FLAGS]) {
324 flags = rta_getattr_u16(tb[LWTUNNEL_IP_FLAGS]);
325 if (flags & TUNNEL_KEY)
326 print_bool(PRINT_ANY, "key", "key ", true);
327 if (flags & TUNNEL_CSUM)
328 print_bool(PRINT_ANY, "csum", "csum ", true);
329 if (flags & TUNNEL_SEQ)
330 print_bool(PRINT_ANY, "seq", "seq ", true);
331 }
1e529305
RP
332}
333
5866bddd
TH
334static void print_encap_ila(FILE *fp, struct rtattr *encap)
335{
336 struct rtattr *tb[ILA_ATTR_MAX+1];
337
338 parse_rtattr_nested(tb, ILA_ATTR_MAX, encap);
339
340 if (tb[ILA_ATTR_LOCATOR]) {
341 char abuf[ADDR64_BUF_SIZE];
342
9f1370c0 343 addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
5866bddd 344 abuf, sizeof(abuf));
663c3cb2
SH
345 print_string(PRINT_ANY, "locator",
346 " %s ", abuf);
5866bddd 347 }
ed67f838
TH
348
349 if (tb[ILA_ATTR_CSUM_MODE])
663c3cb2
SH
350 print_string(PRINT_ANY, "csum_mode",
351 " csum-mode %s ",
352 ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE])));
86905c8f
TH
353
354 if (tb[ILA_ATTR_IDENT_TYPE])
663c3cb2
SH
355 print_string(PRINT_ANY, "ident_type",
356 " ident-type %s ",
357 ila_ident_type2name(rta_getattr_u8(tb[ILA_ATTR_IDENT_TYPE])));
86905c8f
TH
358
359 if (tb[ILA_ATTR_HOOK_TYPE])
663c3cb2
SH
360 print_string(PRINT_ANY, "hook_type",
361 " hook-type %s ",
362 ila_hook_type2name(rta_getattr_u8(tb[ILA_ATTR_HOOK_TYPE])));
5866bddd
TH
363}
364
d95cdcf5
PA
365static void print_encap_ip6(FILE *fp, struct rtattr *encap)
366{
367 struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
3d65cefb 368 __u16 flags;
d95cdcf5
PA
369
370 parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
371
372 if (tb[LWTUNNEL_IP6_ID])
4db2ff0d 373 print_u64(PRINT_ANY, "id", "id %llu ",
663c3cb2 374 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
d95cdcf5
PA
375
376 if (tb[LWTUNNEL_IP6_SRC])
663c3cb2
SH
377 print_color_string(PRINT_ANY, COLOR_INET6,
378 "src", "src %s ",
379 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
d95cdcf5
PA
380
381 if (tb[LWTUNNEL_IP6_DST])
663c3cb2
SH
382 print_color_string(PRINT_ANY, COLOR_INET6,
383 "dst", "dst %s ",
384 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
d95cdcf5
PA
385
386 if (tb[LWTUNNEL_IP6_HOPLIMIT])
4db2ff0d 387 print_u64(PRINT_ANY, "hoplimit",
663c3cb2
SH
388 "hoplimit %u ",
389 rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
d95cdcf5
PA
390
391 if (tb[LWTUNNEL_IP6_TC])
663c3cb2
SH
392 print_uint(PRINT_ANY, "tc",
393 "tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
3d65cefb 394
395 if (tb[LWTUNNEL_IP6_FLAGS]) {
396 flags = rta_getattr_u16(tb[LWTUNNEL_IP6_FLAGS]);
397 if (flags & TUNNEL_KEY)
398 print_bool(PRINT_ANY, "key", "key ", true);
399 if (flags & TUNNEL_CSUM)
400 print_bool(PRINT_ANY, "csum", "csum ", true);
401 if (flags & TUNNEL_SEQ)
402 print_bool(PRINT_ANY, "seq", "seq ", true);
403 }
d95cdcf5
PA
404}
405
b15f440e
TG
406static void print_encap_bpf(FILE *fp, struct rtattr *encap)
407{
408 struct rtattr *tb[LWT_BPF_MAX+1];
409
410 parse_rtattr_nested(tb, LWT_BPF_MAX, encap);
411
412 if (tb[LWT_BPF_IN])
413 print_encap_bpf_prog(fp, tb[LWT_BPF_IN], "in");
414 if (tb[LWT_BPF_OUT])
415 print_encap_bpf_prog(fp, tb[LWT_BPF_OUT], "out");
416 if (tb[LWT_BPF_XMIT])
417 print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit");
418 if (tb[LWT_BPF_XMIT_HEADROOM])
663c3cb2
SH
419 print_uint(PRINT_ANY, "headroom",
420 " %u ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
b15f440e
TG
421}
422
1e529305
RP
423void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
424 struct rtattr *encap)
425{
426 int et;
427
428 if (!encap_type)
429 return;
430
431 et = rta_getattr_u16(encap_type);
432
663c3cb2 433 print_string(PRINT_ANY, "encap", " encap %s ", format_encap_type(et));
1e529305
RP
434
435 switch (et) {
436 case LWTUNNEL_ENCAP_MPLS:
437 print_encap_mpls(fp, encap);
438 break;
439 case LWTUNNEL_ENCAP_IP:
440 print_encap_ip(fp, encap);
441 break;
5866bddd
TH
442 case LWTUNNEL_ENCAP_ILA:
443 print_encap_ila(fp, encap);
444 break;
d95cdcf5
PA
445 case LWTUNNEL_ENCAP_IP6:
446 print_encap_ip6(fp, encap);
447 break;
b15f440e
TG
448 case LWTUNNEL_ENCAP_BPF:
449 print_encap_bpf(fp, encap);
450 break;
e8493916
DL
451 case LWTUNNEL_ENCAP_SEG6:
452 print_encap_seg6(fp, encap);
453 break;
8db158b9
DL
454 case LWTUNNEL_ENCAP_SEG6_LOCAL:
455 print_encap_seg6local(fp, encap);
456 break;
e8493916
DL
457 }
458}
459
00e76d4d
DL
460static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap)
461{
462 struct ipv6_sr_hdr *srh;
463 int nsegs = 0;
464 int srhlen;
465 char *s;
466 int i;
467
468 s = segbuf;
469 for (i = 0; *s; *s++ == ',' ? i++ : *s);
470 nsegs = i + 1;
471
472 if (!encap)
473 nsegs++;
474
475 srhlen = 8 + 16*nsegs;
476
477 if (hmac)
478 srhlen += 40;
479
480 srh = malloc(srhlen);
481 memset(srh, 0, srhlen);
482
483 srh->hdrlen = (srhlen >> 3) - 1;
484 srh->type = 4;
485 srh->segments_left = nsegs - 1;
486 srh->first_segment = nsegs - 1;
487
488 if (hmac)
489 srh->flags |= SR6_FLAG1_HMAC;
490
491 i = srh->first_segment;
492 for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
6caad8f5
SP
493 inet_prefix addr;
494
495 get_addr(&addr, s, AF_INET6);
496 memcpy(&srh->segments[i], addr.data, sizeof(struct in6_addr));
00e76d4d
DL
497 i--;
498 }
499
500 if (hmac) {
501 struct sr6_tlv_hmac *tlv;
502
503 tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40);
504 tlv->tlvhdr.type = SR6_TLV_HMAC;
505 tlv->tlvhdr.len = 38;
506 tlv->hmackeyid = htonl(hmac);
507 }
508
509 return srh;
510}
511
e8493916
DL
512static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
513 char ***argvp)
514{
515 int mode_ok = 0, segs_ok = 0, hmac_ok = 0;
516 struct seg6_iptunnel_encap *tuninfo;
517 struct ipv6_sr_hdr *srh;
518 char **argv = *argvp;
3b5c5ef0 519 char segbuf[1024] = "";
e8493916
DL
520 int argc = *argcp;
521 int encap = -1;
522 __u32 hmac = 0;
e5da392f 523 int ret = 0;
e8493916 524 int srhlen;
e8493916
DL
525
526 while (argc > 0) {
527 if (strcmp(*argv, "mode") == 0) {
528 NEXT_ARG();
529 if (mode_ok++)
530 duparg2("mode", *argv);
cf87da41
DL
531 encap = read_seg6mode_type(*argv);
532 if (encap < 0)
e8493916
DL
533 invarg("\"mode\" value is invalid\n", *argv);
534 } else if (strcmp(*argv, "segs") == 0) {
535 NEXT_ARG();
536 if (segs_ok++)
537 duparg2("segs", *argv);
538 if (encap == -1)
539 invarg("\"segs\" provided before \"mode\"\n",
540 *argv);
541
18f156bf 542 strlcpy(segbuf, *argv, 1024);
e8493916
DL
543 } else if (strcmp(*argv, "hmac") == 0) {
544 NEXT_ARG();
545 if (hmac_ok++)
546 duparg2("hmac", *argv);
547 get_u32(&hmac, *argv, 0);
548 } else {
549 break;
550 }
551 argc--; argv++;
552 }
553
00e76d4d
DL
554 srh = parse_srh(segbuf, hmac, encap);
555 srhlen = (srh->hdrlen + 1) << 3;
e8493916
DL
556
557 tuninfo = malloc(sizeof(*tuninfo) + srhlen);
558 memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
559
cf87da41 560 tuninfo->mode = encap;
e8493916 561
00e76d4d 562 memcpy(tuninfo->srh, srh, srhlen);
e8493916 563
bd59e5b1 564 if (rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
e5da392f
PS
565 sizeof(*tuninfo) + srhlen)) {
566 ret = -1;
567 goto out;
568 }
e8493916
DL
569
570 *argcp = argc + 1;
571 *argvp = argv - 1;
572
e5da392f
PS
573out:
574 free(tuninfo);
575 free(srh);
576
577 return ret;
1e529305
RP
578}
579
04cb3c0d
MX
580struct lwt_x {
581 struct rtattr *rta;
582 size_t len;
583};
584
585static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation)
586{
587 struct lwt_x *x = lwt_ptr;
588
589 rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd);
590 rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation,
591 strlen(annotation) + 1);
592}
593
594static const struct bpf_cfg_ops bpf_cb_ops = {
595 .ebpf_cb = bpf_lwt_cb,
596};
597
598static int lwt_parse_bpf(struct rtattr *rta, size_t len,
599 int *argcp, char ***argvp,
600 int attr, const enum bpf_prog_type bpf_type)
601{
602 struct bpf_cfg_in cfg = {
603 .type = bpf_type,
604 .argc = *argcp,
605 .argv = *argvp,
606 };
607 struct lwt_x x = {
608 .rta = rta,
609 .len = len,
610 };
611 struct rtattr *nest;
612 int err;
613
614 nest = rta_nest(rta, len, attr);
615 err = bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &x);
616 if (err < 0) {
617 fprintf(stderr, "Failed to parse eBPF program: %s\n",
618 strerror(-err));
619 return -1;
620 }
621 rta_nest_end(rta, nest);
622
623 *argcp = cfg.argc;
624 *argvp = cfg.argv;
625
626 return 0;
627}
628
8db158b9
DL
629static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
630 char ***argvp)
631{
632 int segs_ok = 0, hmac_ok = 0, table_ok = 0, nh4_ok = 0, nh6_ok = 0;
04cb3c0d 633 int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0, bpf_ok = 0;
8db158b9
DL
634 __u32 action = 0, table, iif, oif;
635 struct ipv6_sr_hdr *srh;
636 char **argv = *argvp;
637 int argc = *argcp;
638 char segbuf[1024];
639 inet_prefix addr;
640 __u32 hmac = 0;
bd59e5b1 641 int ret = 0;
8db158b9
DL
642
643 while (argc > 0) {
644 if (strcmp(*argv, "action") == 0) {
645 NEXT_ARG();
646 if (action_ok++)
647 duparg2("action", *argv);
648 action = read_action_type(*argv);
649 if (!action)
650 invarg("\"action\" value is invalid\n", *argv);
bd59e5b1
PS
651 ret = rta_addattr32(rta, len, SEG6_LOCAL_ACTION,
652 action);
8db158b9
DL
653 } else if (strcmp(*argv, "table") == 0) {
654 NEXT_ARG();
655 if (table_ok++)
656 duparg2("table", *argv);
657 get_u32(&table, *argv, 0);
bd59e5b1 658 ret = rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
8db158b9
DL
659 } else if (strcmp(*argv, "nh4") == 0) {
660 NEXT_ARG();
661 if (nh4_ok++)
662 duparg2("nh4", *argv);
663 get_addr(&addr, *argv, AF_INET);
bd59e5b1
PS
664 ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH4,
665 &addr.data, addr.bytelen);
8db158b9
DL
666 } else if (strcmp(*argv, "nh6") == 0) {
667 NEXT_ARG();
668 if (nh6_ok++)
669 duparg2("nh6", *argv);
670 get_addr(&addr, *argv, AF_INET6);
bd59e5b1
PS
671 ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH6,
672 &addr.data, addr.bytelen);
8db158b9
DL
673 } else if (strcmp(*argv, "iif") == 0) {
674 NEXT_ARG();
675 if (iif_ok++)
676 duparg2("iif", *argv);
7a14358b 677 iif = ll_name_to_index(*argv);
8db158b9 678 if (!iif)
fe99adbc 679 exit(nodev(*argv));
bd59e5b1 680 ret = rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
8db158b9
DL
681 } else if (strcmp(*argv, "oif") == 0) {
682 NEXT_ARG();
683 if (oif_ok++)
684 duparg2("oif", *argv);
7a14358b 685 oif = ll_name_to_index(*argv);
8db158b9 686 if (!oif)
fe99adbc 687 exit(nodev(*argv));
bd59e5b1 688 ret = rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
8db158b9
DL
689 } else if (strcmp(*argv, "srh") == 0) {
690 NEXT_ARG();
691 if (srh_ok++)
692 duparg2("srh", *argv);
693 if (strcmp(*argv, "segs") != 0)
694 invarg("missing \"segs\" attribute for srh\n",
695 *argv);
696 NEXT_ARG();
697 if (segs_ok++)
698 duparg2("segs", *argv);
699 strncpy(segbuf, *argv, 1024);
700 segbuf[1023] = 0;
701 if (!NEXT_ARG_OK())
702 break;
703 NEXT_ARG();
704 if (strcmp(*argv, "hmac") == 0) {
705 NEXT_ARG();
706 if (hmac_ok++)
707 duparg2("hmac", *argv);
708 get_u32(&hmac, *argv, 0);
709 } else {
710 continue;
711 }
04cb3c0d
MX
712 } else if (strcmp(*argv, "endpoint") == 0) {
713 NEXT_ARG();
714 if (bpf_ok++)
715 duparg2("endpoint", *argv);
716
717 if (lwt_parse_bpf(rta, len, &argc, &argv, SEG6_LOCAL_BPF,
718 BPF_PROG_TYPE_LWT_SEG6LOCAL) < 0)
719 exit(-1);
8db158b9
DL
720 } else {
721 break;
722 }
bd59e5b1
PS
723 if (ret)
724 return ret;
8db158b9
DL
725 argc--; argv++;
726 }
727
728 if (!action) {
729 fprintf(stderr, "Missing action type\n");
730 exit(-1);
731 }
732
733 if (srh_ok) {
734 int srhlen;
735
736 srh = parse_srh(segbuf, hmac,
737 action == SEG6_LOCAL_ACTION_END_B6_ENCAP);
738 srhlen = (srh->hdrlen + 1) << 3;
bd59e5b1 739 ret = rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
8db158b9
DL
740 free(srh);
741 }
742
743 *argcp = argc + 1;
744 *argvp = argv - 1;
745
bd59e5b1 746 return ret;
8db158b9
DL
747}
748
b723368c
SH
749static int parse_encap_mpls(struct rtattr *rta, size_t len,
750 int *argcp, char ***argvp)
1e529305
RP
751{
752 inet_prefix addr;
753 int argc = *argcp;
754 char **argv = *argvp;
9688cf3b 755 int ttl_ok = 0;
1e529305
RP
756
757 if (get_addr(&addr, *argv, AF_MPLS)) {
b723368c
SH
758 fprintf(stderr,
759 "Error: an inet address is expected rather than \"%s\".\n",
760 *argv);
1e529305
RP
761 exit(1);
762 }
763
bd59e5b1
PS
764 if (rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST,
765 &addr.data, addr.bytelen))
766 return -1;
1e529305 767
9688cf3b
RS
768 argc--;
769 argv++;
770
771 while (argc > 0) {
772 if (strcmp(*argv, "ttl") == 0) {
773 __u8 ttl;
774
775 NEXT_ARG();
776 if (ttl_ok++)
777 duparg2("ttl", *argv);
778 if (get_u8(&ttl, *argv, 0))
779 invarg("\"ttl\" value is invalid\n", *argv);
bd59e5b1
PS
780 if (rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl))
781 return -1;
9688cf3b
RS
782 } else {
783 break;
784 }
785 argc--; argv++;
786 }
787
788 /* argv is currently the first unparsed argument,
789 * but the lwt_parse_encap() caller will move to the next,
790 * so step back
791 */
792 *argcp = argc + 1;
793 *argvp = argv - 1;
1e529305
RP
794
795 return 0;
796}
797
b723368c
SH
798static int parse_encap_ip(struct rtattr *rta, size_t len,
799 int *argcp, char ***argvp)
1e529305 800{
94a8722f 801 int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
3d65cefb 802 int key_ok = 0, csum_ok = 0, seq_ok = 0;
1e529305
RP
803 char **argv = *argvp;
804 int argc = *argcp;
bd59e5b1 805 int ret = 0;
3d65cefb 806 __u16 flags = 0;
1e529305
RP
807
808 while (argc > 0) {
809 if (strcmp(*argv, "id") == 0) {
810 __u64 id;
56f5daac 811
1e529305
RP
812 NEXT_ARG();
813 if (id_ok++)
814 duparg2("id", *argv);
9f7401fa 815 if (get_be64(&id, *argv, 0))
1e529305 816 invarg("\"id\" value is invalid\n", *argv);
bd59e5b1 817 ret = rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
1e529305
RP
818 } else if (strcmp(*argv, "dst") == 0) {
819 inet_prefix addr;
56f5daac 820
1e529305
RP
821 NEXT_ARG();
822 if (dst_ok++)
823 duparg2("dst", *argv);
824 get_addr(&addr, *argv, AF_INET);
bd59e5b1
PS
825 ret = rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
826 &addr.data, addr.bytelen);
94a8722f
SL
827 } else if (strcmp(*argv, "src") == 0) {
828 inet_prefix addr;
829
830 NEXT_ARG();
831 if (src_ok++)
832 duparg2("src", *argv);
833 get_addr(&addr, *argv, AF_INET);
34212c73
DA
834 ret = rta_addattr_l(rta, len, LWTUNNEL_IP_SRC,
835 &addr.data, addr.bytelen);
1e529305
RP
836 } else if (strcmp(*argv, "tos") == 0) {
837 __u32 tos;
56f5daac 838
1e529305
RP
839 NEXT_ARG();
840 if (tos_ok++)
841 duparg2("tos", *argv);
842 if (rtnl_dsfield_a2n(&tos, *argv))
843 invarg("\"tos\" value is invalid\n", *argv);
bd59e5b1 844 ret = rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
1e529305
RP
845 } else if (strcmp(*argv, "ttl") == 0) {
846 __u8 ttl;
56f5daac 847
1e529305
RP
848 NEXT_ARG();
849 if (ttl_ok++)
850 duparg2("ttl", *argv);
851 if (get_u8(&ttl, *argv, 0))
852 invarg("\"ttl\" value is invalid\n", *argv);
bd59e5b1 853 ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
3d65cefb 854 } else if (strcmp(*argv, "key") == 0) {
855 if (key_ok++)
856 duparg2("key", *argv);
857 flags |= TUNNEL_KEY;
858 } else if (strcmp(*argv, "csum") == 0) {
859 if (csum_ok++)
860 duparg2("csum", *argv);
861 flags |= TUNNEL_CSUM;
862 } else if (strcmp(*argv, "seq") == 0) {
863 if (seq_ok++)
864 duparg2("seq", *argv);
865 flags |= TUNNEL_SEQ;
1e529305
RP
866 } else {
867 break;
868 }
bd59e5b1
PS
869 if (ret)
870 break;
f0df4081 871 argc--; argv++;
1e529305
RP
872 }
873
3d65cefb 874 if (flags)
875 ret = rta_addattr16(rta, len, LWTUNNEL_IP_FLAGS, flags);
876
f0df4081
PA
877 /* argv is currently the first unparsed argument,
878 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
879 * so step back
880 */
f0df4081
PA
881 *argcp = argc + 1;
882 *argvp = argv - 1;
1e529305 883
bd59e5b1 884 return ret;
1e529305
RP
885}
886
5866bddd
TH
887static int parse_encap_ila(struct rtattr *rta, size_t len,
888 int *argcp, char ***argvp)
889{
890 __u64 locator;
891 int argc = *argcp;
892 char **argv = *argvp;
bd59e5b1 893 int ret = 0;
5866bddd
TH
894
895 if (get_addr64(&locator, *argv) < 0) {
896 fprintf(stderr, "Bad locator: %s\n", *argv);
897 exit(1);
898 }
899
ed67f838
TH
900 argc--; argv++;
901
05d978e0 902 if (rta_addattr64(rta, len, ILA_ATTR_LOCATOR, locator))
bd59e5b1 903 return -1;
5866bddd 904
ed67f838
TH
905 while (argc > 0) {
906 if (strcmp(*argv, "csum-mode") == 0) {
08806fb0 907 int csum_mode;
ed67f838
TH
908
909 NEXT_ARG();
910
911 csum_mode = ila_csum_name2mode(*argv);
912 if (csum_mode < 0)
b723368c
SH
913 invarg("\"csum-mode\" value is invalid\n",
914 *argv);
ed67f838 915
05d978e0 916 ret = rta_addattr8(rta, len, ILA_ATTR_CSUM_MODE,
bd59e5b1 917 (__u8)csum_mode);
ed67f838 918
86905c8f
TH
919 argc--; argv++;
920 } else if (strcmp(*argv, "ident-type") == 0) {
921 int ident_type;
922
923 NEXT_ARG();
924
925 ident_type = ila_ident_name2type(*argv);
926 if (ident_type < 0)
927 invarg("\"ident-type\" value is invalid\n",
928 *argv);
929
05d978e0 930 ret = rta_addattr8(rta, len, ILA_ATTR_IDENT_TYPE,
bd59e5b1 931 (__u8)ident_type);
86905c8f
TH
932
933 argc--; argv++;
934 } else if (strcmp(*argv, "hook-type") == 0) {
935 int hook_type;
936
937 NEXT_ARG();
938
939 hook_type = ila_hook_name2type(*argv);
940 if (hook_type < 0)
941 invarg("\"hook-type\" value is invalid\n",
942 *argv);
943
05d978e0 944 ret = rta_addattr8(rta, len, ILA_ATTR_HOOK_TYPE,
bd59e5b1 945 (__u8)hook_type);
86905c8f 946
ed67f838
TH
947 argc--; argv++;
948 } else {
949 break;
950 }
bd59e5b1
PS
951 if (ret)
952 break;
ed67f838
TH
953 }
954
955 /* argv is currently the first unparsed argument,
956 * but the lwt_parse_encap() caller will move to the next,
957 * so step back
958 */
959 *argcp = argc + 1;
960 *argvp = argv - 1;
5866bddd 961
bd59e5b1 962 return ret;
5866bddd 963}
1e529305 964
b723368c
SH
965static int parse_encap_ip6(struct rtattr *rta, size_t len,
966 int *argcp, char ***argvp)
d95cdcf5 967{
94a8722f 968 int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
3d65cefb 969 int key_ok = 0, csum_ok = 0, seq_ok = 0;
d95cdcf5
PA
970 char **argv = *argvp;
971 int argc = *argcp;
bd59e5b1 972 int ret = 0;
3d65cefb 973 __u16 flags = 0;
d95cdcf5
PA
974
975 while (argc > 0) {
976 if (strcmp(*argv, "id") == 0) {
977 __u64 id;
56f5daac 978
d95cdcf5
PA
979 NEXT_ARG();
980 if (id_ok++)
981 duparg2("id", *argv);
9f7401fa 982 if (get_be64(&id, *argv, 0))
d95cdcf5 983 invarg("\"id\" value is invalid\n", *argv);
bd59e5b1 984 ret = rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
d95cdcf5
PA
985 } else if (strcmp(*argv, "dst") == 0) {
986 inet_prefix addr;
56f5daac 987
d95cdcf5
PA
988 NEXT_ARG();
989 if (dst_ok++)
990 duparg2("dst", *argv);
991 get_addr(&addr, *argv, AF_INET6);
bd59e5b1
PS
992 ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
993 &addr.data, addr.bytelen);
94a8722f
SL
994 } else if (strcmp(*argv, "src") == 0) {
995 inet_prefix addr;
996
997 NEXT_ARG();
998 if (src_ok++)
999 duparg2("src", *argv);
1000 get_addr(&addr, *argv, AF_INET6);
34212c73
DA
1001 ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_SRC,
1002 &addr.data, addr.bytelen);
d95cdcf5
PA
1003 } else if (strcmp(*argv, "tc") == 0) {
1004 __u32 tc;
56f5daac 1005
d95cdcf5
PA
1006 NEXT_ARG();
1007 if (tos_ok++)
1008 duparg2("tc", *argv);
1009 if (rtnl_dsfield_a2n(&tc, *argv))
1010 invarg("\"tc\" value is invalid\n", *argv);
bd59e5b1 1011 ret = rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
d95cdcf5
PA
1012 } else if (strcmp(*argv, "hoplimit") == 0) {
1013 __u8 hoplimit;
56f5daac 1014
d95cdcf5
PA
1015 NEXT_ARG();
1016 if (ttl_ok++)
1017 duparg2("hoplimit", *argv);
1018 if (get_u8(&hoplimit, *argv, 0))
b723368c
SH
1019 invarg("\"hoplimit\" value is invalid\n",
1020 *argv);
bd59e5b1
PS
1021 ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
1022 hoplimit);
3d65cefb 1023 } else if (strcmp(*argv, "key") == 0) {
1024 if (key_ok++)
1025 duparg2("key", *argv);
1026 flags |= TUNNEL_KEY;
1027 } else if (strcmp(*argv, "csum") == 0) {
1028 if (csum_ok++)
1029 duparg2("csum", *argv);
1030 flags |= TUNNEL_CSUM;
1031 } else if (strcmp(*argv, "seq") == 0) {
1032 if (seq_ok++)
1033 duparg2("seq", *argv);
1034 flags |= TUNNEL_SEQ;
d95cdcf5
PA
1035 } else {
1036 break;
1037 }
bd59e5b1
PS
1038 if (ret)
1039 break;
d95cdcf5
PA
1040 argc--; argv++;
1041 }
1042
3d65cefb 1043 if (flags)
1044 ret = rta_addattr16(rta, len, LWTUNNEL_IP6_FLAGS, flags);
1045
d95cdcf5
PA
1046 /* argv is currently the first unparsed argument,
1047 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
1048 * so step back
1049 */
d95cdcf5
PA
1050 *argcp = argc + 1;
1051 *argvp = argv - 1;
1052
bd59e5b1 1053 return ret;
d95cdcf5
PA
1054}
1055
b15f440e
TG
1056static void lwt_bpf_usage(void)
1057{
1058 fprintf(stderr, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
1059 fprintf(stderr, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
1060 exit(-1);
1061}
1062
1063static int parse_encap_bpf(struct rtattr *rta, size_t len, int *argcp,
1064 char ***argvp)
1065{
1066 char **argv = *argvp;
1067 int argc = *argcp;
1068 int headroom_set = 0;
1069
1070 while (argc > 0) {
1071 if (strcmp(*argv, "in") == 0) {
1072 NEXT_ARG();
1073 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_IN,
1074 BPF_PROG_TYPE_LWT_IN) < 0)
1075 return -1;
1076 } else if (strcmp(*argv, "out") == 0) {
1077 NEXT_ARG();
1078 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_OUT,
1079 BPF_PROG_TYPE_LWT_OUT) < 0)
1080 return -1;
1081 } else if (strcmp(*argv, "xmit") == 0) {
1082 NEXT_ARG();
1083 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_XMIT,
1084 BPF_PROG_TYPE_LWT_XMIT) < 0)
1085 return -1;
1086 } else if (strcmp(*argv, "headroom") == 0) {
1087 unsigned int headroom;
1088
1089 NEXT_ARG();
1090 if (get_unsigned(&headroom, *argv, 0) || headroom == 0)
1091 invarg("headroom is invalid\n", *argv);
1092 if (!headroom_set)
05d978e0 1093 rta_addattr32(rta, len, LWT_BPF_XMIT_HEADROOM,
b15f440e
TG
1094 headroom);
1095 headroom_set = 1;
1096 } else if (strcmp(*argv, "help") == 0) {
1097 lwt_bpf_usage();
1098 } else {
1099 break;
1100 }
1101 NEXT_ARG_FWD();
1102 }
1103
1104 /* argv is currently the first unparsed argument,
1105 * but the lwt_parse_encap() caller will move to the next,
b723368c
SH
1106 * so step back
1107 */
b15f440e
TG
1108 *argcp = argc + 1;
1109 *argvp = argv - 1;
1110
1111 return 0;
1112}
1113
1e529305
RP
1114int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
1115{
1116 struct rtattr *nest;
1117 int argc = *argcp;
1118 char **argv = *argvp;
1119 __u16 type;
bd59e5b1 1120 int ret = 0;
1e529305
RP
1121
1122 NEXT_ARG();
1123 type = read_encap_type(*argv);
1124 if (!type)
1125 invarg("\"encap type\" value is invalid\n", *argv);
1126
1127 NEXT_ARG();
1128 if (argc <= 1) {
b723368c
SH
1129 fprintf(stderr,
1130 "Error: unexpected end of line after \"encap\"\n");
1e529305
RP
1131 exit(-1);
1132 }
1133
05d978e0 1134 nest = rta_nest(rta, len, RTA_ENCAP);
1e529305
RP
1135 switch (type) {
1136 case LWTUNNEL_ENCAP_MPLS:
bd59e5b1 1137 ret = parse_encap_mpls(rta, len, &argc, &argv);
1e529305
RP
1138 break;
1139 case LWTUNNEL_ENCAP_IP:
bd59e5b1 1140 ret = parse_encap_ip(rta, len, &argc, &argv);
1e529305 1141 break;
5866bddd 1142 case LWTUNNEL_ENCAP_ILA:
bd59e5b1 1143 ret = parse_encap_ila(rta, len, &argc, &argv);
5866bddd 1144 break;
d95cdcf5 1145 case LWTUNNEL_ENCAP_IP6:
bd59e5b1 1146 ret = parse_encap_ip6(rta, len, &argc, &argv);
d95cdcf5 1147 break;
b15f440e
TG
1148 case LWTUNNEL_ENCAP_BPF:
1149 if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
1150 exit(-1);
1151 break;
e8493916 1152 case LWTUNNEL_ENCAP_SEG6:
bd59e5b1 1153 ret = parse_encap_seg6(rta, len, &argc, &argv);
e8493916 1154 break;
8db158b9 1155 case LWTUNNEL_ENCAP_SEG6_LOCAL:
bd59e5b1 1156 ret = parse_encap_seg6local(rta, len, &argc, &argv);
8db158b9 1157 break;
1e529305
RP
1158 default:
1159 fprintf(stderr, "Error: unsupported encap type\n");
1160 break;
1161 }
bd59e5b1
PS
1162 if (ret)
1163 return ret;
1164
1e529305
RP
1165 rta_nest_end(rta, nest);
1166
05d978e0 1167 ret = rta_addattr16(rta, len, RTA_ENCAP_TYPE, type);
1e529305
RP
1168
1169 *argcp = argc;
1170 *argvp = argv;
1171
bd59e5b1 1172 return ret;
1e529305 1173}