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>
20 #include <bsd/string.h>
22 #include <linux/ila.h>
23 #include <linux/lwtunnel.h>
24 #include <linux/mpls_iptunnel.h>
30 #include "ip_common.h"
31 #include "ila_common.h"
33 #include <linux/seg6.h>
34 #include <linux/seg6_iptunnel.h>
35 #include <linux/seg6_hmac.h>
36 #include <linux/seg6_local.h>
39 static const char *format_encap_type(int type
)
42 case LWTUNNEL_ENCAP_MPLS
:
44 case LWTUNNEL_ENCAP_IP
:
46 case LWTUNNEL_ENCAP_IP6
:
48 case LWTUNNEL_ENCAP_ILA
:
50 case LWTUNNEL_ENCAP_BPF
:
52 case LWTUNNEL_ENCAP_SEG6
:
54 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
61 static void encap_type_usage(void)
65 fprintf(stderr
, "Usage: ip route ... encap TYPE [ OPTIONS ] [...]\n");
67 for (i
= 1; i
<= LWTUNNEL_ENCAP_MAX
; i
++)
68 fprintf(stderr
, "%s %s\n", format_encap_type(i
),
69 i
== 1 ? "TYPE := " : " ");
74 static int read_encap_type(const char *name
)
76 if (strcmp(name
, "mpls") == 0)
77 return LWTUNNEL_ENCAP_MPLS
;
78 else if (strcmp(name
, "ip") == 0)
79 return LWTUNNEL_ENCAP_IP
;
80 else if (strcmp(name
, "ip6") == 0)
81 return LWTUNNEL_ENCAP_IP6
;
82 else if (strcmp(name
, "ila") == 0)
83 return LWTUNNEL_ENCAP_ILA
;
84 else if (strcmp(name
, "bpf") == 0)
85 return LWTUNNEL_ENCAP_BPF
;
86 else if (strcmp(name
, "seg6") == 0)
87 return LWTUNNEL_ENCAP_SEG6
;
88 else if (strcmp(name
, "seg6local") == 0)
89 return LWTUNNEL_ENCAP_SEG6_LOCAL
;
90 else if (strcmp(name
, "help") == 0)
93 return LWTUNNEL_ENCAP_NONE
;
96 static void print_srh(FILE *fp
, struct ipv6_sr_hdr
*srh
)
100 if (is_json_context())
101 open_json_array(PRINT_JSON
, "segs");
103 fprintf(fp
, "segs %d [ ", srh
->first_segment
+ 1);
105 for (i
= srh
->first_segment
; i
>= 0; i
--)
106 print_color_string(PRINT_ANY
, COLOR_INET6
,
108 rt_addr_n2a(AF_INET6
, 16, &srh
->segments
[i
]));
110 if (is_json_context())
111 close_json_array(PRINT_JSON
, NULL
);
115 if (sr_has_hmac(srh
)) {
116 unsigned int offset
= ((srh
->hdrlen
+ 1) << 3) - 40;
117 struct sr6_tlv_hmac
*tlv
;
119 tlv
= (struct sr6_tlv_hmac
*)((char *)srh
+ offset
);
120 print_0xhex(PRINT_ANY
, "hmac",
121 "hmac 0x%X ", ntohl(tlv
->hmackeyid
));
125 static const char *seg6_mode_types
[] = {
126 [SEG6_IPTUN_MODE_INLINE
] = "inline",
127 [SEG6_IPTUN_MODE_ENCAP
] = "encap",
128 [SEG6_IPTUN_MODE_L2ENCAP
] = "l2encap",
131 static const char *format_seg6mode_type(int mode
)
133 if (mode
< 0 || mode
> ARRAY_SIZE(seg6_mode_types
))
136 return seg6_mode_types
[mode
];
139 static int read_seg6mode_type(const char *mode
)
143 for (i
= 0; i
< ARRAY_SIZE(seg6_mode_types
); i
++) {
144 if (strcmp(mode
, seg6_mode_types
[i
]) == 0)
151 static void print_encap_seg6(FILE *fp
, struct rtattr
*encap
)
153 struct rtattr
*tb
[SEG6_IPTUNNEL_MAX
+1];
154 struct seg6_iptunnel_encap
*tuninfo
;
156 parse_rtattr_nested(tb
, SEG6_IPTUNNEL_MAX
, encap
);
158 if (!tb
[SEG6_IPTUNNEL_SRH
])
161 tuninfo
= RTA_DATA(tb
[SEG6_IPTUNNEL_SRH
]);
162 print_string(PRINT_ANY
, "mode",
163 "mode %s ", format_seg6mode_type(tuninfo
->mode
));
165 print_srh(fp
, tuninfo
->srh
);
168 static const char *seg6_action_names
[SEG6_LOCAL_ACTION_MAX
+ 1] = {
169 [SEG6_LOCAL_ACTION_END
] = "End",
170 [SEG6_LOCAL_ACTION_END_X
] = "End.X",
171 [SEG6_LOCAL_ACTION_END_T
] = "End.T",
172 [SEG6_LOCAL_ACTION_END_DX2
] = "End.DX2",
173 [SEG6_LOCAL_ACTION_END_DX6
] = "End.DX6",
174 [SEG6_LOCAL_ACTION_END_DX4
] = "End.DX4",
175 [SEG6_LOCAL_ACTION_END_DT6
] = "End.DT6",
176 [SEG6_LOCAL_ACTION_END_DT4
] = "End.DT4",
177 [SEG6_LOCAL_ACTION_END_B6
] = "End.B6",
178 [SEG6_LOCAL_ACTION_END_B6_ENCAP
] = "End.B6.Encaps",
179 [SEG6_LOCAL_ACTION_END_BM
] = "End.BM",
180 [SEG6_LOCAL_ACTION_END_S
] = "End.S",
181 [SEG6_LOCAL_ACTION_END_AS
] = "End.AS",
182 [SEG6_LOCAL_ACTION_END_AM
] = "End.AM",
183 [SEG6_LOCAL_ACTION_END_BPF
] = "End.BPF",
186 static const char *format_action_type(int action
)
188 if (action
< 0 || action
> SEG6_LOCAL_ACTION_MAX
)
191 return seg6_action_names
[action
] ?: "<unknown>";
194 static int read_action_type(const char *name
)
198 for (i
= 0; i
< SEG6_LOCAL_ACTION_MAX
+ 1; i
++) {
199 if (!seg6_action_names
[i
])
202 if (strcmp(seg6_action_names
[i
], name
) == 0)
206 return SEG6_LOCAL_ACTION_UNSPEC
;
209 static void print_encap_bpf_prog(FILE *fp
, struct rtattr
*encap
,
212 struct rtattr
*tb
[LWT_BPF_PROG_MAX
+1];
213 const char *progname
= NULL
;
215 parse_rtattr_nested(tb
, LWT_BPF_PROG_MAX
, encap
);
217 if (tb
[LWT_BPF_PROG_NAME
])
218 progname
= rta_getattr_str(tb
[LWT_BPF_PROG_NAME
]);
220 if (is_json_context())
221 print_string(PRINT_JSON
, str
, NULL
,
222 progname
? : "<unknown>");
224 fprintf(fp
, "%s ", str
);
226 fprintf(fp
, "%s ", progname
);
230 static void print_encap_seg6local(FILE *fp
, struct rtattr
*encap
)
232 struct rtattr
*tb
[SEG6_LOCAL_MAX
+ 1];
235 parse_rtattr_nested(tb
, SEG6_LOCAL_MAX
, encap
);
237 if (!tb
[SEG6_LOCAL_ACTION
])
240 action
= rta_getattr_u32(tb
[SEG6_LOCAL_ACTION
]);
242 print_string(PRINT_ANY
, "action",
243 "action %s ", format_action_type(action
));
245 if (tb
[SEG6_LOCAL_SRH
]) {
246 open_json_object("srh");
247 print_srh(fp
, RTA_DATA(tb
[SEG6_LOCAL_SRH
]));
251 if (tb
[SEG6_LOCAL_TABLE
])
252 print_uint(PRINT_ANY
, "table",
253 "table %u ", rta_getattr_u32(tb
[SEG6_LOCAL_TABLE
]));
255 if (tb
[SEG6_LOCAL_NH4
]) {
256 print_string(PRINT_ANY
, "nh4",
257 "nh4 %s ", rt_addr_n2a_rta(AF_INET
, tb
[SEG6_LOCAL_NH4
]));
260 if (tb
[SEG6_LOCAL_NH6
]) {
261 print_string(PRINT_ANY
, "nh6",
262 "nh6 %s ", rt_addr_n2a_rta(AF_INET6
, tb
[SEG6_LOCAL_NH6
]));
265 if (tb
[SEG6_LOCAL_IIF
]) {
266 int iif
= rta_getattr_u32(tb
[SEG6_LOCAL_IIF
]);
268 print_string(PRINT_ANY
, "iif",
269 "iif %s ", ll_index_to_name(iif
));
272 if (tb
[SEG6_LOCAL_OIF
]) {
273 int oif
= rta_getattr_u32(tb
[SEG6_LOCAL_OIF
]);
275 print_string(PRINT_ANY
, "oif",
276 "oif %s ", ll_index_to_name(oif
));
279 if (tb
[SEG6_LOCAL_BPF
])
280 print_encap_bpf_prog(fp
, tb
[SEG6_LOCAL_BPF
], "endpoint");
283 static void print_encap_mpls(FILE *fp
, struct rtattr
*encap
)
285 struct rtattr
*tb
[MPLS_IPTUNNEL_MAX
+1];
287 parse_rtattr_nested(tb
, MPLS_IPTUNNEL_MAX
, encap
);
289 if (tb
[MPLS_IPTUNNEL_DST
])
290 print_string(PRINT_ANY
, "dst", " %s ",
291 format_host_rta(AF_MPLS
, tb
[MPLS_IPTUNNEL_DST
]));
292 if (tb
[MPLS_IPTUNNEL_TTL
])
293 print_uint(PRINT_ANY
, "ttl", "ttl %u ",
294 rta_getattr_u8(tb
[MPLS_IPTUNNEL_TTL
]));
297 static void print_encap_ip(FILE *fp
, struct rtattr
*encap
)
299 struct rtattr
*tb
[LWTUNNEL_IP_MAX
+1];
301 parse_rtattr_nested(tb
, LWTUNNEL_IP_MAX
, encap
);
303 if (tb
[LWTUNNEL_IP_ID
])
304 print_u64(PRINT_ANY
, "id", "id %llu ",
305 ntohll(rta_getattr_u64(tb
[LWTUNNEL_IP_ID
])));
307 if (tb
[LWTUNNEL_IP_SRC
])
308 print_color_string(PRINT_ANY
, COLOR_INET
,
310 rt_addr_n2a_rta(AF_INET
, tb
[LWTUNNEL_IP_SRC
]));
312 if (tb
[LWTUNNEL_IP_DST
])
313 print_color_string(PRINT_ANY
, COLOR_INET
,
315 rt_addr_n2a_rta(AF_INET
, tb
[LWTUNNEL_IP_DST
]));
317 if (tb
[LWTUNNEL_IP_TTL
])
318 print_uint(PRINT_ANY
, "ttl",
319 "ttl %u ", rta_getattr_u8(tb
[LWTUNNEL_IP_TTL
]));
321 if (tb
[LWTUNNEL_IP_TOS
])
322 print_uint(PRINT_ANY
, "tos",
323 "tos %d ", rta_getattr_u8(tb
[LWTUNNEL_IP_TOS
]));
326 static void print_encap_ila(FILE *fp
, struct rtattr
*encap
)
328 struct rtattr
*tb
[ILA_ATTR_MAX
+1];
330 parse_rtattr_nested(tb
, ILA_ATTR_MAX
, encap
);
332 if (tb
[ILA_ATTR_LOCATOR
]) {
333 char abuf
[ADDR64_BUF_SIZE
];
335 addr64_n2a(rta_getattr_u64(tb
[ILA_ATTR_LOCATOR
]),
337 print_string(PRINT_ANY
, "locator",
341 if (tb
[ILA_ATTR_CSUM_MODE
])
342 print_string(PRINT_ANY
, "csum_mode",
344 ila_csum_mode2name(rta_getattr_u8(tb
[ILA_ATTR_CSUM_MODE
])));
346 if (tb
[ILA_ATTR_IDENT_TYPE
])
347 print_string(PRINT_ANY
, "ident_type",
349 ila_ident_type2name(rta_getattr_u8(tb
[ILA_ATTR_IDENT_TYPE
])));
351 if (tb
[ILA_ATTR_HOOK_TYPE
])
352 print_string(PRINT_ANY
, "hook_type",
354 ila_hook_type2name(rta_getattr_u8(tb
[ILA_ATTR_HOOK_TYPE
])));
357 static void print_encap_ip6(FILE *fp
, struct rtattr
*encap
)
359 struct rtattr
*tb
[LWTUNNEL_IP6_MAX
+1];
361 parse_rtattr_nested(tb
, LWTUNNEL_IP6_MAX
, encap
);
363 if (tb
[LWTUNNEL_IP6_ID
])
364 print_u64(PRINT_ANY
, "id", "id %llu ",
365 ntohll(rta_getattr_u64(tb
[LWTUNNEL_IP6_ID
])));
367 if (tb
[LWTUNNEL_IP6_SRC
])
368 print_color_string(PRINT_ANY
, COLOR_INET6
,
370 rt_addr_n2a_rta(AF_INET6
, tb
[LWTUNNEL_IP6_SRC
]));
372 if (tb
[LWTUNNEL_IP6_DST
])
373 print_color_string(PRINT_ANY
, COLOR_INET6
,
375 rt_addr_n2a_rta(AF_INET6
, tb
[LWTUNNEL_IP6_DST
]));
377 if (tb
[LWTUNNEL_IP6_HOPLIMIT
])
378 print_u64(PRINT_ANY
, "hoplimit",
380 rta_getattr_u8(tb
[LWTUNNEL_IP6_HOPLIMIT
]));
382 if (tb
[LWTUNNEL_IP6_TC
])
383 print_uint(PRINT_ANY
, "tc",
384 "tc %u ", rta_getattr_u8(tb
[LWTUNNEL_IP6_TC
]));
387 static void print_encap_bpf(FILE *fp
, struct rtattr
*encap
)
389 struct rtattr
*tb
[LWT_BPF_MAX
+1];
391 parse_rtattr_nested(tb
, LWT_BPF_MAX
, encap
);
394 print_encap_bpf_prog(fp
, tb
[LWT_BPF_IN
], "in");
396 print_encap_bpf_prog(fp
, tb
[LWT_BPF_OUT
], "out");
397 if (tb
[LWT_BPF_XMIT
])
398 print_encap_bpf_prog(fp
, tb
[LWT_BPF_XMIT
], "xmit");
399 if (tb
[LWT_BPF_XMIT_HEADROOM
])
400 print_uint(PRINT_ANY
, "headroom",
401 " %u ", rta_getattr_u32(tb
[LWT_BPF_XMIT_HEADROOM
]));
404 void lwt_print_encap(FILE *fp
, struct rtattr
*encap_type
,
405 struct rtattr
*encap
)
412 et
= rta_getattr_u16(encap_type
);
414 print_string(PRINT_ANY
, "encap", " encap %s ", format_encap_type(et
));
417 case LWTUNNEL_ENCAP_MPLS
:
418 print_encap_mpls(fp
, encap
);
420 case LWTUNNEL_ENCAP_IP
:
421 print_encap_ip(fp
, encap
);
423 case LWTUNNEL_ENCAP_ILA
:
424 print_encap_ila(fp
, encap
);
426 case LWTUNNEL_ENCAP_IP6
:
427 print_encap_ip6(fp
, encap
);
429 case LWTUNNEL_ENCAP_BPF
:
430 print_encap_bpf(fp
, encap
);
432 case LWTUNNEL_ENCAP_SEG6
:
433 print_encap_seg6(fp
, encap
);
435 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
436 print_encap_seg6local(fp
, encap
);
441 static struct ipv6_sr_hdr
*parse_srh(char *segbuf
, int hmac
, bool encap
)
443 struct ipv6_sr_hdr
*srh
;
450 for (i
= 0; *s
; *s
++ == ',' ? i
++ : *s
);
456 srhlen
= 8 + 16*nsegs
;
461 srh
= malloc(srhlen
);
462 memset(srh
, 0, srhlen
);
464 srh
->hdrlen
= (srhlen
>> 3) - 1;
466 srh
->segments_left
= nsegs
- 1;
467 srh
->first_segment
= nsegs
- 1;
470 srh
->flags
|= SR6_FLAG1_HMAC
;
472 i
= srh
->first_segment
;
473 for (s
= strtok(segbuf
, ","); s
; s
= strtok(NULL
, ",")) {
476 get_addr(&addr
, s
, AF_INET6
);
477 memcpy(&srh
->segments
[i
], addr
.data
, sizeof(struct in6_addr
));
482 struct sr6_tlv_hmac
*tlv
;
484 tlv
= (struct sr6_tlv_hmac
*)((char *)srh
+ srhlen
- 40);
485 tlv
->tlvhdr
.type
= SR6_TLV_HMAC
;
486 tlv
->tlvhdr
.len
= 38;
487 tlv
->hmackeyid
= htonl(hmac
);
493 static int parse_encap_seg6(struct rtattr
*rta
, size_t len
, int *argcp
,
496 int mode_ok
= 0, segs_ok
= 0, hmac_ok
= 0;
497 struct seg6_iptunnel_encap
*tuninfo
;
498 struct ipv6_sr_hdr
*srh
;
499 char **argv
= *argvp
;
500 char segbuf
[1024] = "";
508 if (strcmp(*argv
, "mode") == 0) {
511 duparg2("mode", *argv
);
512 encap
= read_seg6mode_type(*argv
);
514 invarg("\"mode\" value is invalid\n", *argv
);
515 } else if (strcmp(*argv
, "segs") == 0) {
518 duparg2("segs", *argv
);
520 invarg("\"segs\" provided before \"mode\"\n",
523 strlcpy(segbuf
, *argv
, 1024);
524 } else if (strcmp(*argv
, "hmac") == 0) {
527 duparg2("hmac", *argv
);
528 get_u32(&hmac
, *argv
, 0);
535 srh
= parse_srh(segbuf
, hmac
, encap
);
536 srhlen
= (srh
->hdrlen
+ 1) << 3;
538 tuninfo
= malloc(sizeof(*tuninfo
) + srhlen
);
539 memset(tuninfo
, 0, sizeof(*tuninfo
) + srhlen
);
541 tuninfo
->mode
= encap
;
543 memcpy(tuninfo
->srh
, srh
, srhlen
);
545 if (rta_addattr_l(rta
, len
, SEG6_IPTUNNEL_SRH
, tuninfo
,
546 sizeof(*tuninfo
) + srhlen
)) {
566 static void bpf_lwt_cb(void *lwt_ptr
, int fd
, const char *annotation
)
568 struct lwt_x
*x
= lwt_ptr
;
570 rta_addattr32(x
->rta
, x
->len
, LWT_BPF_PROG_FD
, fd
);
571 rta_addattr_l(x
->rta
, x
->len
, LWT_BPF_PROG_NAME
, annotation
,
572 strlen(annotation
) + 1);
575 static const struct bpf_cfg_ops bpf_cb_ops
= {
576 .ebpf_cb
= bpf_lwt_cb
,
579 static int lwt_parse_bpf(struct rtattr
*rta
, size_t len
,
580 int *argcp
, char ***argvp
,
581 int attr
, const enum bpf_prog_type bpf_type
)
583 struct bpf_cfg_in cfg
= {
595 nest
= rta_nest(rta
, len
, attr
);
596 err
= bpf_parse_and_load_common(&cfg
, &bpf_cb_ops
, &x
);
598 fprintf(stderr
, "Failed to parse eBPF program: %s\n",
602 rta_nest_end(rta
, nest
);
610 static int parse_encap_seg6local(struct rtattr
*rta
, size_t len
, int *argcp
,
613 int segs_ok
= 0, hmac_ok
= 0, table_ok
= 0, nh4_ok
= 0, nh6_ok
= 0;
614 int iif_ok
= 0, oif_ok
= 0, action_ok
= 0, srh_ok
= 0, bpf_ok
= 0;
615 __u32 action
= 0, table
, iif
, oif
;
616 struct ipv6_sr_hdr
*srh
;
617 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 ret
= rta_addattr32(rta
, len
, SEG6_LOCAL_ACTION
,
634 } else if (strcmp(*argv
, "table") == 0) {
637 duparg2("table", *argv
);
638 get_u32(&table
, *argv
, 0);
639 ret
= rta_addattr32(rta
, len
, SEG6_LOCAL_TABLE
, table
);
640 } else if (strcmp(*argv
, "nh4") == 0) {
643 duparg2("nh4", *argv
);
644 get_addr(&addr
, *argv
, AF_INET
);
645 ret
= rta_addattr_l(rta
, len
, SEG6_LOCAL_NH4
,
646 &addr
.data
, addr
.bytelen
);
647 } else if (strcmp(*argv
, "nh6") == 0) {
650 duparg2("nh6", *argv
);
651 get_addr(&addr
, *argv
, AF_INET6
);
652 ret
= rta_addattr_l(rta
, len
, SEG6_LOCAL_NH6
,
653 &addr
.data
, addr
.bytelen
);
654 } else if (strcmp(*argv
, "iif") == 0) {
657 duparg2("iif", *argv
);
658 iif
= ll_name_to_index(*argv
);
661 ret
= rta_addattr32(rta
, len
, SEG6_LOCAL_IIF
, iif
);
662 } else if (strcmp(*argv
, "oif") == 0) {
665 duparg2("oif", *argv
);
666 oif
= ll_name_to_index(*argv
);
669 ret
= rta_addattr32(rta
, len
, SEG6_LOCAL_OIF
, oif
);
670 } else if (strcmp(*argv
, "srh") == 0) {
673 duparg2("srh", *argv
);
674 if (strcmp(*argv
, "segs") != 0)
675 invarg("missing \"segs\" attribute for srh\n",
679 duparg2("segs", *argv
);
680 strncpy(segbuf
, *argv
, 1024);
685 if (strcmp(*argv
, "hmac") == 0) {
688 duparg2("hmac", *argv
);
689 get_u32(&hmac
, *argv
, 0);
693 } else if (strcmp(*argv
, "endpoint") == 0) {
696 duparg2("endpoint", *argv
);
698 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, SEG6_LOCAL_BPF
,
699 BPF_PROG_TYPE_LWT_SEG6LOCAL
) < 0)
710 fprintf(stderr
, "Missing action type\n");
717 srh
= parse_srh(segbuf
, hmac
,
718 action
== SEG6_LOCAL_ACTION_END_B6_ENCAP
);
719 srhlen
= (srh
->hdrlen
+ 1) << 3;
720 ret
= rta_addattr_l(rta
, len
, SEG6_LOCAL_SRH
, srh
, srhlen
);
730 static int parse_encap_mpls(struct rtattr
*rta
, size_t len
,
731 int *argcp
, char ***argvp
)
735 char **argv
= *argvp
;
738 if (get_addr(&addr
, *argv
, AF_MPLS
)) {
740 "Error: an inet address is expected rather than \"%s\".\n",
745 if (rta_addattr_l(rta
, len
, MPLS_IPTUNNEL_DST
,
746 &addr
.data
, addr
.bytelen
))
753 if (strcmp(*argv
, "ttl") == 0) {
758 duparg2("ttl", *argv
);
759 if (get_u8(&ttl
, *argv
, 0))
760 invarg("\"ttl\" value is invalid\n", *argv
);
761 if (rta_addattr8(rta
, len
, MPLS_IPTUNNEL_TTL
, ttl
))
769 /* argv is currently the first unparsed argument,
770 * but the lwt_parse_encap() caller will move to the next,
779 static int parse_encap_ip(struct rtattr
*rta
, size_t len
,
780 int *argcp
, char ***argvp
)
782 int id_ok
= 0, dst_ok
= 0, src_ok
= 0, tos_ok
= 0, ttl_ok
= 0;
783 char **argv
= *argvp
;
788 if (strcmp(*argv
, "id") == 0) {
793 duparg2("id", *argv
);
794 if (get_be64(&id
, *argv
, 0))
795 invarg("\"id\" value is invalid\n", *argv
);
796 ret
= rta_addattr64(rta
, len
, LWTUNNEL_IP_ID
, id
);
797 } else if (strcmp(*argv
, "dst") == 0) {
802 duparg2("dst", *argv
);
803 get_addr(&addr
, *argv
, AF_INET
);
804 ret
= rta_addattr_l(rta
, len
, LWTUNNEL_IP_DST
,
805 &addr
.data
, addr
.bytelen
);
806 } else if (strcmp(*argv
, "src") == 0) {
811 duparg2("src", *argv
);
812 get_addr(&addr
, *argv
, AF_INET
);
813 ret
= rta_addattr_l(rta
, len
, LWTUNNEL_IP_SRC
,
814 &addr
.data
, addr
.bytelen
);
815 } else if (strcmp(*argv
, "tos") == 0) {
820 duparg2("tos", *argv
);
821 if (rtnl_dsfield_a2n(&tos
, *argv
))
822 invarg("\"tos\" value is invalid\n", *argv
);
823 ret
= rta_addattr8(rta
, len
, LWTUNNEL_IP_TOS
, tos
);
824 } else if (strcmp(*argv
, "ttl") == 0) {
829 duparg2("ttl", *argv
);
830 if (get_u8(&ttl
, *argv
, 0))
831 invarg("\"ttl\" value is invalid\n", *argv
);
832 ret
= rta_addattr8(rta
, len
, LWTUNNEL_IP_TTL
, ttl
);
841 /* argv is currently the first unparsed argument,
842 * but the lwt_parse_encap() caller will move to the next,
851 static int parse_encap_ila(struct rtattr
*rta
, size_t len
,
852 int *argcp
, char ***argvp
)
856 char **argv
= *argvp
;
859 if (get_addr64(&locator
, *argv
) < 0) {
860 fprintf(stderr
, "Bad locator: %s\n", *argv
);
866 if (rta_addattr64(rta
, 1024, ILA_ATTR_LOCATOR
, locator
))
870 if (strcmp(*argv
, "csum-mode") == 0) {
875 csum_mode
= ila_csum_name2mode(*argv
);
877 invarg("\"csum-mode\" value is invalid\n",
880 ret
= rta_addattr8(rta
, 1024, ILA_ATTR_CSUM_MODE
,
884 } else if (strcmp(*argv
, "ident-type") == 0) {
889 ident_type
= ila_ident_name2type(*argv
);
891 invarg("\"ident-type\" value is invalid\n",
894 ret
= rta_addattr8(rta
, 1024, ILA_ATTR_IDENT_TYPE
,
898 } else if (strcmp(*argv
, "hook-type") == 0) {
903 hook_type
= ila_hook_name2type(*argv
);
905 invarg("\"hook-type\" value is invalid\n",
908 ret
= rta_addattr8(rta
, 1024, ILA_ATTR_HOOK_TYPE
,
919 /* argv is currently the first unparsed argument,
920 * but the lwt_parse_encap() caller will move to the next,
929 static int parse_encap_ip6(struct rtattr
*rta
, size_t len
,
930 int *argcp
, char ***argvp
)
932 int id_ok
= 0, dst_ok
= 0, src_ok
= 0, tos_ok
= 0, ttl_ok
= 0;
933 char **argv
= *argvp
;
938 if (strcmp(*argv
, "id") == 0) {
943 duparg2("id", *argv
);
944 if (get_be64(&id
, *argv
, 0))
945 invarg("\"id\" value is invalid\n", *argv
);
946 ret
= rta_addattr64(rta
, len
, LWTUNNEL_IP6_ID
, id
);
947 } else if (strcmp(*argv
, "dst") == 0) {
952 duparg2("dst", *argv
);
953 get_addr(&addr
, *argv
, AF_INET6
);
954 ret
= rta_addattr_l(rta
, len
, LWTUNNEL_IP6_DST
,
955 &addr
.data
, addr
.bytelen
);
956 } else if (strcmp(*argv
, "src") == 0) {
961 duparg2("src", *argv
);
962 get_addr(&addr
, *argv
, AF_INET6
);
963 ret
= rta_addattr_l(rta
, len
, LWTUNNEL_IP6_SRC
,
964 &addr
.data
, addr
.bytelen
);
965 } else if (strcmp(*argv
, "tc") == 0) {
970 duparg2("tc", *argv
);
971 if (rtnl_dsfield_a2n(&tc
, *argv
))
972 invarg("\"tc\" value is invalid\n", *argv
);
973 ret
= rta_addattr8(rta
, len
, LWTUNNEL_IP6_TC
, tc
);
974 } else if (strcmp(*argv
, "hoplimit") == 0) {
979 duparg2("hoplimit", *argv
);
980 if (get_u8(&hoplimit
, *argv
, 0))
981 invarg("\"hoplimit\" value is invalid\n",
983 ret
= rta_addattr8(rta
, len
, LWTUNNEL_IP6_HOPLIMIT
,
993 /* argv is currently the first unparsed argument,
994 * but the lwt_parse_encap() caller will move to the next,
1003 static void lwt_bpf_usage(void)
1005 fprintf(stderr
, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
1006 fprintf(stderr
, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
1010 static int parse_encap_bpf(struct rtattr
*rta
, size_t len
, int *argcp
,
1013 char **argv
= *argvp
;
1015 int headroom_set
= 0;
1018 if (strcmp(*argv
, "in") == 0) {
1020 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_IN
,
1021 BPF_PROG_TYPE_LWT_IN
) < 0)
1023 } else if (strcmp(*argv
, "out") == 0) {
1025 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_OUT
,
1026 BPF_PROG_TYPE_LWT_OUT
) < 0)
1028 } else if (strcmp(*argv
, "xmit") == 0) {
1030 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_XMIT
,
1031 BPF_PROG_TYPE_LWT_XMIT
) < 0)
1033 } else if (strcmp(*argv
, "headroom") == 0) {
1034 unsigned int headroom
;
1037 if (get_unsigned(&headroom
, *argv
, 0) || headroom
== 0)
1038 invarg("headroom is invalid\n", *argv
);
1040 rta_addattr32(rta
, 1024, LWT_BPF_XMIT_HEADROOM
,
1043 } else if (strcmp(*argv
, "help") == 0) {
1051 /* argv is currently the first unparsed argument,
1052 * but the lwt_parse_encap() caller will move to the next,
1061 int lwt_parse_encap(struct rtattr
*rta
, size_t len
, int *argcp
, char ***argvp
)
1063 struct rtattr
*nest
;
1065 char **argv
= *argvp
;
1070 type
= read_encap_type(*argv
);
1072 invarg("\"encap type\" value is invalid\n", *argv
);
1077 "Error: unexpected end of line after \"encap\"\n");
1081 nest
= rta_nest(rta
, 1024, RTA_ENCAP
);
1083 case LWTUNNEL_ENCAP_MPLS
:
1084 ret
= parse_encap_mpls(rta
, len
, &argc
, &argv
);
1086 case LWTUNNEL_ENCAP_IP
:
1087 ret
= parse_encap_ip(rta
, len
, &argc
, &argv
);
1089 case LWTUNNEL_ENCAP_ILA
:
1090 ret
= parse_encap_ila(rta
, len
, &argc
, &argv
);
1092 case LWTUNNEL_ENCAP_IP6
:
1093 ret
= parse_encap_ip6(rta
, len
, &argc
, &argv
);
1095 case LWTUNNEL_ENCAP_BPF
:
1096 if (parse_encap_bpf(rta
, len
, &argc
, &argv
) < 0)
1099 case LWTUNNEL_ENCAP_SEG6
:
1100 ret
= parse_encap_seg6(rta
, len
, &argc
, &argv
);
1102 case LWTUNNEL_ENCAP_SEG6_LOCAL
:
1103 ret
= parse_encap_seg6local(rta
, len
, &argc
, &argv
);
1106 fprintf(stderr
, "Error: unsupported encap type\n");
1112 rta_nest_end(rta
, nest
);
1114 ret
= rta_addattr16(rta
, 1024, RTA_ENCAP_TYPE
, type
);