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>
26 #include "iproute_lwtunnel.h"
29 #include <linux/seg6.h>
30 #include <linux/seg6_iptunnel.h>
31 #include <linux/seg6_hmac.h>
32 #include <linux/seg6_local.h>
35 static const char *format_encap_type(int type
)
38 case LWTUNNEL_ENCAP_MPLS
:
40 case LWTUNNEL_ENCAP_IP
:
42 case LWTUNNEL_ENCAP_IP6
:
44 case LWTUNNEL_ENCAP_ILA
:
46 case LWTUNNEL_ENCAP_BPF
:
48 case LWTUNNEL_ENCAP_SEG6
:
50 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
57 static void encap_type_usage(void)
61 fprintf(stderr
, "Usage: ip route ... encap TYPE [ OPTIONS ] [...]\n");
63 for (i
= 1; i
<= LWTUNNEL_ENCAP_MAX
; i
++)
64 fprintf(stderr
, "%s %s\n", format_encap_type(i
),
65 i
== 1 ? "TYPE := " : " ");
70 static int read_encap_type(const char *name
)
72 if (strcmp(name
, "mpls") == 0)
73 return LWTUNNEL_ENCAP_MPLS
;
74 else if (strcmp(name
, "ip") == 0)
75 return LWTUNNEL_ENCAP_IP
;
76 else if (strcmp(name
, "ip6") == 0)
77 return LWTUNNEL_ENCAP_IP6
;
78 else if (strcmp(name
, "ila") == 0)
79 return LWTUNNEL_ENCAP_ILA
;
80 else if (strcmp(name
, "bpf") == 0)
81 return LWTUNNEL_ENCAP_BPF
;
82 else if (strcmp(name
, "seg6") == 0)
83 return LWTUNNEL_ENCAP_SEG6
;
84 else if (strcmp(name
, "seg6local") == 0)
85 return LWTUNNEL_ENCAP_SEG6_LOCAL
;
86 else if (strcmp(name
, "help") == 0)
89 return LWTUNNEL_ENCAP_NONE
;
92 static void print_srh(FILE *fp
, struct ipv6_sr_hdr
*srh
)
96 fprintf(fp
, "segs %d [ ", srh
->first_segment
+ 1);
98 for (i
= srh
->first_segment
; i
>= 0; i
--)
100 rt_addr_n2a(AF_INET6
, 16, &srh
->segments
[i
]));
104 if (sr_has_hmac(srh
)) {
105 unsigned int offset
= ((srh
->hdrlen
+ 1) << 3) - 40;
106 struct sr6_tlv_hmac
*tlv
;
108 tlv
= (struct sr6_tlv_hmac
*)((char *)srh
+ offset
);
109 fprintf(fp
, "hmac 0x%X ", ntohl(tlv
->hmackeyid
));
113 static const char *seg6_mode_types
[] = {
114 [SEG6_IPTUN_MODE_INLINE
] = "inline",
115 [SEG6_IPTUN_MODE_ENCAP
] = "encap",
116 [SEG6_IPTUN_MODE_L2ENCAP
] = "l2encap",
119 static const char *format_seg6mode_type(int mode
)
121 if (mode
< 0 || mode
> ARRAY_SIZE(seg6_mode_types
))
124 return seg6_mode_types
[mode
];
127 static int read_seg6mode_type(const char *mode
)
131 for (i
= 0; i
< ARRAY_SIZE(seg6_mode_types
); i
++) {
132 if (strcmp(mode
, seg6_mode_types
[i
]) == 0)
139 static void print_encap_seg6(FILE *fp
, struct rtattr
*encap
)
141 struct rtattr
*tb
[SEG6_IPTUNNEL_MAX
+1];
142 struct seg6_iptunnel_encap
*tuninfo
;
144 parse_rtattr_nested(tb
, SEG6_IPTUNNEL_MAX
, encap
);
146 if (!tb
[SEG6_IPTUNNEL_SRH
])
149 tuninfo
= RTA_DATA(tb
[SEG6_IPTUNNEL_SRH
]);
150 fprintf(fp
, "mode %s ", format_seg6mode_type(tuninfo
->mode
));
152 print_srh(fp
, tuninfo
->srh
);
155 static const char *seg6_action_names
[SEG6_LOCAL_ACTION_MAX
+ 1] = {
156 [SEG6_LOCAL_ACTION_END
] = "End",
157 [SEG6_LOCAL_ACTION_END_X
] = "End.X",
158 [SEG6_LOCAL_ACTION_END_T
] = "End.T",
159 [SEG6_LOCAL_ACTION_END_DX2
] = "End.DX2",
160 [SEG6_LOCAL_ACTION_END_DX6
] = "End.DX6",
161 [SEG6_LOCAL_ACTION_END_DX4
] = "End.DX4",
162 [SEG6_LOCAL_ACTION_END_DT6
] = "End.DT6",
163 [SEG6_LOCAL_ACTION_END_DT4
] = "End.DT4",
164 [SEG6_LOCAL_ACTION_END_B6
] = "End.B6",
165 [SEG6_LOCAL_ACTION_END_B6_ENCAP
] = "End.B6.Encaps",
166 [SEG6_LOCAL_ACTION_END_BM
] = "End.BM",
167 [SEG6_LOCAL_ACTION_END_S
] = "End.S",
168 [SEG6_LOCAL_ACTION_END_AS
] = "End.AS",
169 [SEG6_LOCAL_ACTION_END_AM
] = "End.AM",
172 static const char *format_action_type(int action
)
174 if (action
< 0 || action
> SEG6_LOCAL_ACTION_MAX
)
177 return seg6_action_names
[action
] ?: "<unknown>";
180 static int read_action_type(const char *name
)
184 for (i
= 0; i
< SEG6_LOCAL_ACTION_MAX
+ 1; i
++) {
185 if (!seg6_action_names
[i
])
188 if (strcmp(seg6_action_names
[i
], name
) == 0)
192 return SEG6_LOCAL_ACTION_UNSPEC
;
195 static void print_encap_seg6local(FILE *fp
, struct rtattr
*encap
)
197 struct rtattr
*tb
[SEG6_LOCAL_MAX
+ 1];
198 char ifbuf
[IFNAMSIZ
];
201 parse_rtattr_nested(tb
, SEG6_LOCAL_MAX
, encap
);
203 if (!tb
[SEG6_LOCAL_ACTION
])
206 action
= rta_getattr_u32(tb
[SEG6_LOCAL_ACTION
]);
208 fprintf(fp
, "action %s ", format_action_type(action
));
210 if (tb
[SEG6_LOCAL_SRH
]) {
212 print_srh(fp
, RTA_DATA(tb
[SEG6_LOCAL_SRH
]));
215 if (tb
[SEG6_LOCAL_TABLE
])
216 fprintf(fp
, "table %u ", rta_getattr_u32(tb
[SEG6_LOCAL_TABLE
]));
218 if (tb
[SEG6_LOCAL_NH4
]) {
219 fprintf(fp
, "nh4 %s ",
220 rt_addr_n2a_rta(AF_INET
, tb
[SEG6_LOCAL_NH4
]));
223 if (tb
[SEG6_LOCAL_NH6
]) {
224 fprintf(fp
, "nh6 %s ",
225 rt_addr_n2a_rta(AF_INET6
, tb
[SEG6_LOCAL_NH6
]));
228 if (tb
[SEG6_LOCAL_IIF
]) {
229 int iif
= rta_getattr_u32(tb
[SEG6_LOCAL_IIF
]);
231 fprintf(fp
, "iif %s ",
232 if_indextoname(iif
, ifbuf
) ?: "<unknown>");
235 if (tb
[SEG6_LOCAL_OIF
]) {
236 int oif
= rta_getattr_u32(tb
[SEG6_LOCAL_OIF
]);
238 fprintf(fp
, "oif %s ",
239 if_indextoname(oif
, ifbuf
) ?: "<unknown>");
243 static void print_encap_mpls(FILE *fp
, struct rtattr
*encap
)
245 struct rtattr
*tb
[MPLS_IPTUNNEL_MAX
+1];
247 parse_rtattr_nested(tb
, MPLS_IPTUNNEL_MAX
, encap
);
249 if (tb
[MPLS_IPTUNNEL_DST
])
251 format_host_rta(AF_MPLS
, tb
[MPLS_IPTUNNEL_DST
]));
252 if (tb
[MPLS_IPTUNNEL_TTL
])
253 fprintf(fp
, "ttl %u ",
254 rta_getattr_u8(tb
[MPLS_IPTUNNEL_TTL
]));
257 static void print_encap_ip(FILE *fp
, struct rtattr
*encap
)
259 struct rtattr
*tb
[LWTUNNEL_IP_MAX
+1];
261 parse_rtattr_nested(tb
, LWTUNNEL_IP_MAX
, encap
);
263 if (tb
[LWTUNNEL_IP_ID
])
264 fprintf(fp
, "id %llu ",
265 ntohll(rta_getattr_u64(tb
[LWTUNNEL_IP_ID
])));
267 if (tb
[LWTUNNEL_IP_SRC
])
268 fprintf(fp
, "src %s ",
269 rt_addr_n2a_rta(AF_INET
, tb
[LWTUNNEL_IP_SRC
]));
271 if (tb
[LWTUNNEL_IP_DST
])
272 fprintf(fp
, "dst %s ",
273 rt_addr_n2a_rta(AF_INET
, tb
[LWTUNNEL_IP_DST
]));
275 if (tb
[LWTUNNEL_IP_TTL
])
276 fprintf(fp
, "ttl %d ", rta_getattr_u8(tb
[LWTUNNEL_IP_TTL
]));
278 if (tb
[LWTUNNEL_IP_TOS
])
279 fprintf(fp
, "tos %d ", rta_getattr_u8(tb
[LWTUNNEL_IP_TOS
]));
282 static char *ila_csum_mode2name(__u8 csum_mode
)
285 case ILA_CSUM_ADJUST_TRANSPORT
:
286 return "adj-transport";
287 case ILA_CSUM_NEUTRAL_MAP
:
288 return "neutral-map";
289 case ILA_CSUM_NO_ACTION
:
291 case ILA_CSUM_NEUTRAL_MAP_AUTO
:
292 return "neutral-map-auto";
298 static int ila_csum_name2mode(char *name
)
300 if (strcmp(name
, "adj-transport") == 0)
301 return ILA_CSUM_ADJUST_TRANSPORT
;
302 else if (strcmp(name
, "neutral-map") == 0)
303 return ILA_CSUM_NEUTRAL_MAP
;
304 else if (strcmp(name
, "no-action") == 0)
305 return ILA_CSUM_NO_ACTION
;
306 else if (strcmp(name
, "neutral-map-auto") == 0)
307 return ILA_CSUM_NEUTRAL_MAP_AUTO
;
312 static char *ila_ident_type2name(__u8 ident_type
)
314 switch (ident_type
) {
319 case ILA_ATYPE_VIRT_V4
:
321 case ILA_ATYPE_VIRT_UNI_V6
:
322 return "virt-uni-v6";
323 case ILA_ATYPE_VIRT_MULTI_V6
:
324 return "virt-multi-v6";
325 case ILA_ATYPE_NONLOCAL_ADDR
:
326 return "nonlocal-addr";
327 case ILA_ATYPE_USE_FORMAT
:
334 static int ila_ident_name2type(char *name
)
336 if (!strcmp(name
, "luid"))
337 return ILA_ATYPE_LUID
;
338 else if (!strcmp(name
, "use-format"))
339 return ILA_ATYPE_USE_FORMAT
;
340 #if 0 /* No kernel support for configuring these yet */
341 else if (!strcmp(name
, "iid"))
342 return ILA_ATYPE_IID
;
343 else if (!strcmp(name
, "virt-v4"))
344 return ILA_ATYPE_VIRT_V4
;
345 else if (!strcmp(name
, "virt-uni-v6"))
346 return ILA_ATYPE_VIRT_UNI_V6
;
347 else if (!strcmp(name
, "virt-multi-v6"))
348 return ILA_ATYPE_VIRT_MULTI_V6
;
349 else if (!strcmp(name
, "nonlocal-addr"))
350 return ILA_ATYPE_NONLOCAL_ADDR
;
356 static char *ila_hook_type2name(__u8 hook_type
)
359 case ILA_HOOK_ROUTE_OUTPUT
:
361 case ILA_HOOK_ROUTE_INPUT
:
368 static int ila_hook_name2type(char *name
)
370 if (!strcmp(name
, "output"))
371 return ILA_HOOK_ROUTE_OUTPUT
;
372 else if (!strcmp(name
, "input"))
373 return ILA_HOOK_ROUTE_INPUT
;
378 static void print_encap_ila(FILE *fp
, struct rtattr
*encap
)
380 struct rtattr
*tb
[ILA_ATTR_MAX
+1];
382 parse_rtattr_nested(tb
, ILA_ATTR_MAX
, encap
);
384 if (tb
[ILA_ATTR_LOCATOR
]) {
385 char abuf
[ADDR64_BUF_SIZE
];
387 addr64_n2a(rta_getattr_u64(tb
[ILA_ATTR_LOCATOR
]),
389 fprintf(fp
, " %s ", abuf
);
392 if (tb
[ILA_ATTR_CSUM_MODE
])
393 fprintf(fp
, " csum-mode %s ",
394 ila_csum_mode2name(rta_getattr_u8(
395 tb
[ILA_ATTR_CSUM_MODE
])));
397 if (tb
[ILA_ATTR_IDENT_TYPE
])
398 fprintf(fp
, " ident-type %s ",
399 ila_ident_type2name(rta_getattr_u8(
400 tb
[ILA_ATTR_IDENT_TYPE
])));
402 if (tb
[ILA_ATTR_HOOK_TYPE
])
403 fprintf(fp
, " hook-type %s ",
404 ila_hook_type2name(rta_getattr_u8(
405 tb
[ILA_ATTR_HOOK_TYPE
])));
408 static void print_encap_ip6(FILE *fp
, struct rtattr
*encap
)
410 struct rtattr
*tb
[LWTUNNEL_IP6_MAX
+1];
412 parse_rtattr_nested(tb
, LWTUNNEL_IP6_MAX
, encap
);
414 if (tb
[LWTUNNEL_IP6_ID
])
415 fprintf(fp
, "id %llu ",
416 ntohll(rta_getattr_u64(tb
[LWTUNNEL_IP6_ID
])));
418 if (tb
[LWTUNNEL_IP6_SRC
])
419 fprintf(fp
, "src %s ",
420 rt_addr_n2a_rta(AF_INET6
, tb
[LWTUNNEL_IP6_SRC
]));
422 if (tb
[LWTUNNEL_IP6_DST
])
423 fprintf(fp
, "dst %s ",
424 rt_addr_n2a_rta(AF_INET6
, tb
[LWTUNNEL_IP6_DST
]));
426 if (tb
[LWTUNNEL_IP6_HOPLIMIT
])
427 fprintf(fp
, "hoplimit %d ",
428 rta_getattr_u8(tb
[LWTUNNEL_IP6_HOPLIMIT
]));
430 if (tb
[LWTUNNEL_IP6_TC
])
431 fprintf(fp
, "tc %d ", rta_getattr_u8(tb
[LWTUNNEL_IP6_TC
]));
434 static void print_encap_bpf_prog(FILE *fp
, struct rtattr
*encap
,
437 struct rtattr
*tb
[LWT_BPF_PROG_MAX
+1];
439 parse_rtattr_nested(tb
, LWT_BPF_PROG_MAX
, encap
);
440 fprintf(fp
, "%s ", str
);
442 if (tb
[LWT_BPF_PROG_NAME
])
443 fprintf(fp
, "%s ", rta_getattr_str(tb
[LWT_BPF_PROG_NAME
]));
446 static void print_encap_bpf(FILE *fp
, struct rtattr
*encap
)
448 struct rtattr
*tb
[LWT_BPF_MAX
+1];
450 parse_rtattr_nested(tb
, LWT_BPF_MAX
, encap
);
453 print_encap_bpf_prog(fp
, tb
[LWT_BPF_IN
], "in");
455 print_encap_bpf_prog(fp
, tb
[LWT_BPF_OUT
], "out");
456 if (tb
[LWT_BPF_XMIT
])
457 print_encap_bpf_prog(fp
, tb
[LWT_BPF_XMIT
], "xmit");
458 if (tb
[LWT_BPF_XMIT_HEADROOM
])
459 fprintf(fp
, "%d ", rta_getattr_u32(tb
[LWT_BPF_XMIT_HEADROOM
]));
462 void lwt_print_encap(FILE *fp
, struct rtattr
*encap_type
,
463 struct rtattr
*encap
)
470 et
= rta_getattr_u16(encap_type
);
472 fprintf(fp
, " encap %s ", format_encap_type(et
));
475 case LWTUNNEL_ENCAP_MPLS
:
476 print_encap_mpls(fp
, encap
);
478 case LWTUNNEL_ENCAP_IP
:
479 print_encap_ip(fp
, encap
);
481 case LWTUNNEL_ENCAP_ILA
:
482 print_encap_ila(fp
, encap
);
484 case LWTUNNEL_ENCAP_IP6
:
485 print_encap_ip6(fp
, encap
);
487 case LWTUNNEL_ENCAP_BPF
:
488 print_encap_bpf(fp
, encap
);
490 case LWTUNNEL_ENCAP_SEG6
:
491 print_encap_seg6(fp
, encap
);
493 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
494 print_encap_seg6local(fp
, encap
);
499 static struct ipv6_sr_hdr
*parse_srh(char *segbuf
, int hmac
, bool encap
)
501 struct ipv6_sr_hdr
*srh
;
508 for (i
= 0; *s
; *s
++ == ',' ? i
++ : *s
);
514 srhlen
= 8 + 16*nsegs
;
519 srh
= malloc(srhlen
);
520 memset(srh
, 0, srhlen
);
522 srh
->hdrlen
= (srhlen
>> 3) - 1;
524 srh
->segments_left
= nsegs
- 1;
525 srh
->first_segment
= nsegs
- 1;
528 srh
->flags
|= SR6_FLAG1_HMAC
;
530 i
= srh
->first_segment
;
531 for (s
= strtok(segbuf
, ","); s
; s
= strtok(NULL
, ",")) {
532 inet_get_addr(s
, NULL
, &srh
->segments
[i
]);
537 struct sr6_tlv_hmac
*tlv
;
539 tlv
= (struct sr6_tlv_hmac
*)((char *)srh
+ srhlen
- 40);
540 tlv
->tlvhdr
.type
= SR6_TLV_HMAC
;
541 tlv
->tlvhdr
.len
= 38;
542 tlv
->hmackeyid
= htonl(hmac
);
548 static int parse_encap_seg6(struct rtattr
*rta
, size_t len
, int *argcp
,
551 int mode_ok
= 0, segs_ok
= 0, hmac_ok
= 0;
552 struct seg6_iptunnel_encap
*tuninfo
;
553 struct ipv6_sr_hdr
*srh
;
554 char **argv
= *argvp
;
562 if (strcmp(*argv
, "mode") == 0) {
565 duparg2("mode", *argv
);
566 encap
= read_seg6mode_type(*argv
);
568 invarg("\"mode\" value is invalid\n", *argv
);
569 } else if (strcmp(*argv
, "segs") == 0) {
572 duparg2("segs", *argv
);
574 invarg("\"segs\" provided before \"mode\"\n",
577 strlcpy(segbuf
, *argv
, 1024);
578 } else if (strcmp(*argv
, "hmac") == 0) {
581 duparg2("hmac", *argv
);
582 get_u32(&hmac
, *argv
, 0);
589 srh
= parse_srh(segbuf
, hmac
, encap
);
590 srhlen
= (srh
->hdrlen
+ 1) << 3;
592 tuninfo
= malloc(sizeof(*tuninfo
) + srhlen
);
593 memset(tuninfo
, 0, sizeof(*tuninfo
) + srhlen
);
595 tuninfo
->mode
= encap
;
597 memcpy(tuninfo
->srh
, srh
, srhlen
);
599 rta_addattr_l(rta
, len
, SEG6_IPTUNNEL_SRH
, tuninfo
,
600 sizeof(*tuninfo
) + srhlen
);
611 static int parse_encap_seg6local(struct rtattr
*rta
, size_t len
, int *argcp
,
614 int segs_ok
= 0, hmac_ok
= 0, table_ok
= 0, nh4_ok
= 0, nh6_ok
= 0;
615 int iif_ok
= 0, oif_ok
= 0, action_ok
= 0, srh_ok
= 0;
616 __u32 action
= 0, table
, iif
, oif
;
617 struct ipv6_sr_hdr
*srh
;
618 char **argv
= *argvp
;
625 if (strcmp(*argv
, "action") == 0) {
628 duparg2("action", *argv
);
629 action
= read_action_type(*argv
);
631 invarg("\"action\" value is invalid\n", *argv
);
632 rta_addattr32(rta
, len
, SEG6_LOCAL_ACTION
, action
);
633 } else if (strcmp(*argv
, "table") == 0) {
636 duparg2("table", *argv
);
637 get_u32(&table
, *argv
, 0);
638 rta_addattr32(rta
, len
, SEG6_LOCAL_TABLE
, table
);
639 } else if (strcmp(*argv
, "nh4") == 0) {
642 duparg2("nh4", *argv
);
643 get_addr(&addr
, *argv
, AF_INET
);
644 rta_addattr_l(rta
, len
, SEG6_LOCAL_NH4
, &addr
.data
,
646 } else if (strcmp(*argv
, "nh6") == 0) {
649 duparg2("nh6", *argv
);
650 get_addr(&addr
, *argv
, AF_INET6
);
651 rta_addattr_l(rta
, len
, SEG6_LOCAL_NH6
, &addr
.data
,
653 } else if (strcmp(*argv
, "iif") == 0) {
656 duparg2("iif", *argv
);
657 iif
= if_nametoindex(*argv
);
659 invarg("\"iif\" interface not found\n", *argv
);
660 rta_addattr32(rta
, len
, SEG6_LOCAL_IIF
, iif
);
661 } else if (strcmp(*argv
, "oif") == 0) {
664 duparg2("oif", *argv
);
665 oif
= if_nametoindex(*argv
);
667 invarg("\"oif\" interface not found\n", *argv
);
668 rta_addattr32(rta
, len
, SEG6_LOCAL_OIF
, oif
);
669 } else if (strcmp(*argv
, "srh") == 0) {
672 duparg2("srh", *argv
);
673 if (strcmp(*argv
, "segs") != 0)
674 invarg("missing \"segs\" attribute for srh\n",
678 duparg2("segs", *argv
);
679 strncpy(segbuf
, *argv
, 1024);
684 if (strcmp(*argv
, "hmac") == 0) {
687 duparg2("hmac", *argv
);
688 get_u32(&hmac
, *argv
, 0);
699 fprintf(stderr
, "Missing action type\n");
706 srh
= parse_srh(segbuf
, hmac
,
707 action
== SEG6_LOCAL_ACTION_END_B6_ENCAP
);
708 srhlen
= (srh
->hdrlen
+ 1) << 3;
709 rta_addattr_l(rta
, len
, SEG6_LOCAL_SRH
, srh
, srhlen
);
719 static int parse_encap_mpls(struct rtattr
*rta
, size_t len
,
720 int *argcp
, char ***argvp
)
724 char **argv
= *argvp
;
727 if (get_addr(&addr
, *argv
, AF_MPLS
)) {
729 "Error: an inet address is expected rather than \"%s\".\n",
734 rta_addattr_l(rta
, len
, MPLS_IPTUNNEL_DST
, &addr
.data
,
741 if (strcmp(*argv
, "ttl") == 0) {
746 duparg2("ttl", *argv
);
747 if (get_u8(&ttl
, *argv
, 0))
748 invarg("\"ttl\" value is invalid\n", *argv
);
749 rta_addattr8(rta
, len
, MPLS_IPTUNNEL_TTL
, ttl
);
756 /* argv is currently the first unparsed argument,
757 * but the lwt_parse_encap() caller will move to the next,
766 static int parse_encap_ip(struct rtattr
*rta
, size_t len
,
767 int *argcp
, char ***argvp
)
769 int id_ok
= 0, dst_ok
= 0, tos_ok
= 0, ttl_ok
= 0;
770 char **argv
= *argvp
;
774 if (strcmp(*argv
, "id") == 0) {
779 duparg2("id", *argv
);
780 if (get_be64(&id
, *argv
, 0))
781 invarg("\"id\" value is invalid\n", *argv
);
782 rta_addattr64(rta
, len
, LWTUNNEL_IP_ID
, id
);
783 } else if (strcmp(*argv
, "dst") == 0) {
788 duparg2("dst", *argv
);
789 get_addr(&addr
, *argv
, AF_INET
);
790 rta_addattr_l(rta
, len
, LWTUNNEL_IP_DST
,
791 &addr
.data
, addr
.bytelen
);
792 } else if (strcmp(*argv
, "tos") == 0) {
797 duparg2("tos", *argv
);
798 if (rtnl_dsfield_a2n(&tos
, *argv
))
799 invarg("\"tos\" value is invalid\n", *argv
);
800 rta_addattr8(rta
, len
, LWTUNNEL_IP_TOS
, tos
);
801 } else if (strcmp(*argv
, "ttl") == 0) {
806 duparg2("ttl", *argv
);
807 if (get_u8(&ttl
, *argv
, 0))
808 invarg("\"ttl\" value is invalid\n", *argv
);
809 rta_addattr8(rta
, len
, LWTUNNEL_IP_TTL
, ttl
);
816 /* argv is currently the first unparsed argument,
817 * but the lwt_parse_encap() caller will move to the next,
826 static int parse_encap_ila(struct rtattr
*rta
, size_t len
,
827 int *argcp
, char ***argvp
)
831 char **argv
= *argvp
;
833 if (get_addr64(&locator
, *argv
) < 0) {
834 fprintf(stderr
, "Bad locator: %s\n", *argv
);
840 rta_addattr64(rta
, 1024, ILA_ATTR_LOCATOR
, locator
);
843 if (strcmp(*argv
, "csum-mode") == 0) {
848 csum_mode
= ila_csum_name2mode(*argv
);
850 invarg("\"csum-mode\" value is invalid\n",
853 rta_addattr8(rta
, 1024, ILA_ATTR_CSUM_MODE
,
857 } else if (strcmp(*argv
, "ident-type") == 0) {
862 ident_type
= ila_ident_name2type(*argv
);
864 invarg("\"ident-type\" value is invalid\n",
867 rta_addattr8(rta
, 1024, ILA_ATTR_IDENT_TYPE
,
871 } else if (strcmp(*argv
, "hook-type") == 0) {
876 hook_type
= ila_hook_name2type(*argv
);
878 invarg("\"hook-type\" value is invalid\n",
881 rta_addattr8(rta
, 1024, ILA_ATTR_HOOK_TYPE
,
890 /* argv is currently the first unparsed argument,
891 * but the lwt_parse_encap() caller will move to the next,
900 static int parse_encap_ip6(struct rtattr
*rta
, size_t len
,
901 int *argcp
, char ***argvp
)
903 int id_ok
= 0, dst_ok
= 0, tos_ok
= 0, ttl_ok
= 0;
904 char **argv
= *argvp
;
908 if (strcmp(*argv
, "id") == 0) {
913 duparg2("id", *argv
);
914 if (get_be64(&id
, *argv
, 0))
915 invarg("\"id\" value is invalid\n", *argv
);
916 rta_addattr64(rta
, len
, LWTUNNEL_IP6_ID
, id
);
917 } else if (strcmp(*argv
, "dst") == 0) {
922 duparg2("dst", *argv
);
923 get_addr(&addr
, *argv
, AF_INET6
);
924 rta_addattr_l(rta
, len
, LWTUNNEL_IP6_DST
,
925 &addr
.data
, addr
.bytelen
);
926 } else if (strcmp(*argv
, "tc") == 0) {
931 duparg2("tc", *argv
);
932 if (rtnl_dsfield_a2n(&tc
, *argv
))
933 invarg("\"tc\" value is invalid\n", *argv
);
934 rta_addattr8(rta
, len
, LWTUNNEL_IP6_TC
, tc
);
935 } else if (strcmp(*argv
, "hoplimit") == 0) {
940 duparg2("hoplimit", *argv
);
941 if (get_u8(&hoplimit
, *argv
, 0))
942 invarg("\"hoplimit\" value is invalid\n",
944 rta_addattr8(rta
, len
, LWTUNNEL_IP6_HOPLIMIT
, hoplimit
);
951 /* argv is currently the first unparsed argument,
952 * but the lwt_parse_encap() caller will move to the next,
966 static void bpf_lwt_cb(void *lwt_ptr
, int fd
, const char *annotation
)
968 struct lwt_x
*x
= lwt_ptr
;
970 rta_addattr32(x
->rta
, x
->len
, LWT_BPF_PROG_FD
, fd
);
971 rta_addattr_l(x
->rta
, x
->len
, LWT_BPF_PROG_NAME
, annotation
,
972 strlen(annotation
) + 1);
975 static const struct bpf_cfg_ops bpf_cb_ops
= {
976 .ebpf_cb
= bpf_lwt_cb
,
979 static int lwt_parse_bpf(struct rtattr
*rta
, size_t len
,
980 int *argcp
, char ***argvp
,
981 int attr
, const enum bpf_prog_type bpf_type
)
983 struct bpf_cfg_in cfg
= {
994 nest
= rta_nest(rta
, len
, attr
);
995 err
= bpf_parse_common(bpf_type
, &cfg
, &bpf_cb_ops
, &x
);
997 fprintf(stderr
, "Failed to parse eBPF program: %s\n",
1001 rta_nest_end(rta
, nest
);
1009 static void lwt_bpf_usage(void)
1011 fprintf(stderr
, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
1012 fprintf(stderr
, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
1016 static int parse_encap_bpf(struct rtattr
*rta
, size_t len
, int *argcp
,
1019 char **argv
= *argvp
;
1021 int headroom_set
= 0;
1024 if (strcmp(*argv
, "in") == 0) {
1026 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_IN
,
1027 BPF_PROG_TYPE_LWT_IN
) < 0)
1029 } else if (strcmp(*argv
, "out") == 0) {
1031 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_OUT
,
1032 BPF_PROG_TYPE_LWT_OUT
) < 0)
1034 } else if (strcmp(*argv
, "xmit") == 0) {
1036 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_XMIT
,
1037 BPF_PROG_TYPE_LWT_XMIT
) < 0)
1039 } else if (strcmp(*argv
, "headroom") == 0) {
1040 unsigned int headroom
;
1043 if (get_unsigned(&headroom
, *argv
, 0) || headroom
== 0)
1044 invarg("headroom is invalid\n", *argv
);
1046 rta_addattr32(rta
, 1024, LWT_BPF_XMIT_HEADROOM
,
1049 } else if (strcmp(*argv
, "help") == 0) {
1057 /* argv is currently the first unparsed argument,
1058 * but the lwt_parse_encap() caller will move to the next,
1067 int lwt_parse_encap(struct rtattr
*rta
, size_t len
, int *argcp
, char ***argvp
)
1069 struct rtattr
*nest
;
1071 char **argv
= *argvp
;
1075 type
= read_encap_type(*argv
);
1077 invarg("\"encap type\" value is invalid\n", *argv
);
1082 "Error: unexpected end of line after \"encap\"\n");
1086 nest
= rta_nest(rta
, 1024, RTA_ENCAP
);
1088 case LWTUNNEL_ENCAP_MPLS
:
1089 parse_encap_mpls(rta
, len
, &argc
, &argv
);
1091 case LWTUNNEL_ENCAP_IP
:
1092 parse_encap_ip(rta
, len
, &argc
, &argv
);
1094 case LWTUNNEL_ENCAP_ILA
:
1095 parse_encap_ila(rta
, len
, &argc
, &argv
);
1097 case LWTUNNEL_ENCAP_IP6
:
1098 parse_encap_ip6(rta
, len
, &argc
, &argv
);
1100 case LWTUNNEL_ENCAP_BPF
:
1101 if (parse_encap_bpf(rta
, len
, &argc
, &argv
) < 0)
1104 case LWTUNNEL_ENCAP_SEG6
:
1105 parse_encap_seg6(rta
, len
, &argc
, &argv
);
1107 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
1108 parse_encap_seg6local(rta
, len
, &argc
, &argv
);
1111 fprintf(stderr
, "Error: unsupported encap type\n");
1114 rta_nest_end(rta
, nest
);
1116 rta_addattr16(rta
, 1024, RTA_ENCAP_TYPE
, type
);