2 * m_tunnel_key.c ip tunnel manipulation module
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: Amir Vadai <amir@vadai.me>
16 #include <linux/if_ether.h>
20 #include <linux/tc_act/tc_tunnel_key.h>
22 static void explain(void)
25 "Usage: tunnel_key unset\n"
26 " tunnel_key set <TUNNEL_KEY>\n"
27 "Where TUNNEL_KEY is a combination of:\n"
29 "src_ip <IP> (mandatory)\n"
30 "dst_ip <IP> (mandatory)\n"
31 "dst_port <UDP_PORT>\n"
32 "geneve_opts | vxlan_opts | erspan_opts <OPTIONS>\n"
33 "csum | nocsum (default is \"csum\")\n");
36 static void usage(void)
42 static int tunnel_key_parse_ip_addr(const char *str
, int addr4_type
,
43 int addr6_type
, struct nlmsghdr
*n
)
48 ret
= get_addr(&addr
, str
, AF_UNSPEC
);
52 addattr_l(n
, MAX_MSG
, addr
.family
== AF_INET
? addr4_type
: addr6_type
,
53 addr
.data
, addr
.bytelen
);
58 static int tunnel_key_parse_key_id(const char *str
, int type
,
64 ret
= get_be32(&key_id
, str
, 10);
66 addattr32(n
, MAX_MSG
, type
, key_id
);
71 static int tunnel_key_parse_dst_port(char *str
, int type
, struct nlmsghdr
*n
)
76 ret
= get_be16(&dst_port
, str
, 10);
80 addattr16(n
, MAX_MSG
, type
, dst_port
);
85 static int tunnel_key_parse_be16(char *str
, int base
, int type
,
91 ret
= get_be16(&value
, str
, base
);
95 addattr16(n
, MAX_MSG
, type
, value
);
100 static int tunnel_key_parse_be32(char *str
, int base
, int type
,
106 ret
= get_be32(&value
, str
, base
);
110 addattr32(n
, MAX_MSG
, type
, value
);
115 static int tunnel_key_parse_u8(char *str
, int base
, int type
,
121 ret
= get_u8(&value
, str
, base
);
125 addattr8(n
, MAX_MSG
, type
, value
);
130 static int tunnel_key_parse_u32(char *str
, int base
, int type
,
136 ret
= get_u32(&value
, str
, base
);
140 addattr32(n
, MAX_MSG
, type
, value
);
145 static int tunnel_key_parse_geneve_opt(char *str
, struct nlmsghdr
*n
)
147 char *token
, *saveptr
= NULL
;
151 nest
= addattr_nest(n
, MAX_MSG
, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
);
153 token
= strtok_r(str
, ":", &saveptr
);
157 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
:
159 ret
= tunnel_key_parse_be16(token
, 16, i
, n
);
164 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
:
166 ret
= tunnel_key_parse_u8(token
, 16, i
, n
);
171 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
:
173 size_t token_len
= strlen(token
);
176 opts
= malloc(token_len
/ 2);
179 if (hex2mem(token
, opts
, token_len
/ 2) < 0) {
183 addattr_l(n
, MAX_MSG
, i
, opts
, token_len
/ 2);
192 token
= strtok_r(NULL
, ":", &saveptr
);
196 addattr_nest_end(n
, nest
);
201 static int tunnel_key_parse_geneve_opts(char *str
, struct nlmsghdr
*n
)
203 char *token
, *saveptr
= NULL
;
207 nest
= addattr_nest(n
, MAX_MSG
, TCA_TUNNEL_KEY_ENC_OPTS
);
209 token
= strtok_r(str
, ",", &saveptr
);
211 ret
= tunnel_key_parse_geneve_opt(token
, n
);
215 token
= strtok_r(NULL
, ",", &saveptr
);
218 addattr_nest_end(n
, nest
);
223 static int tunnel_key_parse_vxlan_opt(char *str
, struct nlmsghdr
*n
)
225 struct rtattr
*encap
, *nest
;
228 encap
= addattr_nest(n
, MAX_MSG
,
229 TCA_TUNNEL_KEY_ENC_OPTS
| NLA_F_NESTED
);
230 nest
= addattr_nest(n
, MAX_MSG
,
231 TCA_TUNNEL_KEY_ENC_OPTS_VXLAN
| NLA_F_NESTED
);
233 ret
= tunnel_key_parse_u32(str
, 0,
234 TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP
, n
);
238 addattr_nest_end(n
, nest
);
239 addattr_nest_end(n
, encap
);
244 static int tunnel_key_parse_erspan_opt(char *str
, struct nlmsghdr
*n
)
246 char *token
, *saveptr
= NULL
;
247 struct rtattr
*encap
, *nest
;
250 encap
= addattr_nest(n
, MAX_MSG
,
251 TCA_TUNNEL_KEY_ENC_OPTS
| NLA_F_NESTED
);
252 nest
= addattr_nest(n
, MAX_MSG
,
253 TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN
| NLA_F_NESTED
);
255 token
= strtok_r(str
, ":", &saveptr
);
259 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER
:
261 ret
= tunnel_key_parse_u8(token
, 0, i
, n
);
266 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX
:
268 ret
= tunnel_key_parse_be32(token
, 0, i
, n
);
273 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR
:
275 ret
= tunnel_key_parse_u8(token
, 0, i
, n
);
280 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID
:
282 ret
= tunnel_key_parse_u8(token
, 0, i
, n
);
291 token
= strtok_r(NULL
, ":", &saveptr
);
295 addattr_nest_end(n
, nest
);
296 addattr_nest_end(n
, encap
);
301 static int tunnel_key_parse_tos_ttl(char *str
, int type
, struct nlmsghdr
*n
)
306 ret
= get_u8(&val
, str
, 10);
308 ret
= get_u8(&val
, str
, 16);
312 addattr8(n
, MAX_MSG
, type
, val
);
317 static int parse_tunnel_key(struct action_util
*a
, int *argc_p
, char ***argv_p
,
318 int tca_id
, struct nlmsghdr
*n
)
320 struct tc_tunnel_key parm
= {};
321 char **argv
= *argv_p
;
330 if (matches(*argv
, "tunnel_key") != 0)
333 tail
= addattr_nest(n
, MAX_MSG
, tca_id
);
338 if (matches(*argv
, "unset") == 0) {
340 fprintf(stderr
, "unexpected \"%s\" - action already specified\n",
345 action
= TCA_TUNNEL_KEY_ACT_RELEASE
;
346 } else if (matches(*argv
, "set") == 0) {
348 fprintf(stderr
, "unexpected \"%s\" - action already specified\n",
353 action
= TCA_TUNNEL_KEY_ACT_SET
;
354 } else if (matches(*argv
, "src_ip") == 0) {
356 ret
= tunnel_key_parse_ip_addr(*argv
,
357 TCA_TUNNEL_KEY_ENC_IPV4_SRC
,
358 TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
361 fprintf(stderr
, "Illegal \"src_ip\"\n");
365 } else if (matches(*argv
, "dst_ip") == 0) {
367 ret
= tunnel_key_parse_ip_addr(*argv
,
368 TCA_TUNNEL_KEY_ENC_IPV4_DST
,
369 TCA_TUNNEL_KEY_ENC_IPV6_DST
,
372 fprintf(stderr
, "Illegal \"dst_ip\"\n");
376 } else if (matches(*argv
, "id") == 0) {
378 ret
= tunnel_key_parse_key_id(*argv
, TCA_TUNNEL_KEY_ENC_KEY_ID
, n
);
380 fprintf(stderr
, "Illegal \"id\"\n");
383 } else if (matches(*argv
, "dst_port") == 0) {
385 ret
= tunnel_key_parse_dst_port(*argv
,
386 TCA_TUNNEL_KEY_ENC_DST_PORT
, n
);
388 fprintf(stderr
, "Illegal \"dst port\"\n");
391 } else if (matches(*argv
, "geneve_opts") == 0) {
394 if (tunnel_key_parse_geneve_opts(*argv
, n
)) {
395 fprintf(stderr
, "Illegal \"geneve_opts\"\n");
398 } else if (matches(*argv
, "vxlan_opts") == 0) {
401 if (tunnel_key_parse_vxlan_opt(*argv
, n
)) {
402 fprintf(stderr
, "Illegal \"vxlan_opts\"\n");
405 } else if (matches(*argv
, "erspan_opts") == 0) {
408 if (tunnel_key_parse_erspan_opt(*argv
, n
)) {
409 fprintf(stderr
, "Illegal \"erspan_opts\"\n");
412 } else if (matches(*argv
, "tos") == 0) {
414 ret
= tunnel_key_parse_tos_ttl(*argv
,
415 TCA_TUNNEL_KEY_ENC_TOS
, n
);
417 fprintf(stderr
, "Illegal \"tos\"\n");
420 } else if (matches(*argv
, "ttl") == 0) {
422 ret
= tunnel_key_parse_tos_ttl(*argv
,
423 TCA_TUNNEL_KEY_ENC_TTL
, n
);
425 fprintf(stderr
, "Illegal \"ttl\"\n");
428 } else if (matches(*argv
, "csum") == 0) {
430 } else if (matches(*argv
, "nocsum") == 0) {
432 } else if (matches(*argv
, "help") == 0) {
440 addattr8(n
, MAX_MSG
, TCA_TUNNEL_KEY_NO_CSUM
, !csum
);
442 parse_action_control_dflt(&argc
, &argv
, &parm
.action
,
446 if (matches(*argv
, "index") == 0) {
448 if (get_u32(&parm
.index
, *argv
, 10)) {
449 fprintf(stderr
, "tunnel_key: Illegal \"index\"\n");
457 if (action
== TCA_TUNNEL_KEY_ACT_SET
&&
458 (!has_src_ip
|| !has_dst_ip
)) {
459 fprintf(stderr
, "set needs tunnel_key parameters\n");
464 parm
.t_action
= action
;
465 addattr_l(n
, MAX_MSG
, TCA_TUNNEL_KEY_PARMS
, &parm
, sizeof(parm
));
466 addattr_nest_end(n
, tail
);
474 static void tunnel_key_print_ip_addr(FILE *f
, const char *name
,
483 len
= RTA_PAYLOAD(attr
);
493 if (matches(name
, "src_ip") == 0)
494 print_string(PRINT_ANY
, "src_ip", "\tsrc_ip %s",
495 rt_addr_n2a_rta(family
, attr
));
496 else if (matches(name
, "dst_ip") == 0)
497 print_string(PRINT_ANY
, "dst_ip", "\tdst_ip %s",
498 rt_addr_n2a_rta(family
, attr
));
501 static void tunnel_key_print_key_id(FILE *f
, const char *name
,
507 print_uint(PRINT_ANY
, "key_id", "\tkey_id %u", rta_getattr_be32(attr
));
510 static void tunnel_key_print_dst_port(FILE *f
, char *name
,
516 print_uint(PRINT_ANY
, "dst_port", "\tdst_port %u",
517 rta_getattr_be16(attr
));
520 static void tunnel_key_print_flag(FILE *f
, const char *name_on
,
521 const char *name_off
,
527 print_string(PRINT_ANY
, "flag", "\t%s",
528 rta_getattr_u8(attr
) ? name_on
: name_off
);
531 static void tunnel_key_print_geneve_options(struct rtattr
*attr
)
533 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX
+ 1];
534 struct rtattr
*i
= RTA_DATA(attr
);
535 int ii
, data_len
= 0, offset
= 0;
536 int rem
= RTA_PAYLOAD(attr
);
537 char *name
= "geneve_opts";
538 char strbuf
[rem
* 2 + 1];
539 char data
[rem
* 2 + 1];
544 open_json_array(PRINT_JSON
, name
);
546 print_string(PRINT_FP
, name
, "\t%s ", name
);
549 parse_rtattr(tb
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX
, i
, rem
);
550 clss
= rta_getattr_be16(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
]);
551 type
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
]);
552 data_len
= RTA_PAYLOAD(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
]);
553 hexstring_n2a(RTA_DATA(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
]),
554 data_len
, data
, sizeof(data
));
555 hex2mem(data
, data_r
, data_len
);
556 offset
+= data_len
+ 20;
557 rem
-= data_len
+ 20;
558 i
= RTA_DATA(attr
) + offset
;
560 open_json_object(NULL
);
561 print_uint(PRINT_JSON
, "class", NULL
, clss
);
562 print_uint(PRINT_JSON
, "type", NULL
, type
);
563 open_json_array(PRINT_JSON
, "data");
564 for (ii
= 0; ii
< data_len
; ii
++)
565 print_uint(PRINT_JSON
, NULL
, NULL
, data_r
[ii
]);
566 close_json_array(PRINT_JSON
, "data");
569 sprintf(strbuf
, "%04x:%02x:%s", clss
, type
, data
);
571 print_string(PRINT_FP
, NULL
, "%s,", strbuf
);
573 print_string(PRINT_FP
, NULL
, "%s", strbuf
);
576 close_json_array(PRINT_JSON
, name
);
579 static void tunnel_key_print_vxlan_options(struct rtattr
*attr
)
581 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX
+ 1];
582 struct rtattr
*i
= RTA_DATA(attr
);
583 int rem
= RTA_PAYLOAD(attr
);
584 char *name
= "vxlan_opts";
587 parse_rtattr(tb
, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX
, i
, rem
);
588 gbp
= rta_getattr_u32(tb
[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP
]);
591 print_string(PRINT_FP
, name
, "\t%s ", name
);
592 open_json_array(PRINT_JSON
, name
);
593 open_json_object(NULL
);
594 print_uint(PRINT_ANY
, "gbp", "%u", gbp
);
596 close_json_array(PRINT_JSON
, name
);
599 static void tunnel_key_print_erspan_options(struct rtattr
*attr
)
601 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX
+ 1];
602 struct rtattr
*i
= RTA_DATA(attr
);
603 int rem
= RTA_PAYLOAD(attr
);
604 char *name
= "erspan_opts";
608 parse_rtattr(tb
, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX
, i
, rem
);
609 ver
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER
]);
611 idx
= rta_getattr_be32(tb
[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX
]);
616 dir
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR
]);
617 hwid
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID
]);
621 print_string(PRINT_FP
, name
, "\t%s ", name
);
622 open_json_array(PRINT_JSON
, name
);
623 open_json_object(NULL
);
624 print_uint(PRINT_ANY
, "ver", "%u", ver
);
625 print_uint(PRINT_ANY
, "index", ":%u", idx
);
626 print_uint(PRINT_ANY
, "dir", ":%u", dir
);
627 print_uint(PRINT_ANY
, "hwid", ":%u", hwid
);
629 close_json_array(PRINT_JSON
, name
);
632 static void tunnel_key_print_key_opt(struct rtattr
*attr
)
634 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPTS_MAX
+ 1];
639 parse_rtattr_nested(tb
, TCA_TUNNEL_KEY_ENC_OPTS_MAX
, attr
);
640 if (tb
[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
])
641 tunnel_key_print_geneve_options(
642 tb
[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
]);
643 else if (tb
[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN
])
644 tunnel_key_print_vxlan_options(
645 tb
[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN
]);
646 else if (tb
[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN
])
647 tunnel_key_print_erspan_options(
648 tb
[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN
]);
651 static void tunnel_key_print_tos_ttl(FILE *f
, char *name
,
657 if (matches(name
, "tos") == 0 && rta_getattr_u8(attr
) != 0) {
659 print_uint(PRINT_ANY
, "tos", "\ttos 0x%x",
660 rta_getattr_u8(attr
));
661 } else if (matches(name
, "ttl") == 0 && rta_getattr_u8(attr
) != 0) {
663 print_uint(PRINT_ANY
, "ttl", "\tttl %u",
664 rta_getattr_u8(attr
));
668 static int print_tunnel_key(struct action_util
*au
, FILE *f
, struct rtattr
*arg
)
670 struct rtattr
*tb
[TCA_TUNNEL_KEY_MAX
+ 1];
671 struct tc_tunnel_key
*parm
;
673 print_string(PRINT_ANY
, "kind", "%s ", "tunnel_key");
677 parse_rtattr_nested(tb
, TCA_TUNNEL_KEY_MAX
, arg
);
679 if (!tb
[TCA_TUNNEL_KEY_PARMS
]) {
680 fprintf(stderr
, "Missing tunnel_key parameters\n");
683 parm
= RTA_DATA(tb
[TCA_TUNNEL_KEY_PARMS
]);
685 switch (parm
->t_action
) {
686 case TCA_TUNNEL_KEY_ACT_RELEASE
:
687 print_string(PRINT_ANY
, "mode", " %s", "unset");
689 case TCA_TUNNEL_KEY_ACT_SET
:
690 print_string(PRINT_ANY
, "mode", " %s", "set");
691 tunnel_key_print_ip_addr(f
, "src_ip",
692 tb
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
]);
693 tunnel_key_print_ip_addr(f
, "dst_ip",
694 tb
[TCA_TUNNEL_KEY_ENC_IPV4_DST
]);
695 tunnel_key_print_ip_addr(f
, "src_ip",
696 tb
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
]);
697 tunnel_key_print_ip_addr(f
, "dst_ip",
698 tb
[TCA_TUNNEL_KEY_ENC_IPV6_DST
]);
699 tunnel_key_print_key_id(f
, "key_id",
700 tb
[TCA_TUNNEL_KEY_ENC_KEY_ID
]);
701 tunnel_key_print_dst_port(f
, "dst_port",
702 tb
[TCA_TUNNEL_KEY_ENC_DST_PORT
]);
703 tunnel_key_print_key_opt(tb
[TCA_TUNNEL_KEY_ENC_OPTS
]);
704 tunnel_key_print_flag(f
, "nocsum", "csum",
705 tb
[TCA_TUNNEL_KEY_NO_CSUM
]);
706 tunnel_key_print_tos_ttl(f
, "tos",
707 tb
[TCA_TUNNEL_KEY_ENC_TOS
]);
708 tunnel_key_print_tos_ttl(f
, "ttl",
709 tb
[TCA_TUNNEL_KEY_ENC_TTL
]);
712 print_action_control(f
, " ", parm
->action
, "");
715 print_uint(PRINT_ANY
, "index", "\t index %u", parm
->index
);
716 print_int(PRINT_ANY
, "ref", " ref %d", parm
->refcnt
);
717 print_int(PRINT_ANY
, "bind", " bind %d", parm
->bindcnt
);
720 if (tb
[TCA_TUNNEL_KEY_TM
]) {
721 struct tcf_t
*tm
= RTA_DATA(tb
[TCA_TUNNEL_KEY_TM
]);
732 struct action_util tunnel_key_action_util
= {
734 .parse_aopt
= parse_tunnel_key
,
735 .print_aopt
= print_tunnel_key
,