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/seg6_hmac.h>
33 #include <linux/seg6_local.h>
36 static const char *format_encap_type(int type
)
39 case LWTUNNEL_ENCAP_MPLS
:
41 case LWTUNNEL_ENCAP_IP
:
43 case LWTUNNEL_ENCAP_IP6
:
45 case LWTUNNEL_ENCAP_ILA
:
47 case LWTUNNEL_ENCAP_BPF
:
49 case LWTUNNEL_ENCAP_SEG6
:
51 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
58 static void encap_type_usage(void)
62 fprintf(stderr
, "Usage: ip route ... encap TYPE [ OPTIONS ] [...]\n");
64 for (i
= 1; i
<= LWTUNNEL_ENCAP_MAX
; i
++)
65 fprintf(stderr
, "%s %s\n", format_encap_type(i
),
66 i
== 1 ? "TYPE := " : " ");
71 static int read_encap_type(const char *name
)
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
;
83 else if (strcmp(name
, "seg6") == 0)
84 return LWTUNNEL_ENCAP_SEG6
;
85 else if (strcmp(name
, "seg6local") == 0)
86 return LWTUNNEL_ENCAP_SEG6_LOCAL
;
87 else if (strcmp(name
, "help") == 0)
90 return LWTUNNEL_ENCAP_NONE
;
93 static void print_srh(FILE *fp
, struct ipv6_sr_hdr
*srh
)
97 if (is_json_context())
98 open_json_array(PRINT_JSON
, "segs");
100 fprintf(fp
, "segs %d [ ", srh
->first_segment
+ 1);
102 for (i
= srh
->first_segment
; i
>= 0; i
--)
103 print_color_string(PRINT_ANY
, COLOR_INET6
,
105 rt_addr_n2a(AF_INET6
, 16, &srh
->segments
[i
]));
107 if (is_json_context())
108 close_json_array(PRINT_JSON
, NULL
);
112 if (sr_has_hmac(srh
)) {
113 unsigned int offset
= ((srh
->hdrlen
+ 1) << 3) - 40;
114 struct sr6_tlv_hmac
*tlv
;
116 tlv
= (struct sr6_tlv_hmac
*)((char *)srh
+ offset
);
117 print_0xhex(PRINT_ANY
, "hmac",
118 "hmac 0x%X ", ntohl(tlv
->hmackeyid
));
122 static const char *seg6_mode_types
[] = {
123 [SEG6_IPTUN_MODE_INLINE
] = "inline",
124 [SEG6_IPTUN_MODE_ENCAP
] = "encap",
125 [SEG6_IPTUN_MODE_L2ENCAP
] = "l2encap",
128 static const char *format_seg6mode_type(int mode
)
130 if (mode
< 0 || mode
> ARRAY_SIZE(seg6_mode_types
))
133 return seg6_mode_types
[mode
];
136 static int read_seg6mode_type(const char *mode
)
140 for (i
= 0; i
< ARRAY_SIZE(seg6_mode_types
); i
++) {
141 if (strcmp(mode
, seg6_mode_types
[i
]) == 0)
148 static void print_encap_seg6(FILE *fp
, struct rtattr
*encap
)
150 struct rtattr
*tb
[SEG6_IPTUNNEL_MAX
+1];
151 struct seg6_iptunnel_encap
*tuninfo
;
153 parse_rtattr_nested(tb
, SEG6_IPTUNNEL_MAX
, encap
);
155 if (!tb
[SEG6_IPTUNNEL_SRH
])
158 tuninfo
= RTA_DATA(tb
[SEG6_IPTUNNEL_SRH
]);
159 print_string(PRINT_ANY
, "mode",
160 "mode %s ", format_seg6mode_type(tuninfo
->mode
));
162 print_srh(fp
, tuninfo
->srh
);
165 static 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",
182 static const char *format_action_type(int action
)
184 if (action
< 0 || action
> SEG6_LOCAL_ACTION_MAX
)
187 return seg6_action_names
[action
] ?: "<unknown>";
190 static int read_action_type(const char *name
)
194 for (i
= 0; i
< SEG6_LOCAL_ACTION_MAX
+ 1; i
++) {
195 if (!seg6_action_names
[i
])
198 if (strcmp(seg6_action_names
[i
], name
) == 0)
202 return SEG6_LOCAL_ACTION_UNSPEC
;
205 static void print_encap_seg6local(FILE *fp
, struct rtattr
*encap
)
207 struct rtattr
*tb
[SEG6_LOCAL_MAX
+ 1];
210 parse_rtattr_nested(tb
, SEG6_LOCAL_MAX
, encap
);
212 if (!tb
[SEG6_LOCAL_ACTION
])
215 action
= rta_getattr_u32(tb
[SEG6_LOCAL_ACTION
]);
217 print_string(PRINT_ANY
, "action",
218 "action %s ", format_action_type(action
));
220 if (tb
[SEG6_LOCAL_SRH
]) {
221 open_json_object("srh");
222 print_srh(fp
, RTA_DATA(tb
[SEG6_LOCAL_SRH
]));
226 if (tb
[SEG6_LOCAL_TABLE
])
227 print_uint(PRINT_ANY
, "table",
228 "table %u ", rta_getattr_u32(tb
[SEG6_LOCAL_TABLE
]));
230 if (tb
[SEG6_LOCAL_NH4
]) {
231 print_string(PRINT_ANY
, "nh4",
232 "nh4 %s ", rt_addr_n2a_rta(AF_INET
, tb
[SEG6_LOCAL_NH4
]));
235 if (tb
[SEG6_LOCAL_NH6
]) {
236 print_string(PRINT_ANY
, "nh6",
237 "nh6 %s ", rt_addr_n2a_rta(AF_INET6
, tb
[SEG6_LOCAL_NH6
]));
240 if (tb
[SEG6_LOCAL_IIF
]) {
241 int iif
= rta_getattr_u32(tb
[SEG6_LOCAL_IIF
]);
243 print_string(PRINT_ANY
, "iif",
244 "iif %s ", ll_index_to_name(iif
));
247 if (tb
[SEG6_LOCAL_OIF
]) {
248 int oif
= rta_getattr_u32(tb
[SEG6_LOCAL_OIF
]);
250 print_string(PRINT_ANY
, "oif",
251 "oif %s ", ll_index_to_name(oif
));
255 static void print_encap_mpls(FILE *fp
, struct rtattr
*encap
)
257 struct rtattr
*tb
[MPLS_IPTUNNEL_MAX
+1];
259 parse_rtattr_nested(tb
, MPLS_IPTUNNEL_MAX
, encap
);
261 if (tb
[MPLS_IPTUNNEL_DST
])
262 print_string(PRINT_ANY
, "dst", " %s ",
263 format_host_rta(AF_MPLS
, tb
[MPLS_IPTUNNEL_DST
]));
264 if (tb
[MPLS_IPTUNNEL_TTL
])
265 print_uint(PRINT_ANY
, "ttl", "ttl %u ",
266 rta_getattr_u8(tb
[MPLS_IPTUNNEL_TTL
]));
269 static void print_encap_ip(FILE *fp
, struct rtattr
*encap
)
271 struct rtattr
*tb
[LWTUNNEL_IP_MAX
+1];
273 parse_rtattr_nested(tb
, LWTUNNEL_IP_MAX
, encap
);
275 if (tb
[LWTUNNEL_IP_ID
])
276 print_uint(PRINT_ANY
, "id", "id %llu ",
277 ntohll(rta_getattr_u64(tb
[LWTUNNEL_IP_ID
])));
279 if (tb
[LWTUNNEL_IP_SRC
])
280 print_color_string(PRINT_ANY
, COLOR_INET
,
282 rt_addr_n2a_rta(AF_INET
, tb
[LWTUNNEL_IP_SRC
]));
284 if (tb
[LWTUNNEL_IP_DST
])
285 print_color_string(PRINT_ANY
, COLOR_INET
,
287 rt_addr_n2a_rta(AF_INET
, tb
[LWTUNNEL_IP_DST
]));
289 if (tb
[LWTUNNEL_IP_TTL
])
290 print_uint(PRINT_ANY
, "ttl",
291 "ttl %u ", rta_getattr_u8(tb
[LWTUNNEL_IP_TTL
]));
293 if (tb
[LWTUNNEL_IP_TOS
])
294 print_uint(PRINT_ANY
, "tos",
295 "tos %d ", rta_getattr_u8(tb
[LWTUNNEL_IP_TOS
]));
298 static void print_encap_ila(FILE *fp
, struct rtattr
*encap
)
300 struct rtattr
*tb
[ILA_ATTR_MAX
+1];
302 parse_rtattr_nested(tb
, ILA_ATTR_MAX
, encap
);
304 if (tb
[ILA_ATTR_LOCATOR
]) {
305 char abuf
[ADDR64_BUF_SIZE
];
307 addr64_n2a(rta_getattr_u64(tb
[ILA_ATTR_LOCATOR
]),
309 print_string(PRINT_ANY
, "locator",
313 if (tb
[ILA_ATTR_CSUM_MODE
])
314 print_string(PRINT_ANY
, "csum_mode",
316 ila_csum_mode2name(rta_getattr_u8(tb
[ILA_ATTR_CSUM_MODE
])));
318 if (tb
[ILA_ATTR_IDENT_TYPE
])
319 print_string(PRINT_ANY
, "ident_type",
321 ila_ident_type2name(rta_getattr_u8(tb
[ILA_ATTR_IDENT_TYPE
])));
323 if (tb
[ILA_ATTR_HOOK_TYPE
])
324 print_string(PRINT_ANY
, "hook_type",
326 ila_hook_type2name(rta_getattr_u8(tb
[ILA_ATTR_HOOK_TYPE
])));
329 static void print_encap_ip6(FILE *fp
, struct rtattr
*encap
)
331 struct rtattr
*tb
[LWTUNNEL_IP6_MAX
+1];
333 parse_rtattr_nested(tb
, LWTUNNEL_IP6_MAX
, encap
);
335 if (tb
[LWTUNNEL_IP6_ID
])
336 print_uint(PRINT_ANY
, "id", "id %llu ",
337 ntohll(rta_getattr_u64(tb
[LWTUNNEL_IP6_ID
])));
339 if (tb
[LWTUNNEL_IP6_SRC
])
340 print_color_string(PRINT_ANY
, COLOR_INET6
,
342 rt_addr_n2a_rta(AF_INET6
, tb
[LWTUNNEL_IP6_SRC
]));
344 if (tb
[LWTUNNEL_IP6_DST
])
345 print_color_string(PRINT_ANY
, COLOR_INET6
,
347 rt_addr_n2a_rta(AF_INET6
, tb
[LWTUNNEL_IP6_DST
]));
349 if (tb
[LWTUNNEL_IP6_HOPLIMIT
])
350 print_uint(PRINT_ANY
, "hoplimit",
352 rta_getattr_u8(tb
[LWTUNNEL_IP6_HOPLIMIT
]));
354 if (tb
[LWTUNNEL_IP6_TC
])
355 print_uint(PRINT_ANY
, "tc",
356 "tc %u ", rta_getattr_u8(tb
[LWTUNNEL_IP6_TC
]));
359 static void print_encap_bpf_prog(FILE *fp
, struct rtattr
*encap
,
362 struct rtattr
*tb
[LWT_BPF_PROG_MAX
+1];
363 const char *progname
= NULL
;
365 parse_rtattr_nested(tb
, LWT_BPF_PROG_MAX
, encap
);
367 if (tb
[LWT_BPF_PROG_NAME
])
368 progname
= rta_getattr_str(tb
[LWT_BPF_PROG_NAME
]);
370 if (is_json_context())
371 print_string(PRINT_JSON
, str
, NULL
,
372 progname
? : "<unknown>");
374 fprintf(fp
, "%s ", str
);
376 fprintf(fp
, "%s ", progname
);
380 static void print_encap_bpf(FILE *fp
, struct rtattr
*encap
)
382 struct rtattr
*tb
[LWT_BPF_MAX
+1];
384 parse_rtattr_nested(tb
, LWT_BPF_MAX
, encap
);
387 print_encap_bpf_prog(fp
, tb
[LWT_BPF_IN
], "in");
389 print_encap_bpf_prog(fp
, tb
[LWT_BPF_OUT
], "out");
390 if (tb
[LWT_BPF_XMIT
])
391 print_encap_bpf_prog(fp
, tb
[LWT_BPF_XMIT
], "xmit");
392 if (tb
[LWT_BPF_XMIT_HEADROOM
])
393 print_uint(PRINT_ANY
, "headroom",
394 " %u ", rta_getattr_u32(tb
[LWT_BPF_XMIT_HEADROOM
]));
397 void lwt_print_encap(FILE *fp
, struct rtattr
*encap_type
,
398 struct rtattr
*encap
)
405 et
= rta_getattr_u16(encap_type
);
407 print_string(PRINT_ANY
, "encap", " encap %s ", format_encap_type(et
));
410 case LWTUNNEL_ENCAP_MPLS
:
411 print_encap_mpls(fp
, encap
);
413 case LWTUNNEL_ENCAP_IP
:
414 print_encap_ip(fp
, encap
);
416 case LWTUNNEL_ENCAP_ILA
:
417 print_encap_ila(fp
, encap
);
419 case LWTUNNEL_ENCAP_IP6
:
420 print_encap_ip6(fp
, encap
);
422 case LWTUNNEL_ENCAP_BPF
:
423 print_encap_bpf(fp
, encap
);
425 case LWTUNNEL_ENCAP_SEG6
:
426 print_encap_seg6(fp
, encap
);
428 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
429 print_encap_seg6local(fp
, encap
);
434 static struct ipv6_sr_hdr
*parse_srh(char *segbuf
, int hmac
, bool encap
)
436 struct ipv6_sr_hdr
*srh
;
443 for (i
= 0; *s
; *s
++ == ',' ? i
++ : *s
);
449 srhlen
= 8 + 16*nsegs
;
454 srh
= malloc(srhlen
);
455 memset(srh
, 0, srhlen
);
457 srh
->hdrlen
= (srhlen
>> 3) - 1;
459 srh
->segments_left
= nsegs
- 1;
460 srh
->first_segment
= nsegs
- 1;
463 srh
->flags
|= SR6_FLAG1_HMAC
;
465 i
= srh
->first_segment
;
466 for (s
= strtok(segbuf
, ","); s
; s
= strtok(NULL
, ",")) {
469 get_addr(&addr
, s
, AF_INET6
);
470 memcpy(&srh
->segments
[i
], addr
.data
, sizeof(struct in6_addr
));
475 struct sr6_tlv_hmac
*tlv
;
477 tlv
= (struct sr6_tlv_hmac
*)((char *)srh
+ srhlen
- 40);
478 tlv
->tlvhdr
.type
= SR6_TLV_HMAC
;
479 tlv
->tlvhdr
.len
= 38;
480 tlv
->hmackeyid
= htonl(hmac
);
486 static int parse_encap_seg6(struct rtattr
*rta
, size_t len
, int *argcp
,
489 int mode_ok
= 0, segs_ok
= 0, hmac_ok
= 0;
490 struct seg6_iptunnel_encap
*tuninfo
;
491 struct ipv6_sr_hdr
*srh
;
492 char **argv
= *argvp
;
500 if (strcmp(*argv
, "mode") == 0) {
503 duparg2("mode", *argv
);
504 encap
= read_seg6mode_type(*argv
);
506 invarg("\"mode\" value is invalid\n", *argv
);
507 } else if (strcmp(*argv
, "segs") == 0) {
510 duparg2("segs", *argv
);
512 invarg("\"segs\" provided before \"mode\"\n",
515 strlcpy(segbuf
, *argv
, 1024);
516 } else if (strcmp(*argv
, "hmac") == 0) {
519 duparg2("hmac", *argv
);
520 get_u32(&hmac
, *argv
, 0);
527 srh
= parse_srh(segbuf
, hmac
, encap
);
528 srhlen
= (srh
->hdrlen
+ 1) << 3;
530 tuninfo
= malloc(sizeof(*tuninfo
) + srhlen
);
531 memset(tuninfo
, 0, sizeof(*tuninfo
) + srhlen
);
533 tuninfo
->mode
= encap
;
535 memcpy(tuninfo
->srh
, srh
, srhlen
);
537 rta_addattr_l(rta
, len
, SEG6_IPTUNNEL_SRH
, tuninfo
,
538 sizeof(*tuninfo
) + srhlen
);
549 static int parse_encap_seg6local(struct rtattr
*rta
, size_t len
, int *argcp
,
552 int segs_ok
= 0, hmac_ok
= 0, table_ok
= 0, nh4_ok
= 0, nh6_ok
= 0;
553 int iif_ok
= 0, oif_ok
= 0, action_ok
= 0, srh_ok
= 0;
554 __u32 action
= 0, table
, iif
, oif
;
555 struct ipv6_sr_hdr
*srh
;
556 char **argv
= *argvp
;
563 if (strcmp(*argv
, "action") == 0) {
566 duparg2("action", *argv
);
567 action
= read_action_type(*argv
);
569 invarg("\"action\" value is invalid\n", *argv
);
570 rta_addattr32(rta
, len
, SEG6_LOCAL_ACTION
, action
);
571 } else if (strcmp(*argv
, "table") == 0) {
574 duparg2("table", *argv
);
575 get_u32(&table
, *argv
, 0);
576 rta_addattr32(rta
, len
, SEG6_LOCAL_TABLE
, table
);
577 } else if (strcmp(*argv
, "nh4") == 0) {
580 duparg2("nh4", *argv
);
581 get_addr(&addr
, *argv
, AF_INET
);
582 rta_addattr_l(rta
, len
, SEG6_LOCAL_NH4
, &addr
.data
,
584 } else if (strcmp(*argv
, "nh6") == 0) {
587 duparg2("nh6", *argv
);
588 get_addr(&addr
, *argv
, AF_INET6
);
589 rta_addattr_l(rta
, len
, SEG6_LOCAL_NH6
, &addr
.data
,
591 } else if (strcmp(*argv
, "iif") == 0) {
594 duparg2("iif", *argv
);
595 iif
= ll_name_to_index(*argv
);
598 rta_addattr32(rta
, len
, SEG6_LOCAL_IIF
, iif
);
599 } else if (strcmp(*argv
, "oif") == 0) {
602 duparg2("oif", *argv
);
603 oif
= ll_name_to_index(*argv
);
606 rta_addattr32(rta
, len
, SEG6_LOCAL_OIF
, oif
);
607 } else if (strcmp(*argv
, "srh") == 0) {
610 duparg2("srh", *argv
);
611 if (strcmp(*argv
, "segs") != 0)
612 invarg("missing \"segs\" attribute for srh\n",
616 duparg2("segs", *argv
);
617 strncpy(segbuf
, *argv
, 1024);
622 if (strcmp(*argv
, "hmac") == 0) {
625 duparg2("hmac", *argv
);
626 get_u32(&hmac
, *argv
, 0);
637 fprintf(stderr
, "Missing action type\n");
644 srh
= parse_srh(segbuf
, hmac
,
645 action
== SEG6_LOCAL_ACTION_END_B6_ENCAP
);
646 srhlen
= (srh
->hdrlen
+ 1) << 3;
647 rta_addattr_l(rta
, len
, SEG6_LOCAL_SRH
, srh
, srhlen
);
657 static int parse_encap_mpls(struct rtattr
*rta
, size_t len
,
658 int *argcp
, char ***argvp
)
662 char **argv
= *argvp
;
665 if (get_addr(&addr
, *argv
, AF_MPLS
)) {
667 "Error: an inet address is expected rather than \"%s\".\n",
672 rta_addattr_l(rta
, len
, MPLS_IPTUNNEL_DST
, &addr
.data
,
679 if (strcmp(*argv
, "ttl") == 0) {
684 duparg2("ttl", *argv
);
685 if (get_u8(&ttl
, *argv
, 0))
686 invarg("\"ttl\" value is invalid\n", *argv
);
687 rta_addattr8(rta
, len
, MPLS_IPTUNNEL_TTL
, ttl
);
694 /* argv is currently the first unparsed argument,
695 * but the lwt_parse_encap() caller will move to the next,
704 static int parse_encap_ip(struct rtattr
*rta
, size_t len
,
705 int *argcp
, char ***argvp
)
707 int id_ok
= 0, dst_ok
= 0, tos_ok
= 0, ttl_ok
= 0;
708 char **argv
= *argvp
;
712 if (strcmp(*argv
, "id") == 0) {
717 duparg2("id", *argv
);
718 if (get_be64(&id
, *argv
, 0))
719 invarg("\"id\" value is invalid\n", *argv
);
720 rta_addattr64(rta
, len
, LWTUNNEL_IP_ID
, id
);
721 } else if (strcmp(*argv
, "dst") == 0) {
726 duparg2("dst", *argv
);
727 get_addr(&addr
, *argv
, AF_INET
);
728 rta_addattr_l(rta
, len
, LWTUNNEL_IP_DST
,
729 &addr
.data
, addr
.bytelen
);
730 } else if (strcmp(*argv
, "tos") == 0) {
735 duparg2("tos", *argv
);
736 if (rtnl_dsfield_a2n(&tos
, *argv
))
737 invarg("\"tos\" value is invalid\n", *argv
);
738 rta_addattr8(rta
, len
, LWTUNNEL_IP_TOS
, tos
);
739 } else if (strcmp(*argv
, "ttl") == 0) {
744 duparg2("ttl", *argv
);
745 if (get_u8(&ttl
, *argv
, 0))
746 invarg("\"ttl\" value is invalid\n", *argv
);
747 rta_addattr8(rta
, len
, LWTUNNEL_IP_TTL
, ttl
);
754 /* argv is currently the first unparsed argument,
755 * but the lwt_parse_encap() caller will move to the next,
764 static int parse_encap_ila(struct rtattr
*rta
, size_t len
,
765 int *argcp
, char ***argvp
)
769 char **argv
= *argvp
;
771 if (get_addr64(&locator
, *argv
) < 0) {
772 fprintf(stderr
, "Bad locator: %s\n", *argv
);
778 rta_addattr64(rta
, 1024, ILA_ATTR_LOCATOR
, locator
);
781 if (strcmp(*argv
, "csum-mode") == 0) {
786 csum_mode
= ila_csum_name2mode(*argv
);
788 invarg("\"csum-mode\" value is invalid\n",
791 rta_addattr8(rta
, 1024, ILA_ATTR_CSUM_MODE
,
795 } else if (strcmp(*argv
, "ident-type") == 0) {
800 ident_type
= ila_ident_name2type(*argv
);
802 invarg("\"ident-type\" value is invalid\n",
805 rta_addattr8(rta
, 1024, ILA_ATTR_IDENT_TYPE
,
809 } else if (strcmp(*argv
, "hook-type") == 0) {
814 hook_type
= ila_hook_name2type(*argv
);
816 invarg("\"hook-type\" value is invalid\n",
819 rta_addattr8(rta
, 1024, ILA_ATTR_HOOK_TYPE
,
828 /* argv is currently the first unparsed argument,
829 * but the lwt_parse_encap() caller will move to the next,
838 static int parse_encap_ip6(struct rtattr
*rta
, size_t len
,
839 int *argcp
, char ***argvp
)
841 int id_ok
= 0, dst_ok
= 0, tos_ok
= 0, ttl_ok
= 0;
842 char **argv
= *argvp
;
846 if (strcmp(*argv
, "id") == 0) {
851 duparg2("id", *argv
);
852 if (get_be64(&id
, *argv
, 0))
853 invarg("\"id\" value is invalid\n", *argv
);
854 rta_addattr64(rta
, len
, LWTUNNEL_IP6_ID
, id
);
855 } else if (strcmp(*argv
, "dst") == 0) {
860 duparg2("dst", *argv
);
861 get_addr(&addr
, *argv
, AF_INET6
);
862 rta_addattr_l(rta
, len
, LWTUNNEL_IP6_DST
,
863 &addr
.data
, addr
.bytelen
);
864 } else if (strcmp(*argv
, "tc") == 0) {
869 duparg2("tc", *argv
);
870 if (rtnl_dsfield_a2n(&tc
, *argv
))
871 invarg("\"tc\" value is invalid\n", *argv
);
872 rta_addattr8(rta
, len
, LWTUNNEL_IP6_TC
, tc
);
873 } else if (strcmp(*argv
, "hoplimit") == 0) {
878 duparg2("hoplimit", *argv
);
879 if (get_u8(&hoplimit
, *argv
, 0))
880 invarg("\"hoplimit\" value is invalid\n",
882 rta_addattr8(rta
, len
, LWTUNNEL_IP6_HOPLIMIT
, hoplimit
);
889 /* argv is currently the first unparsed argument,
890 * but the lwt_parse_encap() caller will move to the next,
904 static void bpf_lwt_cb(void *lwt_ptr
, int fd
, const char *annotation
)
906 struct lwt_x
*x
= lwt_ptr
;
908 rta_addattr32(x
->rta
, x
->len
, LWT_BPF_PROG_FD
, fd
);
909 rta_addattr_l(x
->rta
, x
->len
, LWT_BPF_PROG_NAME
, annotation
,
910 strlen(annotation
) + 1);
913 static const struct bpf_cfg_ops bpf_cb_ops
= {
914 .ebpf_cb
= bpf_lwt_cb
,
917 static int lwt_parse_bpf(struct rtattr
*rta
, size_t len
,
918 int *argcp
, char ***argvp
,
919 int attr
, const enum bpf_prog_type bpf_type
)
921 struct bpf_cfg_in cfg
= {
933 nest
= rta_nest(rta
, len
, attr
);
934 err
= bpf_parse_and_load_common(&cfg
, &bpf_cb_ops
, &x
);
936 fprintf(stderr
, "Failed to parse eBPF program: %s\n",
940 rta_nest_end(rta
, nest
);
948 static void lwt_bpf_usage(void)
950 fprintf(stderr
, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
951 fprintf(stderr
, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
955 static int parse_encap_bpf(struct rtattr
*rta
, size_t len
, int *argcp
,
958 char **argv
= *argvp
;
960 int headroom_set
= 0;
963 if (strcmp(*argv
, "in") == 0) {
965 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_IN
,
966 BPF_PROG_TYPE_LWT_IN
) < 0)
968 } else if (strcmp(*argv
, "out") == 0) {
970 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_OUT
,
971 BPF_PROG_TYPE_LWT_OUT
) < 0)
973 } else if (strcmp(*argv
, "xmit") == 0) {
975 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_XMIT
,
976 BPF_PROG_TYPE_LWT_XMIT
) < 0)
978 } else if (strcmp(*argv
, "headroom") == 0) {
979 unsigned int headroom
;
982 if (get_unsigned(&headroom
, *argv
, 0) || headroom
== 0)
983 invarg("headroom is invalid\n", *argv
);
985 rta_addattr32(rta
, 1024, LWT_BPF_XMIT_HEADROOM
,
988 } else if (strcmp(*argv
, "help") == 0) {
996 /* argv is currently the first unparsed argument,
997 * but the lwt_parse_encap() caller will move to the next,
1006 int lwt_parse_encap(struct rtattr
*rta
, size_t len
, int *argcp
, char ***argvp
)
1008 struct rtattr
*nest
;
1010 char **argv
= *argvp
;
1014 type
= read_encap_type(*argv
);
1016 invarg("\"encap type\" value is invalid\n", *argv
);
1021 "Error: unexpected end of line after \"encap\"\n");
1025 nest
= rta_nest(rta
, 1024, RTA_ENCAP
);
1027 case LWTUNNEL_ENCAP_MPLS
:
1028 parse_encap_mpls(rta
, len
, &argc
, &argv
);
1030 case LWTUNNEL_ENCAP_IP
:
1031 parse_encap_ip(rta
, len
, &argc
, &argv
);
1033 case LWTUNNEL_ENCAP_ILA
:
1034 parse_encap_ila(rta
, len
, &argc
, &argv
);
1036 case LWTUNNEL_ENCAP_IP6
:
1037 parse_encap_ip6(rta
, len
, &argc
, &argv
);
1039 case LWTUNNEL_ENCAP_BPF
:
1040 if (parse_encap_bpf(rta
, len
, &argc
, &argv
) < 0)
1043 case LWTUNNEL_ENCAP_SEG6
:
1044 parse_encap_seg6(rta
, len
, &argc
, &argv
);
1046 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
1047 parse_encap_seg6local(rta
, len
, &argc
, &argv
);
1050 fprintf(stderr
, "Error: unsupported encap type\n");
1053 rta_nest_end(rta
, nest
);
1055 rta_addattr16(rta
, 1024, RTA_ENCAP_TYPE
, type
);