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.
9 * Authors: Roopa Prabhu, <roopa@cumulusnetworks.com>
10 * Thomas Graf <tgraf@suug.ch>
19 #include <linux/ila.h>
20 #include <linux/lwtunnel.h>
21 #include <linux/mpls_iptunnel.h>
27 #include "ip_common.h"
28 #include "ila_common.h"
30 #include <linux/seg6.h>
31 #include <linux/seg6_iptunnel.h>
32 #include <linux/rpl.h>
33 #include <linux/rpl_iptunnel.h>
34 #include <linux/seg6_hmac.h>
35 #include <linux/seg6_local.h>
36 #include <linux/if_tunnel.h>
38 static const char *format_encap_type(int type
)
41 case LWTUNNEL_ENCAP_MPLS
:
43 case LWTUNNEL_ENCAP_IP
:
45 case LWTUNNEL_ENCAP_IP6
:
47 case LWTUNNEL_ENCAP_ILA
:
49 case LWTUNNEL_ENCAP_BPF
:
51 case LWTUNNEL_ENCAP_SEG6
:
53 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
55 case LWTUNNEL_ENCAP_RPL
:
62 static void encap_type_usage(void)
66 fprintf(stderr
, "Usage: ip route ... encap TYPE [ OPTIONS ] [...]\n");
68 for (i
= 1; i
<= LWTUNNEL_ENCAP_MAX
; i
++)
69 fprintf(stderr
, "%s %s\n", format_encap_type(i
),
70 i
== 1 ? "TYPE := " : " ");
75 static int read_encap_type(const char *name
)
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
;
87 else if (strcmp(name
, "seg6") == 0)
88 return LWTUNNEL_ENCAP_SEG6
;
89 else if (strcmp(name
, "seg6local") == 0)
90 return LWTUNNEL_ENCAP_SEG6_LOCAL
;
91 else if (strcmp(name
, "rpl") == 0)
92 return LWTUNNEL_ENCAP_RPL
;
93 else if (strcmp(name
, "help") == 0)
96 return LWTUNNEL_ENCAP_NONE
;
99 static void print_srh(FILE *fp
, struct ipv6_sr_hdr
*srh
)
103 if (is_json_context())
104 open_json_array(PRINT_JSON
, "segs");
106 fprintf(fp
, "segs %d [ ", srh
->first_segment
+ 1);
108 for (i
= srh
->first_segment
; i
>= 0; i
--)
109 print_color_string(PRINT_ANY
, COLOR_INET6
,
111 rt_addr_n2a(AF_INET6
, 16, &srh
->segments
[i
]));
113 if (is_json_context())
114 close_json_array(PRINT_JSON
, NULL
);
118 if (sr_has_hmac(srh
)) {
119 unsigned int offset
= ((srh
->hdrlen
+ 1) << 3) - 40;
120 struct sr6_tlv_hmac
*tlv
;
122 tlv
= (struct sr6_tlv_hmac
*)((char *)srh
+ offset
);
123 print_0xhex(PRINT_ANY
, "hmac",
124 "hmac %llX ", ntohl(tlv
->hmackeyid
));
128 static const char *seg6_mode_types
[] = {
129 [SEG6_IPTUN_MODE_INLINE
] = "inline",
130 [SEG6_IPTUN_MODE_ENCAP
] = "encap",
131 [SEG6_IPTUN_MODE_L2ENCAP
] = "l2encap",
134 static const char *format_seg6mode_type(int mode
)
136 if (mode
< 0 || mode
> ARRAY_SIZE(seg6_mode_types
))
139 return seg6_mode_types
[mode
];
142 static int read_seg6mode_type(const char *mode
)
146 for (i
= 0; i
< ARRAY_SIZE(seg6_mode_types
); i
++) {
147 if (strcmp(mode
, seg6_mode_types
[i
]) == 0)
154 static void print_encap_seg6(FILE *fp
, struct rtattr
*encap
)
156 struct rtattr
*tb
[SEG6_IPTUNNEL_MAX
+1];
157 struct seg6_iptunnel_encap
*tuninfo
;
159 parse_rtattr_nested(tb
, SEG6_IPTUNNEL_MAX
, encap
);
161 if (!tb
[SEG6_IPTUNNEL_SRH
])
164 tuninfo
= RTA_DATA(tb
[SEG6_IPTUNNEL_SRH
]);
165 print_string(PRINT_ANY
, "mode",
166 "mode %s ", format_seg6mode_type(tuninfo
->mode
));
168 print_srh(fp
, tuninfo
->srh
);
171 static void print_rpl_srh(FILE *fp
, struct ipv6_rpl_sr_hdr
*srh
)
175 if (is_json_context())
176 open_json_array(PRINT_JSON
, "segs");
178 fprintf(fp
, "segs %d [ ", srh
->segments_left
);
180 for (i
= srh
->segments_left
- 1; i
>= 0; i
--) {
181 print_color_string(PRINT_ANY
, COLOR_INET6
,
183 rt_addr_n2a(AF_INET6
, 16, &srh
->rpl_segaddr
[i
]));
186 if (is_json_context())
187 close_json_array(PRINT_JSON
, NULL
);
192 static void print_encap_rpl(FILE *fp
, struct rtattr
*encap
)
194 struct rtattr
*tb
[RPL_IPTUNNEL_MAX
+ 1];
195 struct ipv6_rpl_sr_hdr
*srh
;
197 parse_rtattr_nested(tb
, RPL_IPTUNNEL_MAX
, encap
);
199 if (!tb
[RPL_IPTUNNEL_SRH
])
202 srh
= RTA_DATA(tb
[RPL_IPTUNNEL_SRH
]);
204 print_rpl_srh(fp
, srh
);
207 static 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",
222 [SEG6_LOCAL_ACTION_END_BPF
] = "End.BPF",
225 static const char *format_action_type(int action
)
227 if (action
< 0 || action
> SEG6_LOCAL_ACTION_MAX
)
230 return seg6_action_names
[action
] ?: "<unknown>";
233 static int read_action_type(const char *name
)
237 for (i
= 0; i
< SEG6_LOCAL_ACTION_MAX
+ 1; i
++) {
238 if (!seg6_action_names
[i
])
241 if (strcmp(seg6_action_names
[i
], name
) == 0)
245 return SEG6_LOCAL_ACTION_UNSPEC
;
248 static void print_encap_bpf_prog(FILE *fp
, struct rtattr
*encap
,
251 struct rtattr
*tb
[LWT_BPF_PROG_MAX
+1];
252 const char *progname
= NULL
;
254 parse_rtattr_nested(tb
, LWT_BPF_PROG_MAX
, encap
);
256 if (tb
[LWT_BPF_PROG_NAME
])
257 progname
= rta_getattr_str(tb
[LWT_BPF_PROG_NAME
]);
259 if (is_json_context())
260 print_string(PRINT_JSON
, str
, NULL
,
261 progname
? : "<unknown>");
263 fprintf(fp
, "%s ", str
);
265 fprintf(fp
, "%s ", progname
);
269 static void print_encap_seg6local(FILE *fp
, struct rtattr
*encap
)
271 struct rtattr
*tb
[SEG6_LOCAL_MAX
+ 1];
276 parse_rtattr_nested(tb
, SEG6_LOCAL_MAX
, encap
);
278 if (!tb
[SEG6_LOCAL_ACTION
])
281 action
= rta_getattr_u32(tb
[SEG6_LOCAL_ACTION
]);
283 print_string(PRINT_ANY
, "action",
284 "action %s ", format_action_type(action
));
286 if (tb
[SEG6_LOCAL_SRH
]) {
287 open_json_object("srh");
288 print_srh(fp
, RTA_DATA(tb
[SEG6_LOCAL_SRH
]));
292 if (tb
[SEG6_LOCAL_TABLE
])
293 print_string(PRINT_ANY
, "table", "table %s ",
294 rtnl_rttable_n2a(rta_getattr_u32(tb
[SEG6_LOCAL_TABLE
]),
297 if (tb
[SEG6_LOCAL_VRFTABLE
])
298 print_string(PRINT_ANY
, "vrftable", "vrftable %s ",
299 rtnl_rttable_n2a(rta_getattr_u32(tb
[SEG6_LOCAL_VRFTABLE
]),
302 if (tb
[SEG6_LOCAL_NH4
]) {
303 print_string(PRINT_ANY
, "nh4",
304 "nh4 %s ", rt_addr_n2a_rta(AF_INET
, tb
[SEG6_LOCAL_NH4
]));
307 if (tb
[SEG6_LOCAL_NH6
]) {
308 print_string(PRINT_ANY
, "nh6",
309 "nh6 %s ", rt_addr_n2a_rta(AF_INET6
, tb
[SEG6_LOCAL_NH6
]));
312 if (tb
[SEG6_LOCAL_IIF
]) {
313 int iif
= rta_getattr_u32(tb
[SEG6_LOCAL_IIF
]);
315 print_string(PRINT_ANY
, "iif",
316 "iif %s ", ll_index_to_name(iif
));
319 if (tb
[SEG6_LOCAL_OIF
]) {
320 int oif
= rta_getattr_u32(tb
[SEG6_LOCAL_OIF
]);
322 print_string(PRINT_ANY
, "oif",
323 "oif %s ", ll_index_to_name(oif
));
326 if (tb
[SEG6_LOCAL_BPF
])
327 print_encap_bpf_prog(fp
, tb
[SEG6_LOCAL_BPF
], "endpoint");
330 static void print_encap_mpls(FILE *fp
, struct rtattr
*encap
)
332 struct rtattr
*tb
[MPLS_IPTUNNEL_MAX
+1];
334 parse_rtattr_nested(tb
, MPLS_IPTUNNEL_MAX
, encap
);
336 if (tb
[MPLS_IPTUNNEL_DST
])
337 print_string(PRINT_ANY
, "dst", " %s ",
338 format_host_rta(AF_MPLS
, tb
[MPLS_IPTUNNEL_DST
]));
339 if (tb
[MPLS_IPTUNNEL_TTL
])
340 print_uint(PRINT_ANY
, "ttl", "ttl %u ",
341 rta_getattr_u8(tb
[MPLS_IPTUNNEL_TTL
]));
344 static void lwtunnel_print_geneve_opts(struct rtattr
*attr
)
346 struct rtattr
*tb
[LWTUNNEL_IP_OPT_GENEVE_MAX
+ 1];
347 struct rtattr
*i
= RTA_DATA(attr
);
348 int rem
= RTA_PAYLOAD(attr
);
349 char *name
= "geneve_opts";
350 int data_len
, offset
= 0;
351 char data
[rem
* 2 + 1];
356 print_string(PRINT_FP
, name
, "\t%s ", name
);
357 open_json_array(PRINT_JSON
, name
);
360 parse_rtattr(tb
, LWTUNNEL_IP_OPT_GENEVE_MAX
, i
, rem
);
361 class = rta_getattr_be16(tb
[LWTUNNEL_IP_OPT_GENEVE_CLASS
]);
362 type
= rta_getattr_u8(tb
[LWTUNNEL_IP_OPT_GENEVE_TYPE
]);
363 data_len
= RTA_PAYLOAD(tb
[LWTUNNEL_IP_OPT_GENEVE_DATA
]);
364 hexstring_n2a(RTA_DATA(tb
[LWTUNNEL_IP_OPT_GENEVE_DATA
]),
365 data_len
, data
, sizeof(data
));
366 offset
+= data_len
+ 20;
367 rem
-= data_len
+ 20;
368 i
= RTA_DATA(attr
) + offset
;
370 open_json_object(NULL
);
371 print_uint(PRINT_ANY
, "class", "%u", class);
372 print_uint(PRINT_ANY
, "type", ":%u", type
);
374 print_string(PRINT_ANY
, "data", ":%s,", data
);
376 print_string(PRINT_ANY
, "data", ":%s ", data
);
380 close_json_array(PRINT_JSON
, name
);
383 static void lwtunnel_print_vxlan_opts(struct rtattr
*attr
)
385 struct rtattr
*tb
[LWTUNNEL_IP_OPT_VXLAN_MAX
+ 1];
386 struct rtattr
*i
= RTA_DATA(attr
);
387 int rem
= RTA_PAYLOAD(attr
);
388 char *name
= "vxlan_opts";
391 parse_rtattr(tb
, LWTUNNEL_IP_OPT_VXLAN_MAX
, i
, rem
);
392 gbp
= rta_getattr_u32(tb
[LWTUNNEL_IP_OPT_VXLAN_GBP
]);
395 print_string(PRINT_FP
, name
, "\t%s ", name
);
396 open_json_array(PRINT_JSON
, name
);
397 open_json_object(NULL
);
398 print_uint(PRINT_ANY
, "gbp", "%u ", gbp
);
400 close_json_array(PRINT_JSON
, name
);
403 static void lwtunnel_print_erspan_opts(struct rtattr
*attr
)
405 struct rtattr
*tb
[LWTUNNEL_IP_OPT_ERSPAN_MAX
+ 1];
406 struct rtattr
*i
= RTA_DATA(attr
);
407 char *name
= "erspan_opts";
411 parse_rtattr(tb
, LWTUNNEL_IP_OPT_ERSPAN_MAX
, i
, RTA_PAYLOAD(attr
));
412 ver
= rta_getattr_u8(tb
[LWTUNNEL_IP_OPT_ERSPAN_VER
]);
414 idx
= rta_getattr_be32(tb
[LWTUNNEL_IP_OPT_ERSPAN_INDEX
]);
419 dir
= rta_getattr_u8(tb
[LWTUNNEL_IP_OPT_ERSPAN_DIR
]);
420 hwid
= rta_getattr_u8(tb
[LWTUNNEL_IP_OPT_ERSPAN_HWID
]);
424 print_string(PRINT_FP
, name
, "\t%s ", name
);
425 open_json_array(PRINT_JSON
, name
);
426 open_json_object(NULL
);
427 print_uint(PRINT_ANY
, "ver", "%u", ver
);
428 print_uint(PRINT_ANY
, "index", ":%u", idx
);
429 print_uint(PRINT_ANY
, "dir", ":%u", dir
);
430 print_uint(PRINT_ANY
, "hwid", ":%u ", hwid
);
432 close_json_array(PRINT_JSON
, name
);
435 static void lwtunnel_print_opts(struct rtattr
*attr
)
437 struct rtattr
*tb_opt
[LWTUNNEL_IP_OPTS_MAX
+ 1];
439 parse_rtattr_nested(tb_opt
, LWTUNNEL_IP_OPTS_MAX
, attr
);
440 if (tb_opt
[LWTUNNEL_IP_OPTS_GENEVE
])
441 lwtunnel_print_geneve_opts(tb_opt
[LWTUNNEL_IP_OPTS_GENEVE
]);
442 else if (tb_opt
[LWTUNNEL_IP_OPTS_VXLAN
])
443 lwtunnel_print_vxlan_opts(tb_opt
[LWTUNNEL_IP_OPTS_VXLAN
]);
444 else if (tb_opt
[LWTUNNEL_IP_OPTS_ERSPAN
])
445 lwtunnel_print_erspan_opts(tb_opt
[LWTUNNEL_IP_OPTS_ERSPAN
]);
448 static void print_encap_ip(FILE *fp
, struct rtattr
*encap
)
450 struct rtattr
*tb
[LWTUNNEL_IP_MAX
+1];
453 parse_rtattr_nested(tb
, LWTUNNEL_IP_MAX
, encap
);
455 if (tb
[LWTUNNEL_IP_ID
])
456 print_u64(PRINT_ANY
, "id", "id %llu ",
457 ntohll(rta_getattr_u64(tb
[LWTUNNEL_IP_ID
])));
459 if (tb
[LWTUNNEL_IP_SRC
])
460 print_color_string(PRINT_ANY
, COLOR_INET
,
462 rt_addr_n2a_rta(AF_INET
, tb
[LWTUNNEL_IP_SRC
]));
464 if (tb
[LWTUNNEL_IP_DST
])
465 print_color_string(PRINT_ANY
, COLOR_INET
,
467 rt_addr_n2a_rta(AF_INET
, tb
[LWTUNNEL_IP_DST
]));
469 if (tb
[LWTUNNEL_IP_TTL
])
470 print_uint(PRINT_ANY
, "ttl",
471 "ttl %u ", rta_getattr_u8(tb
[LWTUNNEL_IP_TTL
]));
473 if (tb
[LWTUNNEL_IP_TOS
])
474 print_uint(PRINT_ANY
, "tos",
475 "tos %d ", rta_getattr_u8(tb
[LWTUNNEL_IP_TOS
]));
477 if (tb
[LWTUNNEL_IP_FLAGS
]) {
478 flags
= rta_getattr_u16(tb
[LWTUNNEL_IP_FLAGS
]);
479 if (flags
& TUNNEL_KEY
)
480 print_bool(PRINT_ANY
, "key", "key ", true);
481 if (flags
& TUNNEL_CSUM
)
482 print_bool(PRINT_ANY
, "csum", "csum ", true);
483 if (flags
& TUNNEL_SEQ
)
484 print_bool(PRINT_ANY
, "seq", "seq ", true);
487 if (tb
[LWTUNNEL_IP_OPTS
])
488 lwtunnel_print_opts(tb
[LWTUNNEL_IP_OPTS
]);
491 static void print_encap_ila(FILE *fp
, struct rtattr
*encap
)
493 struct rtattr
*tb
[ILA_ATTR_MAX
+1];
495 parse_rtattr_nested(tb
, ILA_ATTR_MAX
, encap
);
497 if (tb
[ILA_ATTR_LOCATOR
]) {
498 char abuf
[ADDR64_BUF_SIZE
];
500 addr64_n2a(rta_getattr_u64(tb
[ILA_ATTR_LOCATOR
]),
502 print_string(PRINT_ANY
, "locator",
506 if (tb
[ILA_ATTR_CSUM_MODE
])
507 print_string(PRINT_ANY
, "csum_mode",
509 ila_csum_mode2name(rta_getattr_u8(tb
[ILA_ATTR_CSUM_MODE
])));
511 if (tb
[ILA_ATTR_IDENT_TYPE
])
512 print_string(PRINT_ANY
, "ident_type",
514 ila_ident_type2name(rta_getattr_u8(tb
[ILA_ATTR_IDENT_TYPE
])));
516 if (tb
[ILA_ATTR_HOOK_TYPE
])
517 print_string(PRINT_ANY
, "hook_type",
519 ila_hook_type2name(rta_getattr_u8(tb
[ILA_ATTR_HOOK_TYPE
])));
522 static void print_encap_ip6(FILE *fp
, struct rtattr
*encap
)
524 struct rtattr
*tb
[LWTUNNEL_IP6_MAX
+1];
527 parse_rtattr_nested(tb
, LWTUNNEL_IP6_MAX
, encap
);
529 if (tb
[LWTUNNEL_IP6_ID
])
530 print_u64(PRINT_ANY
, "id", "id %llu ",
531 ntohll(rta_getattr_u64(tb
[LWTUNNEL_IP6_ID
])));
533 if (tb
[LWTUNNEL_IP6_SRC
])
534 print_color_string(PRINT_ANY
, COLOR_INET6
,
536 rt_addr_n2a_rta(AF_INET6
, tb
[LWTUNNEL_IP6_SRC
]));
538 if (tb
[LWTUNNEL_IP6_DST
])
539 print_color_string(PRINT_ANY
, COLOR_INET6
,
541 rt_addr_n2a_rta(AF_INET6
, tb
[LWTUNNEL_IP6_DST
]));
543 if (tb
[LWTUNNEL_IP6_HOPLIMIT
])
544 print_u64(PRINT_ANY
, "hoplimit",
546 rta_getattr_u8(tb
[LWTUNNEL_IP6_HOPLIMIT
]));
548 if (tb
[LWTUNNEL_IP6_TC
])
549 print_uint(PRINT_ANY
, "tc",
550 "tc %u ", rta_getattr_u8(tb
[LWTUNNEL_IP6_TC
]));
552 if (tb
[LWTUNNEL_IP6_FLAGS
]) {
553 flags
= rta_getattr_u16(tb
[LWTUNNEL_IP6_FLAGS
]);
554 if (flags
& TUNNEL_KEY
)
555 print_bool(PRINT_ANY
, "key", "key ", true);
556 if (flags
& TUNNEL_CSUM
)
557 print_bool(PRINT_ANY
, "csum", "csum ", true);
558 if (flags
& TUNNEL_SEQ
)
559 print_bool(PRINT_ANY
, "seq", "seq ", true);
562 if (tb
[LWTUNNEL_IP6_OPTS
])
563 lwtunnel_print_opts(tb
[LWTUNNEL_IP6_OPTS
]);
566 static void print_encap_bpf(FILE *fp
, struct rtattr
*encap
)
568 struct rtattr
*tb
[LWT_BPF_MAX
+1];
570 parse_rtattr_nested(tb
, LWT_BPF_MAX
, encap
);
573 print_encap_bpf_prog(fp
, tb
[LWT_BPF_IN
], "in");
575 print_encap_bpf_prog(fp
, tb
[LWT_BPF_OUT
], "out");
576 if (tb
[LWT_BPF_XMIT
])
577 print_encap_bpf_prog(fp
, tb
[LWT_BPF_XMIT
], "xmit");
578 if (tb
[LWT_BPF_XMIT_HEADROOM
])
579 print_uint(PRINT_ANY
, "headroom",
580 " %u ", rta_getattr_u32(tb
[LWT_BPF_XMIT_HEADROOM
]));
583 void lwt_print_encap(FILE *fp
, struct rtattr
*encap_type
,
584 struct rtattr
*encap
)
591 et
= rta_getattr_u16(encap_type
);
593 print_string(PRINT_ANY
, "encap", " encap %s ", format_encap_type(et
));
596 case LWTUNNEL_ENCAP_MPLS
:
597 print_encap_mpls(fp
, encap
);
599 case LWTUNNEL_ENCAP_IP
:
600 print_encap_ip(fp
, encap
);
602 case LWTUNNEL_ENCAP_ILA
:
603 print_encap_ila(fp
, encap
);
605 case LWTUNNEL_ENCAP_IP6
:
606 print_encap_ip6(fp
, encap
);
608 case LWTUNNEL_ENCAP_BPF
:
609 print_encap_bpf(fp
, encap
);
611 case LWTUNNEL_ENCAP_SEG6
:
612 print_encap_seg6(fp
, encap
);
614 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
615 print_encap_seg6local(fp
, encap
);
617 case LWTUNNEL_ENCAP_RPL
:
618 print_encap_rpl(fp
, encap
);
623 static struct ipv6_sr_hdr
*parse_srh(char *segbuf
, int hmac
, bool encap
)
625 struct ipv6_sr_hdr
*srh
;
632 for (i
= 0; *s
; *s
++ == ',' ? i
++ : *s
);
638 srhlen
= 8 + 16*nsegs
;
643 srh
= malloc(srhlen
);
644 memset(srh
, 0, srhlen
);
646 srh
->hdrlen
= (srhlen
>> 3) - 1;
648 srh
->segments_left
= nsegs
- 1;
649 srh
->first_segment
= nsegs
- 1;
652 srh
->flags
|= SR6_FLAG1_HMAC
;
654 i
= srh
->first_segment
;
655 for (s
= strtok(segbuf
, ","); s
; s
= strtok(NULL
, ",")) {
658 get_addr(&addr
, s
, AF_INET6
);
659 memcpy(&srh
->segments
[i
], addr
.data
, sizeof(struct in6_addr
));
664 struct sr6_tlv_hmac
*tlv
;
666 tlv
= (struct sr6_tlv_hmac
*)((char *)srh
+ srhlen
- 40);
667 tlv
->tlvhdr
.type
= SR6_TLV_HMAC
;
668 tlv
->tlvhdr
.len
= 38;
669 tlv
->hmackeyid
= htonl(hmac
);
675 static int parse_encap_seg6(struct rtattr
*rta
, size_t len
, int *argcp
,
678 int mode_ok
= 0, segs_ok
= 0, hmac_ok
= 0;
679 struct seg6_iptunnel_encap
*tuninfo
;
680 struct ipv6_sr_hdr
*srh
;
681 char **argv
= *argvp
;
682 char segbuf
[1024] = "";
690 if (strcmp(*argv
, "mode") == 0) {
693 duparg2("mode", *argv
);
694 encap
= read_seg6mode_type(*argv
);
696 invarg("\"mode\" value is invalid\n", *argv
);
697 } else if (strcmp(*argv
, "segs") == 0) {
700 duparg2("segs", *argv
);
702 invarg("\"segs\" provided before \"mode\"\n",
705 strlcpy(segbuf
, *argv
, 1024);
706 } else if (strcmp(*argv
, "hmac") == 0) {
709 duparg2("hmac", *argv
);
710 get_u32(&hmac
, *argv
, 0);
717 srh
= parse_srh(segbuf
, hmac
, encap
);
718 srhlen
= (srh
->hdrlen
+ 1) << 3;
720 tuninfo
= malloc(sizeof(*tuninfo
) + srhlen
);
721 memset(tuninfo
, 0, sizeof(*tuninfo
) + srhlen
);
723 tuninfo
->mode
= encap
;
725 memcpy(tuninfo
->srh
, srh
, srhlen
);
727 if (rta_addattr_l(rta
, len
, SEG6_IPTUNNEL_SRH
, tuninfo
,
728 sizeof(*tuninfo
) + srhlen
)) {
743 static struct ipv6_rpl_sr_hdr
*parse_rpl_srh(char *segbuf
)
745 struct ipv6_rpl_sr_hdr
*srh
;
752 for (i
= 0; *s
; *s
++ == ',' ? i
++ : *s
);
755 srhlen
= 8 + 16 * nsegs
;
757 srh
= calloc(1, srhlen
);
759 srh
->hdrlen
= (srhlen
>> 3) - 1;
761 srh
->segments_left
= nsegs
;
763 for (s
= strtok(segbuf
, ","); s
; s
= strtok(NULL
, ",")) {
766 get_addr(&addr
, s
, AF_INET6
);
767 memcpy(&srh
->rpl_segaddr
[i
], addr
.data
, sizeof(struct in6_addr
));
774 static int parse_encap_rpl(struct rtattr
*rta
, size_t len
, int *argcp
,
777 struct ipv6_rpl_sr_hdr
*srh
;
778 char **argv
= *argvp
;
779 char segbuf
[1024] = "";
786 if (strcmp(*argv
, "segs") == 0) {
789 duparg2("segs", *argv
);
791 strlcpy(segbuf
, *argv
, 1024);
798 srh
= parse_rpl_srh(segbuf
);
799 srhlen
= (srh
->hdrlen
+ 1) << 3;
801 if (rta_addattr_l(rta
, len
, RPL_IPTUNNEL_SRH
, srh
,
821 static void bpf_lwt_cb(void *lwt_ptr
, int fd
, const char *annotation
)
823 struct lwt_x
*x
= lwt_ptr
;
825 rta_addattr32(x
->rta
, x
->len
, LWT_BPF_PROG_FD
, fd
);
826 rta_addattr_l(x
->rta
, x
->len
, LWT_BPF_PROG_NAME
, annotation
,
827 strlen(annotation
) + 1);
830 static const struct bpf_cfg_ops bpf_cb_ops
= {
831 .ebpf_cb
= bpf_lwt_cb
,
834 static int lwt_parse_bpf(struct rtattr
*rta
, size_t len
,
835 int *argcp
, char ***argvp
,
836 int attr
, const enum bpf_prog_type bpf_type
)
838 struct bpf_cfg_in cfg
= {
850 nest
= rta_nest(rta
, len
, attr
);
851 err
= bpf_parse_and_load_common(&cfg
, &bpf_cb_ops
, &x
);
853 fprintf(stderr
, "Failed to parse eBPF program: %s\n",
857 rta_nest_end(rta
, nest
);
865 static int parse_encap_seg6local(struct rtattr
*rta
, size_t len
, int *argcp
,
868 int segs_ok
= 0, hmac_ok
= 0, table_ok
= 0, vrftable_ok
= 0;
869 int nh4_ok
= 0, nh6_ok
= 0, iif_ok
= 0, oif_ok
= 0;
870 __u32 action
= 0, table
, vrftable
, iif
, oif
;
871 int action_ok
= 0, srh_ok
= 0, bpf_ok
= 0;
872 struct ipv6_sr_hdr
*srh
;
873 char **argv
= *argvp
;
881 if (strcmp(*argv
, "action") == 0) {
884 duparg2("action", *argv
);
885 action
= read_action_type(*argv
);
887 invarg("\"action\" value is invalid\n", *argv
);
888 ret
= rta_addattr32(rta
, len
, SEG6_LOCAL_ACTION
,
890 } else if (strcmp(*argv
, "table") == 0) {
893 duparg2("table", *argv
);
894 if (rtnl_rttable_a2n(&table
, *argv
))
895 invarg("invalid table id\n", *argv
);
896 ret
= rta_addattr32(rta
, len
, SEG6_LOCAL_TABLE
, table
);
897 } else if (strcmp(*argv
, "vrftable") == 0) {
900 duparg2("vrftable", *argv
);
901 if (rtnl_rttable_a2n(&vrftable
, *argv
))
902 invarg("invalid vrf table id\n", *argv
);
903 ret
= rta_addattr32(rta
, len
, SEG6_LOCAL_VRFTABLE
,
905 } else if (strcmp(*argv
, "nh4") == 0) {
908 duparg2("nh4", *argv
);
909 get_addr(&addr
, *argv
, AF_INET
);
910 ret
= rta_addattr_l(rta
, len
, SEG6_LOCAL_NH4
,
911 &addr
.data
, addr
.bytelen
);
912 } else if (strcmp(*argv
, "nh6") == 0) {
915 duparg2("nh6", *argv
);
916 get_addr(&addr
, *argv
, AF_INET6
);
917 ret
= rta_addattr_l(rta
, len
, SEG6_LOCAL_NH6
,
918 &addr
.data
, addr
.bytelen
);
919 } else if (strcmp(*argv
, "iif") == 0) {
922 duparg2("iif", *argv
);
923 iif
= ll_name_to_index(*argv
);
926 ret
= rta_addattr32(rta
, len
, SEG6_LOCAL_IIF
, iif
);
927 } else if (strcmp(*argv
, "oif") == 0) {
930 duparg2("oif", *argv
);
931 oif
= ll_name_to_index(*argv
);
934 ret
= rta_addattr32(rta
, len
, SEG6_LOCAL_OIF
, oif
);
935 } else if (strcmp(*argv
, "srh") == 0) {
938 duparg2("srh", *argv
);
939 if (strcmp(*argv
, "segs") != 0)
940 invarg("missing \"segs\" attribute for srh\n",
944 duparg2("segs", *argv
);
945 strncpy(segbuf
, *argv
, 1024);
950 if (strcmp(*argv
, "hmac") == 0) {
953 duparg2("hmac", *argv
);
954 get_u32(&hmac
, *argv
, 0);
958 } else if (strcmp(*argv
, "endpoint") == 0) {
961 duparg2("endpoint", *argv
);
963 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, SEG6_LOCAL_BPF
,
964 BPF_PROG_TYPE_LWT_SEG6LOCAL
) < 0)
975 fprintf(stderr
, "Missing action type\n");
982 srh
= parse_srh(segbuf
, hmac
,
983 action
== SEG6_LOCAL_ACTION_END_B6_ENCAP
);
984 srhlen
= (srh
->hdrlen
+ 1) << 3;
985 ret
= rta_addattr_l(rta
, len
, SEG6_LOCAL_SRH
, srh
, srhlen
);
995 static int parse_encap_mpls(struct rtattr
*rta
, size_t len
,
996 int *argcp
, char ***argvp
)
1000 char **argv
= *argvp
;
1003 if (get_addr(&addr
, *argv
, AF_MPLS
)) {
1005 "Error: an inet address is expected rather than \"%s\".\n",
1010 if (rta_addattr_l(rta
, len
, MPLS_IPTUNNEL_DST
,
1011 &addr
.data
, addr
.bytelen
))
1018 if (strcmp(*argv
, "ttl") == 0) {
1023 duparg2("ttl", *argv
);
1024 if (get_u8(&ttl
, *argv
, 0))
1025 invarg("\"ttl\" value is invalid\n", *argv
);
1026 if (rta_addattr8(rta
, len
, MPLS_IPTUNNEL_TTL
, ttl
))
1034 /* argv is currently the first unparsed argument,
1035 * but the lwt_parse_encap() caller will move to the next,
1044 static int lwtunnel_parse_geneve_opt(char *str
, size_t len
, struct rtattr
*rta
)
1046 struct rtattr
*nest
;
1050 nest
= rta_nest(rta
, len
, LWTUNNEL_IP_OPTS_GENEVE
| NLA_F_NESTED
);
1052 token
= strsep(&str
, ":");
1055 case LWTUNNEL_IP_OPT_GENEVE_CLASS
:
1061 err
= get_be16(&opt_class
, token
, 0);
1065 rta_addattr16(rta
, len
, i
, opt_class
);
1068 case LWTUNNEL_IP_OPT_GENEVE_TYPE
:
1074 err
= get_u8(&opt_type
, token
, 0);
1078 rta_addattr8(rta
, len
, i
, opt_type
);
1081 case LWTUNNEL_IP_OPT_GENEVE_DATA
:
1083 size_t token_len
= strlen(token
);
1088 opts
= malloc(token_len
/ 2);
1091 if (hex2mem(token
, opts
, token_len
/ 2) < 0) {
1095 rta_addattr_l(rta
, len
, i
, opts
, token_len
/ 2);
1101 fprintf(stderr
, "Unknown \"geneve_opts\" type\n");
1105 token
= strsep(&str
, ":");
1108 rta_nest_end(rta
, nest
);
1113 static int lwtunnel_parse_geneve_opts(char *str
, size_t len
, struct rtattr
*rta
)
1118 token
= strsep(&str
, ",");
1120 err
= lwtunnel_parse_geneve_opt(token
, len
, rta
);
1124 token
= strsep(&str
, ",");
1130 static int lwtunnel_parse_vxlan_opts(char *str
, size_t len
, struct rtattr
*rta
)
1132 struct rtattr
*nest
;
1136 nest
= rta_nest(rta
, len
, LWTUNNEL_IP_OPTS_VXLAN
| NLA_F_NESTED
);
1137 err
= get_u32(&gbp
, str
, 0);
1140 rta_addattr32(rta
, len
, LWTUNNEL_IP_OPT_VXLAN_GBP
, gbp
);
1142 rta_nest_end(rta
, nest
);
1146 static int lwtunnel_parse_erspan_opts(char *str
, size_t len
, struct rtattr
*rta
)
1148 struct rtattr
*nest
;
1152 nest
= rta_nest(rta
, len
, LWTUNNEL_IP_OPTS_ERSPAN
| NLA_F_NESTED
);
1154 token
= strsep(&str
, ":");
1157 case LWTUNNEL_IP_OPT_ERSPAN_VER
:
1163 err
= get_u8(&opt_type
, token
, 0);
1167 rta_addattr8(rta
, len
, i
, opt_type
);
1170 case LWTUNNEL_IP_OPT_ERSPAN_INDEX
:
1176 err
= get_be32(&opt_class
, token
, 0);
1180 rta_addattr32(rta
, len
, i
, opt_class
);
1183 case LWTUNNEL_IP_OPT_ERSPAN_DIR
:
1189 err
= get_u8(&opt_type
, token
, 0);
1193 rta_addattr8(rta
, len
, i
, opt_type
);
1196 case LWTUNNEL_IP_OPT_ERSPAN_HWID
:
1202 err
= get_u8(&opt_type
, token
, 0);
1206 rta_addattr8(rta
, len
, i
, opt_type
);
1210 fprintf(stderr
, "Unknown \"geneve_opts\" type\n");
1214 token
= strsep(&str
, ":");
1218 rta_nest_end(rta
, nest
);
1222 static int parse_encap_ip(struct rtattr
*rta
, size_t len
,
1223 int *argcp
, char ***argvp
)
1225 int id_ok
= 0, dst_ok
= 0, src_ok
= 0, tos_ok
= 0, ttl_ok
= 0;
1226 int key_ok
= 0, csum_ok
= 0, seq_ok
= 0, opts_ok
= 0;
1227 char **argv
= *argvp
;
1233 if (strcmp(*argv
, "id") == 0) {
1238 duparg2("id", *argv
);
1239 if (get_be64(&id
, *argv
, 0))
1240 invarg("\"id\" value is invalid\n", *argv
);
1241 ret
= rta_addattr64(rta
, len
, LWTUNNEL_IP_ID
, id
);
1242 } else if (strcmp(*argv
, "dst") == 0) {
1247 duparg2("dst", *argv
);
1248 get_addr(&addr
, *argv
, AF_INET
);
1249 ret
= rta_addattr_l(rta
, len
, LWTUNNEL_IP_DST
,
1250 &addr
.data
, addr
.bytelen
);
1251 } else if (strcmp(*argv
, "src") == 0) {
1256 duparg2("src", *argv
);
1257 get_addr(&addr
, *argv
, AF_INET
);
1258 ret
= rta_addattr_l(rta
, len
, LWTUNNEL_IP_SRC
,
1259 &addr
.data
, addr
.bytelen
);
1260 } else if (strcmp(*argv
, "tos") == 0) {
1265 duparg2("tos", *argv
);
1266 if (rtnl_dsfield_a2n(&tos
, *argv
))
1267 invarg("\"tos\" value is invalid\n", *argv
);
1268 ret
= rta_addattr8(rta
, len
, LWTUNNEL_IP_TOS
, tos
);
1269 } else if (strcmp(*argv
, "ttl") == 0) {
1274 duparg2("ttl", *argv
);
1275 if (get_u8(&ttl
, *argv
, 0))
1276 invarg("\"ttl\" value is invalid\n", *argv
);
1277 ret
= rta_addattr8(rta
, len
, LWTUNNEL_IP_TTL
, ttl
);
1278 } else if (strcmp(*argv
, "geneve_opts") == 0) {
1279 struct rtattr
*nest
;
1282 duparg2("opts", *argv
);
1286 nest
= rta_nest(rta
, len
,
1287 LWTUNNEL_IP_OPTS
| NLA_F_NESTED
);
1288 ret
= lwtunnel_parse_geneve_opts(*argv
, len
, rta
);
1290 invarg("\"geneve_opts\" value is invalid\n",
1292 rta_nest_end(rta
, nest
);
1293 } else if (strcmp(*argv
, "vxlan_opts") == 0) {
1294 struct rtattr
*nest
;
1297 duparg2("opts", *argv
);
1301 nest
= rta_nest(rta
, len
,
1302 LWTUNNEL_IP_OPTS
| NLA_F_NESTED
);
1303 ret
= lwtunnel_parse_vxlan_opts(*argv
, len
, rta
);
1305 invarg("\"vxlan_opts\" value is invalid\n",
1307 rta_nest_end(rta
, nest
);
1308 } else if (strcmp(*argv
, "erspan_opts") == 0) {
1309 struct rtattr
*nest
;
1312 duparg2("opts", *argv
);
1316 nest
= rta_nest(rta
, len
,
1317 LWTUNNEL_IP_OPTS
| NLA_F_NESTED
);
1318 ret
= lwtunnel_parse_erspan_opts(*argv
, len
, rta
);
1320 invarg("\"erspan_opts\" value is invalid\n",
1322 rta_nest_end(rta
, nest
);
1323 } else if (strcmp(*argv
, "key") == 0) {
1325 duparg2("key", *argv
);
1326 flags
|= TUNNEL_KEY
;
1327 } else if (strcmp(*argv
, "csum") == 0) {
1329 duparg2("csum", *argv
);
1330 flags
|= TUNNEL_CSUM
;
1331 } else if (strcmp(*argv
, "seq") == 0) {
1333 duparg2("seq", *argv
);
1334 flags
|= TUNNEL_SEQ
;
1344 ret
= rta_addattr16(rta
, len
, LWTUNNEL_IP_FLAGS
, flags
);
1346 /* argv is currently the first unparsed argument,
1347 * but the lwt_parse_encap() caller will move to the next,
1356 static int parse_encap_ila(struct rtattr
*rta
, size_t len
,
1357 int *argcp
, char ***argvp
)
1361 char **argv
= *argvp
;
1364 if (get_addr64(&locator
, *argv
) < 0) {
1365 fprintf(stderr
, "Bad locator: %s\n", *argv
);
1371 if (rta_addattr64(rta
, len
, ILA_ATTR_LOCATOR
, locator
))
1375 if (strcmp(*argv
, "csum-mode") == 0) {
1380 csum_mode
= ila_csum_name2mode(*argv
);
1382 invarg("\"csum-mode\" value is invalid\n",
1385 ret
= rta_addattr8(rta
, len
, ILA_ATTR_CSUM_MODE
,
1389 } else if (strcmp(*argv
, "ident-type") == 0) {
1394 ident_type
= ila_ident_name2type(*argv
);
1396 invarg("\"ident-type\" value is invalid\n",
1399 ret
= rta_addattr8(rta
, len
, ILA_ATTR_IDENT_TYPE
,
1403 } else if (strcmp(*argv
, "hook-type") == 0) {
1408 hook_type
= ila_hook_name2type(*argv
);
1410 invarg("\"hook-type\" value is invalid\n",
1413 ret
= rta_addattr8(rta
, len
, ILA_ATTR_HOOK_TYPE
,
1424 /* argv is currently the first unparsed argument,
1425 * but the lwt_parse_encap() caller will move to the next,
1434 static int parse_encap_ip6(struct rtattr
*rta
, size_t len
,
1435 int *argcp
, char ***argvp
)
1437 int id_ok
= 0, dst_ok
= 0, src_ok
= 0, tos_ok
= 0, ttl_ok
= 0;
1438 int key_ok
= 0, csum_ok
= 0, seq_ok
= 0, opts_ok
= 0;
1439 char **argv
= *argvp
;
1445 if (strcmp(*argv
, "id") == 0) {
1450 duparg2("id", *argv
);
1451 if (get_be64(&id
, *argv
, 0))
1452 invarg("\"id\" value is invalid\n", *argv
);
1453 ret
= rta_addattr64(rta
, len
, LWTUNNEL_IP6_ID
, id
);
1454 } else if (strcmp(*argv
, "dst") == 0) {
1459 duparg2("dst", *argv
);
1460 get_addr(&addr
, *argv
, AF_INET6
);
1461 ret
= rta_addattr_l(rta
, len
, LWTUNNEL_IP6_DST
,
1462 &addr
.data
, addr
.bytelen
);
1463 } else if (strcmp(*argv
, "src") == 0) {
1468 duparg2("src", *argv
);
1469 get_addr(&addr
, *argv
, AF_INET6
);
1470 ret
= rta_addattr_l(rta
, len
, LWTUNNEL_IP6_SRC
,
1471 &addr
.data
, addr
.bytelen
);
1472 } else if (strcmp(*argv
, "tc") == 0) {
1477 duparg2("tc", *argv
);
1478 if (rtnl_dsfield_a2n(&tc
, *argv
))
1479 invarg("\"tc\" value is invalid\n", *argv
);
1480 ret
= rta_addattr8(rta
, len
, LWTUNNEL_IP6_TC
, tc
);
1481 } else if (strcmp(*argv
, "hoplimit") == 0) {
1486 duparg2("hoplimit", *argv
);
1487 if (get_u8(&hoplimit
, *argv
, 0))
1488 invarg("\"hoplimit\" value is invalid\n",
1490 ret
= rta_addattr8(rta
, len
, LWTUNNEL_IP6_HOPLIMIT
,
1492 } else if (strcmp(*argv
, "geneve_opts") == 0) {
1493 struct rtattr
*nest
;
1496 duparg2("opts", *argv
);
1500 nest
= rta_nest(rta
, len
,
1501 LWTUNNEL_IP_OPTS
| NLA_F_NESTED
);
1502 ret
= lwtunnel_parse_geneve_opts(*argv
, len
, rta
);
1504 invarg("\"geneve_opts\" value is invalid\n",
1506 rta_nest_end(rta
, nest
);
1507 } else if (strcmp(*argv
, "vxlan_opts") == 0) {
1508 struct rtattr
*nest
;
1511 duparg2("opts", *argv
);
1515 nest
= rta_nest(rta
, len
,
1516 LWTUNNEL_IP_OPTS
| NLA_F_NESTED
);
1517 ret
= lwtunnel_parse_vxlan_opts(*argv
, len
, rta
);
1519 invarg("\"vxlan_opts\" value is invalid\n",
1521 rta_nest_end(rta
, nest
);
1522 } else if (strcmp(*argv
, "erspan_opts") == 0) {
1523 struct rtattr
*nest
;
1526 duparg2("opts", *argv
);
1530 nest
= rta_nest(rta
, len
,
1531 LWTUNNEL_IP_OPTS
| NLA_F_NESTED
);
1532 ret
= lwtunnel_parse_erspan_opts(*argv
, len
, rta
);
1534 invarg("\"erspan_opts\" value is invalid\n",
1536 rta_nest_end(rta
, nest
);
1537 } else if (strcmp(*argv
, "key") == 0) {
1539 duparg2("key", *argv
);
1540 flags
|= TUNNEL_KEY
;
1541 } else if (strcmp(*argv
, "csum") == 0) {
1543 duparg2("csum", *argv
);
1544 flags
|= TUNNEL_CSUM
;
1545 } else if (strcmp(*argv
, "seq") == 0) {
1547 duparg2("seq", *argv
);
1548 flags
|= TUNNEL_SEQ
;
1558 ret
= rta_addattr16(rta
, len
, LWTUNNEL_IP6_FLAGS
, flags
);
1560 /* argv is currently the first unparsed argument,
1561 * but the lwt_parse_encap() caller will move to the next,
1570 static void lwt_bpf_usage(void)
1572 fprintf(stderr
, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
1573 fprintf(stderr
, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
1577 static int parse_encap_bpf(struct rtattr
*rta
, size_t len
, int *argcp
,
1580 char **argv
= *argvp
;
1582 int headroom_set
= 0;
1585 if (strcmp(*argv
, "in") == 0) {
1587 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_IN
,
1588 BPF_PROG_TYPE_LWT_IN
) < 0)
1590 } else if (strcmp(*argv
, "out") == 0) {
1592 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_OUT
,
1593 BPF_PROG_TYPE_LWT_OUT
) < 0)
1595 } else if (strcmp(*argv
, "xmit") == 0) {
1597 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_XMIT
,
1598 BPF_PROG_TYPE_LWT_XMIT
) < 0)
1600 } else if (strcmp(*argv
, "headroom") == 0) {
1601 unsigned int headroom
;
1604 if (get_unsigned(&headroom
, *argv
, 0) || headroom
== 0)
1605 invarg("headroom is invalid\n", *argv
);
1607 rta_addattr32(rta
, len
, LWT_BPF_XMIT_HEADROOM
,
1610 } else if (strcmp(*argv
, "help") == 0) {
1618 /* argv is currently the first unparsed argument,
1619 * but the lwt_parse_encap() caller will move to the next,
1628 int lwt_parse_encap(struct rtattr
*rta
, size_t len
, int *argcp
, char ***argvp
,
1629 int encap_attr
, int encap_type_attr
)
1631 struct rtattr
*nest
;
1633 char **argv
= *argvp
;
1638 type
= read_encap_type(*argv
);
1640 invarg("\"encap type\" value is invalid\n", *argv
);
1645 "Error: unexpected end of line after \"encap\"\n");
1649 nest
= rta_nest(rta
, len
, encap_attr
);
1651 case LWTUNNEL_ENCAP_MPLS
:
1652 ret
= parse_encap_mpls(rta
, len
, &argc
, &argv
);
1654 case LWTUNNEL_ENCAP_IP
:
1655 ret
= parse_encap_ip(rta
, len
, &argc
, &argv
);
1657 case LWTUNNEL_ENCAP_ILA
:
1658 ret
= parse_encap_ila(rta
, len
, &argc
, &argv
);
1660 case LWTUNNEL_ENCAP_IP6
:
1661 ret
= parse_encap_ip6(rta
, len
, &argc
, &argv
);
1663 case LWTUNNEL_ENCAP_BPF
:
1664 if (parse_encap_bpf(rta
, len
, &argc
, &argv
) < 0)
1667 case LWTUNNEL_ENCAP_SEG6
:
1668 ret
= parse_encap_seg6(rta
, len
, &argc
, &argv
);
1670 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
1671 ret
= parse_encap_seg6local(rta
, len
, &argc
, &argv
);
1673 case LWTUNNEL_ENCAP_RPL
:
1674 ret
= parse_encap_rpl(rta
, len
, &argc
, &argv
);
1677 fprintf(stderr
, "Error: unsupported encap type\n");
1683 rta_nest_end(rta
, nest
);
1685 ret
= rta_addattr16(rta
, len
, encap_type_attr
, type
);