1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * m_tunnel_key.c ip tunnel manipulation module
5 * Authors: Amir Vadai <amir@vadai.me>
12 #include <linux/if_ether.h>
16 #include <linux/tc_act/tc_tunnel_key.h>
18 static void explain(void)
21 "Usage: tunnel_key unset\n"
22 " tunnel_key set <TUNNEL_KEY>\n"
23 "Where TUNNEL_KEY is a combination of:\n"
25 "src_ip <IP> (mandatory)\n"
26 "dst_ip <IP> (mandatory)\n"
27 "dst_port <UDP_PORT>\n"
28 "geneve_opts | vxlan_opts | erspan_opts <OPTIONS>\n"
29 "csum | nocsum (default is \"csum\")\n"
33 static void usage(void)
39 static int tunnel_key_parse_ip_addr(const char *str
, int addr4_type
,
40 int addr6_type
, struct nlmsghdr
*n
)
45 ret
= get_addr(&addr
, str
, AF_UNSPEC
);
49 addattr_l(n
, MAX_MSG
, addr
.family
== AF_INET
? addr4_type
: addr6_type
,
50 addr
.data
, addr
.bytelen
);
55 static int tunnel_key_parse_key_id(const char *str
, int type
,
61 ret
= get_be32(&key_id
, str
, 10);
63 addattr32(n
, MAX_MSG
, type
, key_id
);
68 static int tunnel_key_parse_dst_port(char *str
, int type
, struct nlmsghdr
*n
)
73 ret
= get_be16(&dst_port
, str
, 10);
77 addattr16(n
, MAX_MSG
, type
, dst_port
);
82 static int tunnel_key_parse_be16(char *str
, int base
, int type
,
88 ret
= get_be16(&value
, str
, base
);
92 addattr16(n
, MAX_MSG
, type
, value
);
97 static int tunnel_key_parse_be32(char *str
, int base
, int type
,
103 ret
= get_be32(&value
, str
, base
);
107 addattr32(n
, MAX_MSG
, type
, value
);
112 static int tunnel_key_parse_u8(char *str
, int base
, int type
,
118 ret
= get_u8(&value
, str
, base
);
122 addattr8(n
, MAX_MSG
, type
, value
);
127 static int tunnel_key_parse_u32(char *str
, int base
, int type
,
133 ret
= get_u32(&value
, str
, base
);
137 addattr32(n
, MAX_MSG
, type
, value
);
142 static int tunnel_key_parse_geneve_opt(char *str
, struct nlmsghdr
*n
)
144 char *token
, *saveptr
= NULL
;
148 nest
= addattr_nest(n
, MAX_MSG
, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
);
150 token
= strtok_r(str
, ":", &saveptr
);
154 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
:
156 ret
= tunnel_key_parse_be16(token
, 16, i
, n
);
161 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
:
163 ret
= tunnel_key_parse_u8(token
, 16, i
, n
);
168 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
:
170 size_t token_len
= strlen(token
);
173 opts
= malloc(token_len
/ 2);
176 if (hex2mem(token
, opts
, token_len
/ 2) < 0) {
180 addattr_l(n
, MAX_MSG
, i
, opts
, token_len
/ 2);
189 token
= strtok_r(NULL
, ":", &saveptr
);
193 addattr_nest_end(n
, nest
);
198 static int tunnel_key_parse_geneve_opts(char *str
, struct nlmsghdr
*n
)
200 char *token
, *saveptr
= NULL
;
204 nest
= addattr_nest(n
, MAX_MSG
, TCA_TUNNEL_KEY_ENC_OPTS
);
206 token
= strtok_r(str
, ",", &saveptr
);
208 ret
= tunnel_key_parse_geneve_opt(token
, n
);
212 token
= strtok_r(NULL
, ",", &saveptr
);
215 addattr_nest_end(n
, nest
);
220 static int tunnel_key_parse_vxlan_opt(char *str
, struct nlmsghdr
*n
)
222 struct rtattr
*encap
, *nest
;
225 encap
= addattr_nest(n
, MAX_MSG
,
226 TCA_TUNNEL_KEY_ENC_OPTS
| NLA_F_NESTED
);
227 nest
= addattr_nest(n
, MAX_MSG
,
228 TCA_TUNNEL_KEY_ENC_OPTS_VXLAN
| NLA_F_NESTED
);
230 ret
= tunnel_key_parse_u32(str
, 0,
231 TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP
, n
);
235 addattr_nest_end(n
, nest
);
236 addattr_nest_end(n
, encap
);
241 static int tunnel_key_parse_erspan_opt(char *str
, struct nlmsghdr
*n
)
243 char *token
, *saveptr
= NULL
;
244 struct rtattr
*encap
, *nest
;
247 encap
= addattr_nest(n
, MAX_MSG
,
248 TCA_TUNNEL_KEY_ENC_OPTS
| NLA_F_NESTED
);
249 nest
= addattr_nest(n
, MAX_MSG
,
250 TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN
| NLA_F_NESTED
);
252 token
= strtok_r(str
, ":", &saveptr
);
256 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER
:
258 ret
= tunnel_key_parse_u8(token
, 0, i
, n
);
263 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX
:
265 ret
= tunnel_key_parse_be32(token
, 0, i
, n
);
270 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR
:
272 ret
= tunnel_key_parse_u8(token
, 0, i
, n
);
277 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID
:
279 ret
= tunnel_key_parse_u8(token
, 0, i
, n
);
288 token
= strtok_r(NULL
, ":", &saveptr
);
292 addattr_nest_end(n
, nest
);
293 addattr_nest_end(n
, encap
);
298 static int tunnel_key_parse_tos_ttl(char *str
, int type
, struct nlmsghdr
*n
)
303 ret
= get_u8(&val
, str
, 10);
305 ret
= get_u8(&val
, str
, 16);
309 addattr8(n
, MAX_MSG
, type
, val
);
314 static int parse_tunnel_key(const struct action_util
*a
, int *argc_p
, char ***argv_p
,
315 int tca_id
, struct nlmsghdr
*n
)
317 struct tc_tunnel_key parm
= {};
318 char **argv
= *argv_p
;
325 int csum
= 1, nofrag
= 0;
327 if (matches(*argv
, "tunnel_key") != 0)
330 tail
= addattr_nest(n
, MAX_MSG
, tca_id
);
335 if (matches(*argv
, "unset") == 0) {
337 fprintf(stderr
, "unexpected \"%s\" - action already specified\n",
342 action
= TCA_TUNNEL_KEY_ACT_RELEASE
;
343 } else if (matches(*argv
, "set") == 0) {
345 fprintf(stderr
, "unexpected \"%s\" - action already specified\n",
350 action
= TCA_TUNNEL_KEY_ACT_SET
;
351 } else if (matches(*argv
, "src_ip") == 0) {
353 ret
= tunnel_key_parse_ip_addr(*argv
,
354 TCA_TUNNEL_KEY_ENC_IPV4_SRC
,
355 TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
358 fprintf(stderr
, "Illegal \"src_ip\"\n");
362 } else if (matches(*argv
, "dst_ip") == 0) {
364 ret
= tunnel_key_parse_ip_addr(*argv
,
365 TCA_TUNNEL_KEY_ENC_IPV4_DST
,
366 TCA_TUNNEL_KEY_ENC_IPV6_DST
,
369 fprintf(stderr
, "Illegal \"dst_ip\"\n");
373 } else if (matches(*argv
, "id") == 0) {
375 ret
= tunnel_key_parse_key_id(*argv
, TCA_TUNNEL_KEY_ENC_KEY_ID
, n
);
377 fprintf(stderr
, "Illegal \"id\"\n");
380 } else if (matches(*argv
, "dst_port") == 0) {
382 ret
= tunnel_key_parse_dst_port(*argv
,
383 TCA_TUNNEL_KEY_ENC_DST_PORT
, n
);
385 fprintf(stderr
, "Illegal \"dst port\"\n");
388 } else if (matches(*argv
, "geneve_opts") == 0) {
391 if (tunnel_key_parse_geneve_opts(*argv
, n
)) {
392 fprintf(stderr
, "Illegal \"geneve_opts\"\n");
395 } else if (matches(*argv
, "vxlan_opts") == 0) {
398 if (tunnel_key_parse_vxlan_opt(*argv
, n
)) {
399 fprintf(stderr
, "Illegal \"vxlan_opts\"\n");
402 } else if (matches(*argv
, "erspan_opts") == 0) {
405 if (tunnel_key_parse_erspan_opt(*argv
, n
)) {
406 fprintf(stderr
, "Illegal \"erspan_opts\"\n");
409 } else if (matches(*argv
, "tos") == 0) {
411 ret
= tunnel_key_parse_tos_ttl(*argv
,
412 TCA_TUNNEL_KEY_ENC_TOS
, n
);
414 fprintf(stderr
, "Illegal \"tos\"\n");
417 } else if (matches(*argv
, "ttl") == 0) {
419 ret
= tunnel_key_parse_tos_ttl(*argv
,
420 TCA_TUNNEL_KEY_ENC_TTL
, n
);
422 fprintf(stderr
, "Illegal \"ttl\"\n");
425 } else if (matches(*argv
, "csum") == 0) {
427 } else if (matches(*argv
, "nocsum") == 0) {
429 } else if (strcmp(*argv
, "nofrag") == 0) {
431 } else if (matches(*argv
, "help") == 0) {
439 addattr8(n
, MAX_MSG
, TCA_TUNNEL_KEY_NO_CSUM
, !csum
);
442 addattr(n
, MAX_MSG
, TCA_TUNNEL_KEY_NO_FRAG
);
444 parse_action_control_dflt(&argc
, &argv
, &parm
.action
,
448 if (matches(*argv
, "index") == 0) {
450 if (get_u32(&parm
.index
, *argv
, 10)) {
451 fprintf(stderr
, "tunnel_key: Illegal \"index\"\n");
459 if (action
== TCA_TUNNEL_KEY_ACT_SET
&&
460 (!has_src_ip
|| !has_dst_ip
)) {
461 fprintf(stderr
, "set needs tunnel_key parameters\n");
466 parm
.t_action
= action
;
467 addattr_l(n
, MAX_MSG
, TCA_TUNNEL_KEY_PARMS
, &parm
, sizeof(parm
));
468 addattr_nest_end(n
, tail
);
476 static void tunnel_key_print_ip_addr(FILE *f
, const char *name
,
485 len
= RTA_PAYLOAD(attr
);
495 if (matches(name
, "src_ip") == 0)
496 print_string(PRINT_ANY
, "src_ip", "\tsrc_ip %s",
497 rt_addr_n2a_rta(family
, attr
));
498 else if (matches(name
, "dst_ip") == 0)
499 print_string(PRINT_ANY
, "dst_ip", "\tdst_ip %s",
500 rt_addr_n2a_rta(family
, attr
));
503 static void tunnel_key_print_key_id(FILE *f
, const char *name
,
509 print_uint(PRINT_ANY
, "key_id", "\tkey_id %u", rta_getattr_be32(attr
));
512 static void tunnel_key_print_dst_port(FILE *f
, char *name
,
518 print_uint(PRINT_ANY
, "dst_port", "\tdst_port %u",
519 rta_getattr_be16(attr
));
522 static const struct {
524 unsigned int nl_flag
;
525 } tunnel_key_flag_names
[] = {
526 { "", TCA_TUNNEL_KEY_NO_CSUM
}, /* special handling, not bool */
527 { "nofrag", TCA_TUNNEL_KEY_NO_FRAG
},
530 static void tunnel_key_print_flags(struct rtattr
*tb
[])
532 unsigned int i
, nl_flag
;
535 for (i
= 0; i
< ARRAY_SIZE(tunnel_key_flag_names
); i
++) {
536 nl_flag
= tunnel_key_flag_names
[i
].nl_flag
;
537 if (nl_flag
== TCA_TUNNEL_KEY_NO_CSUM
) {
538 /* special handling to preserve csum/nocsum design */
541 print_string(PRINT_ANY
, "flag", "\t%s",
542 rta_getattr_u8(tb
[nl_flag
]) ?
546 print_string(PRINT_FP
, NULL
, "\t%s",
547 tunnel_key_flag_names
[i
].name
);
548 print_bool(PRINT_JSON
, tunnel_key_flag_names
[i
].name
,
549 NULL
, !!tb
[nl_flag
]);
554 static void tunnel_key_print_geneve_options(struct rtattr
*attr
)
556 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX
+ 1];
557 struct rtattr
*i
= RTA_DATA(attr
);
558 int ii
, data_len
= 0, offset
= 0;
559 int rem
= RTA_PAYLOAD(attr
);
560 char *name
= "geneve_opts";
561 char strbuf
[rem
* 2 + 1];
562 char data
[rem
* 2 + 1];
567 open_json_array(PRINT_JSON
, name
);
569 print_string(PRINT_FP
, name
, "\t%s ", name
);
572 parse_rtattr(tb
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX
, i
, rem
);
573 clss
= rta_getattr_be16(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
]);
574 type
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
]);
575 data_len
= RTA_PAYLOAD(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
]);
576 hexstring_n2a(RTA_DATA(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
]),
577 data_len
, data
, sizeof(data
));
578 hex2mem(data
, data_r
, data_len
);
579 offset
+= data_len
+ 20;
580 rem
-= data_len
+ 20;
581 i
= RTA_DATA(attr
) + offset
;
583 open_json_object(NULL
);
584 print_uint(PRINT_JSON
, "class", NULL
, clss
);
585 print_uint(PRINT_JSON
, "type", NULL
, type
);
586 open_json_array(PRINT_JSON
, "data");
587 for (ii
= 0; ii
< data_len
; ii
++)
588 print_uint(PRINT_JSON
, NULL
, NULL
, data_r
[ii
]);
589 close_json_array(PRINT_JSON
, "data");
592 sprintf(strbuf
, "%04x:%02x:%s", clss
, type
, data
);
594 print_string(PRINT_FP
, NULL
, "%s,", strbuf
);
596 print_string(PRINT_FP
, NULL
, "%s", strbuf
);
599 close_json_array(PRINT_JSON
, name
);
602 static void tunnel_key_print_vxlan_options(struct rtattr
*attr
)
604 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX
+ 1];
605 struct rtattr
*i
= RTA_DATA(attr
);
606 int rem
= RTA_PAYLOAD(attr
);
607 char *name
= "vxlan_opts";
610 parse_rtattr(tb
, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX
, i
, rem
);
611 gbp
= rta_getattr_u32(tb
[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP
]);
614 print_string(PRINT_FP
, name
, "\t%s ", name
);
615 open_json_array(PRINT_JSON
, name
);
616 open_json_object(NULL
);
617 print_uint(PRINT_ANY
, "gbp", "%u", gbp
);
619 close_json_array(PRINT_JSON
, name
);
622 static void tunnel_key_print_erspan_options(struct rtattr
*attr
)
624 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX
+ 1];
625 struct rtattr
*i
= RTA_DATA(attr
);
626 int rem
= RTA_PAYLOAD(attr
);
627 char *name
= "erspan_opts";
631 parse_rtattr(tb
, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX
, i
, rem
);
632 ver
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER
]);
634 idx
= rta_getattr_be32(tb
[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX
]);
639 dir
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR
]);
640 hwid
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID
]);
644 print_string(PRINT_FP
, name
, "\t%s ", name
);
645 open_json_array(PRINT_JSON
, name
);
646 open_json_object(NULL
);
647 print_uint(PRINT_ANY
, "ver", "%u", ver
);
648 print_uint(PRINT_ANY
, "index", ":%u", idx
);
649 print_uint(PRINT_ANY
, "dir", ":%u", dir
);
650 print_uint(PRINT_ANY
, "hwid", ":%u", hwid
);
652 close_json_array(PRINT_JSON
, name
);
655 static void tunnel_key_print_key_opt(struct rtattr
*attr
)
657 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPTS_MAX
+ 1];
662 parse_rtattr_nested(tb
, TCA_TUNNEL_KEY_ENC_OPTS_MAX
, attr
);
663 if (tb
[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
])
664 tunnel_key_print_geneve_options(
665 tb
[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
]);
666 else if (tb
[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN
])
667 tunnel_key_print_vxlan_options(
668 tb
[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN
]);
669 else if (tb
[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN
])
670 tunnel_key_print_erspan_options(
671 tb
[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN
]);
674 static void tunnel_key_print_tos_ttl(FILE *f
, char *name
,
680 if (matches(name
, "tos") == 0 && rta_getattr_u8(attr
) != 0) {
682 print_uint(PRINT_ANY
, "tos", "\ttos 0x%x",
683 rta_getattr_u8(attr
));
684 } else if (matches(name
, "ttl") == 0 && rta_getattr_u8(attr
) != 0) {
686 print_uint(PRINT_ANY
, "ttl", "\tttl %u",
687 rta_getattr_u8(attr
));
691 static int print_tunnel_key(const struct action_util
*au
, FILE *f
, struct rtattr
*arg
)
693 struct rtattr
*tb
[TCA_TUNNEL_KEY_MAX
+ 1];
694 struct tc_tunnel_key
*parm
;
696 print_string(PRINT_ANY
, "kind", "%s ", "tunnel_key");
700 parse_rtattr_nested(tb
, TCA_TUNNEL_KEY_MAX
, arg
);
702 if (!tb
[TCA_TUNNEL_KEY_PARMS
]) {
703 fprintf(stderr
, "Missing tunnel_key parameters\n");
706 parm
= RTA_DATA(tb
[TCA_TUNNEL_KEY_PARMS
]);
708 switch (parm
->t_action
) {
709 case TCA_TUNNEL_KEY_ACT_RELEASE
:
710 print_string(PRINT_ANY
, "mode", " %s", "unset");
712 case TCA_TUNNEL_KEY_ACT_SET
:
713 print_string(PRINT_ANY
, "mode", " %s", "set");
714 tunnel_key_print_ip_addr(f
, "src_ip",
715 tb
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
]);
716 tunnel_key_print_ip_addr(f
, "dst_ip",
717 tb
[TCA_TUNNEL_KEY_ENC_IPV4_DST
]);
718 tunnel_key_print_ip_addr(f
, "src_ip",
719 tb
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
]);
720 tunnel_key_print_ip_addr(f
, "dst_ip",
721 tb
[TCA_TUNNEL_KEY_ENC_IPV6_DST
]);
722 tunnel_key_print_key_id(f
, "key_id",
723 tb
[TCA_TUNNEL_KEY_ENC_KEY_ID
]);
724 tunnel_key_print_dst_port(f
, "dst_port",
725 tb
[TCA_TUNNEL_KEY_ENC_DST_PORT
]);
726 tunnel_key_print_key_opt(tb
[TCA_TUNNEL_KEY_ENC_OPTS
]);
727 tunnel_key_print_flags(tb
);
728 tunnel_key_print_tos_ttl(f
, "tos",
729 tb
[TCA_TUNNEL_KEY_ENC_TOS
]);
730 tunnel_key_print_tos_ttl(f
, "ttl",
731 tb
[TCA_TUNNEL_KEY_ENC_TTL
]);
734 print_action_control(f
, " ", parm
->action
, "");
737 print_uint(PRINT_ANY
, "index", "\t index %u", parm
->index
);
738 print_int(PRINT_ANY
, "ref", " ref %d", parm
->refcnt
);
739 print_int(PRINT_ANY
, "bind", " bind %d", parm
->bindcnt
);
742 if (tb
[TCA_TUNNEL_KEY_TM
]) {
743 struct tcf_t
*tm
= RTA_DATA(tb
[TCA_TUNNEL_KEY_TM
]);
754 struct action_util tunnel_key_action_util
= {
756 .parse_aopt
= parse_tunnel_key
,
757 .print_aopt
= print_tunnel_key
,