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)
24 fprintf(stderr
, "Usage: tunnel_key unset\n");
25 fprintf(stderr
, " 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 <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_u8(char *str
, int base
, int type
,
106 ret
= get_u8(&value
, str
, base
);
110 addattr8(n
, MAX_MSG
, type
, value
);
115 static int tunnel_key_parse_geneve_opt(char *str
, struct nlmsghdr
*n
)
117 char *token
, *saveptr
= NULL
;
121 nest
= addattr_nest(n
, MAX_MSG
, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
);
123 token
= strtok_r(str
, ":", &saveptr
);
127 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
:
129 ret
= tunnel_key_parse_be16(token
, 16, i
, n
);
134 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
:
136 ret
= tunnel_key_parse_u8(token
, 16, i
, n
);
141 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
:
143 size_t token_len
= strlen(token
);
146 opts
= malloc(token_len
/ 2);
149 if (hex2mem(token
, opts
, token_len
/ 2) < 0) {
153 addattr_l(n
, MAX_MSG
, i
, opts
, token_len
/ 2);
162 token
= strtok_r(NULL
, ":", &saveptr
);
166 addattr_nest_end(n
, nest
);
171 static int tunnel_key_parse_geneve_opts(char *str
, struct nlmsghdr
*n
)
173 char *token
, *saveptr
= NULL
;
177 nest
= addattr_nest(n
, MAX_MSG
, TCA_TUNNEL_KEY_ENC_OPTS
);
179 token
= strtok_r(str
, ",", &saveptr
);
181 ret
= tunnel_key_parse_geneve_opt(token
, n
);
185 token
= strtok_r(NULL
, ",", &saveptr
);
188 addattr_nest_end(n
, nest
);
193 static int tunnel_key_parse_tos_ttl(char *str
, int type
, struct nlmsghdr
*n
)
198 ret
= get_u8(&val
, str
, 10);
200 ret
= get_u8(&val
, str
, 16);
204 addattr8(n
, MAX_MSG
, type
, val
);
209 static int parse_tunnel_key(struct action_util
*a
, int *argc_p
, char ***argv_p
,
210 int tca_id
, struct nlmsghdr
*n
)
212 struct tc_tunnel_key parm
= {};
213 char **argv
= *argv_p
;
222 if (matches(*argv
, "tunnel_key") != 0)
225 tail
= addattr_nest(n
, MAX_MSG
, tca_id
);
230 if (matches(*argv
, "unset") == 0) {
232 fprintf(stderr
, "unexpected \"%s\" - action already specified\n",
237 action
= TCA_TUNNEL_KEY_ACT_RELEASE
;
238 } else if (matches(*argv
, "set") == 0) {
240 fprintf(stderr
, "unexpected \"%s\" - action already specified\n",
245 action
= TCA_TUNNEL_KEY_ACT_SET
;
246 } else if (matches(*argv
, "src_ip") == 0) {
248 ret
= tunnel_key_parse_ip_addr(*argv
,
249 TCA_TUNNEL_KEY_ENC_IPV4_SRC
,
250 TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
253 fprintf(stderr
, "Illegal \"src_ip\"\n");
257 } else if (matches(*argv
, "dst_ip") == 0) {
259 ret
= tunnel_key_parse_ip_addr(*argv
,
260 TCA_TUNNEL_KEY_ENC_IPV4_DST
,
261 TCA_TUNNEL_KEY_ENC_IPV6_DST
,
264 fprintf(stderr
, "Illegal \"dst_ip\"\n");
268 } else if (matches(*argv
, "id") == 0) {
270 ret
= tunnel_key_parse_key_id(*argv
, TCA_TUNNEL_KEY_ENC_KEY_ID
, n
);
272 fprintf(stderr
, "Illegal \"id\"\n");
275 } else if (matches(*argv
, "dst_port") == 0) {
277 ret
= tunnel_key_parse_dst_port(*argv
,
278 TCA_TUNNEL_KEY_ENC_DST_PORT
, n
);
280 fprintf(stderr
, "Illegal \"dst port\"\n");
283 } else if (matches(*argv
, "geneve_opts") == 0) {
286 if (tunnel_key_parse_geneve_opts(*argv
, n
)) {
287 fprintf(stderr
, "Illegal \"geneve_opts\"\n");
290 } else if (matches(*argv
, "tos") == 0) {
292 ret
= tunnel_key_parse_tos_ttl(*argv
,
293 TCA_TUNNEL_KEY_ENC_TOS
, n
);
295 fprintf(stderr
, "Illegal \"tos\"\n");
298 } else if (matches(*argv
, "ttl") == 0) {
300 ret
= tunnel_key_parse_tos_ttl(*argv
,
301 TCA_TUNNEL_KEY_ENC_TTL
, n
);
303 fprintf(stderr
, "Illegal \"ttl\"\n");
306 } else if (matches(*argv
, "csum") == 0) {
308 } else if (matches(*argv
, "nocsum") == 0) {
310 } else if (matches(*argv
, "help") == 0) {
318 addattr8(n
, MAX_MSG
, TCA_TUNNEL_KEY_NO_CSUM
, !csum
);
320 parse_action_control_dflt(&argc
, &argv
, &parm
.action
,
324 if (matches(*argv
, "index") == 0) {
326 if (get_u32(&parm
.index
, *argv
, 10)) {
327 fprintf(stderr
, "tunnel_key: Illegal \"index\"\n");
335 if (action
== TCA_TUNNEL_KEY_ACT_SET
&&
336 (!has_src_ip
|| !has_dst_ip
)) {
337 fprintf(stderr
, "set needs tunnel_key parameters\n");
342 parm
.t_action
= action
;
343 addattr_l(n
, MAX_MSG
, TCA_TUNNEL_KEY_PARMS
, &parm
, sizeof(parm
));
344 addattr_nest_end(n
, tail
);
352 static void tunnel_key_print_ip_addr(FILE *f
, const char *name
,
361 len
= RTA_PAYLOAD(attr
);
370 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
371 if (matches(name
, "src_ip") == 0)
372 print_string(PRINT_ANY
, "src_ip", "\tsrc_ip %s",
373 rt_addr_n2a_rta(family
, attr
));
374 else if (matches(name
, "dst_ip") == 0)
375 print_string(PRINT_ANY
, "dst_ip", "\tdst_ip %s",
376 rt_addr_n2a_rta(family
, attr
));
379 static void tunnel_key_print_key_id(FILE *f
, const char *name
,
384 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
385 print_uint(PRINT_ANY
, "key_id", "\tkey_id %u", rta_getattr_be32(attr
));
388 static void tunnel_key_print_dst_port(FILE *f
, char *name
,
393 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
394 print_uint(PRINT_ANY
, "dst_port", "\tdst_port %u",
395 rta_getattr_be16(attr
));
398 static void tunnel_key_print_flag(FILE *f
, const char *name_on
,
399 const char *name_off
,
404 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
405 print_string(PRINT_ANY
, "flag", "\t%s",
406 rta_getattr_u8(attr
) ? name_on
: name_off
);
409 static void tunnel_key_print_geneve_options(const char *name
,
412 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX
+ 1];
413 struct rtattr
*i
= RTA_DATA(attr
);
414 int ii
, data_len
= 0, offset
= 0;
415 int rem
= RTA_PAYLOAD(attr
);
416 char strbuf
[rem
* 2 + 1];
417 char data
[rem
* 2 + 1];
422 open_json_array(PRINT_JSON
, name
);
423 print_string(PRINT_FP
, name
, "\n\t%s ", "geneve_opt");
426 parse_rtattr(tb
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX
, i
, rem
);
427 clss
= rta_getattr_be16(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
]);
428 type
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
]);
429 data_len
= RTA_PAYLOAD(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
]);
430 hexstring_n2a(RTA_DATA(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
]),
431 data_len
, data
, sizeof(data
));
432 hex2mem(data
, data_r
, data_len
);
433 offset
+= data_len
+ 20;
434 rem
-= data_len
+ 20;
435 i
= RTA_DATA(attr
) + offset
;
437 open_json_object(NULL
);
438 print_uint(PRINT_JSON
, "class", NULL
, clss
);
439 print_uint(PRINT_JSON
, "type", NULL
, type
);
440 open_json_array(PRINT_JSON
, "data");
441 for (ii
= 0; ii
< data_len
; ii
++)
442 print_uint(PRINT_JSON
, NULL
, NULL
, data_r
[ii
]);
443 close_json_array(PRINT_JSON
, "data");
446 sprintf(strbuf
, "%04x:%02x:%s", clss
, type
, data
);
448 print_string(PRINT_FP
, NULL
, "%s,", strbuf
);
450 print_string(PRINT_FP
, NULL
, "%s", strbuf
);
453 close_json_array(PRINT_JSON
, name
);
456 static void tunnel_key_print_key_opt(const char *name
, struct rtattr
*attr
)
458 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPTS_MAX
+ 1];
463 parse_rtattr_nested(tb
, TCA_TUNNEL_KEY_ENC_OPTS_MAX
, attr
);
464 tunnel_key_print_geneve_options(name
,
465 tb
[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
]);
468 static void tunnel_key_print_tos_ttl(FILE *f
, char *name
,
474 if (matches(name
, "tos") == 0 && rta_getattr_u8(attr
) != 0) {
475 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
476 print_uint(PRINT_ANY
, "tos", "\ttos 0x%x",
477 rta_getattr_u8(attr
));
478 } else if (matches(name
, "ttl") == 0 && rta_getattr_u8(attr
) != 0) {
479 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
480 print_uint(PRINT_ANY
, "ttl", "\tttl %u",
481 rta_getattr_u8(attr
));
485 static int print_tunnel_key(struct action_util
*au
, FILE *f
, struct rtattr
*arg
)
487 struct rtattr
*tb
[TCA_TUNNEL_KEY_MAX
+ 1];
488 struct tc_tunnel_key
*parm
;
493 parse_rtattr_nested(tb
, TCA_TUNNEL_KEY_MAX
, arg
);
495 if (!tb
[TCA_TUNNEL_KEY_PARMS
]) {
496 print_string(PRINT_FP
, NULL
, "%s",
497 "[NULL tunnel_key parameters]");
500 parm
= RTA_DATA(tb
[TCA_TUNNEL_KEY_PARMS
]);
502 print_string(PRINT_ANY
, "kind", "%s ", "tunnel_key");
504 switch (parm
->t_action
) {
505 case TCA_TUNNEL_KEY_ACT_RELEASE
:
506 print_string(PRINT_ANY
, "mode", " %s", "unset");
508 case TCA_TUNNEL_KEY_ACT_SET
:
509 print_string(PRINT_ANY
, "mode", " %s", "set");
510 tunnel_key_print_ip_addr(f
, "src_ip",
511 tb
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
]);
512 tunnel_key_print_ip_addr(f
, "dst_ip",
513 tb
[TCA_TUNNEL_KEY_ENC_IPV4_DST
]);
514 tunnel_key_print_ip_addr(f
, "src_ip",
515 tb
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
]);
516 tunnel_key_print_ip_addr(f
, "dst_ip",
517 tb
[TCA_TUNNEL_KEY_ENC_IPV6_DST
]);
518 tunnel_key_print_key_id(f
, "key_id",
519 tb
[TCA_TUNNEL_KEY_ENC_KEY_ID
]);
520 tunnel_key_print_dst_port(f
, "dst_port",
521 tb
[TCA_TUNNEL_KEY_ENC_DST_PORT
]);
522 tunnel_key_print_key_opt("geneve_opts",
523 tb
[TCA_TUNNEL_KEY_ENC_OPTS
]);
524 tunnel_key_print_flag(f
, "nocsum", "csum",
525 tb
[TCA_TUNNEL_KEY_NO_CSUM
]);
526 tunnel_key_print_tos_ttl(f
, "tos",
527 tb
[TCA_TUNNEL_KEY_ENC_TOS
]);
528 tunnel_key_print_tos_ttl(f
, "ttl",
529 tb
[TCA_TUNNEL_KEY_ENC_TTL
]);
532 print_action_control(f
, " ", parm
->action
, "");
534 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
535 print_uint(PRINT_ANY
, "index", "\t index %u", parm
->index
);
536 print_int(PRINT_ANY
, "ref", " ref %d", parm
->refcnt
);
537 print_int(PRINT_ANY
, "bind", " bind %d", parm
->bindcnt
);
540 if (tb
[TCA_TUNNEL_KEY_TM
]) {
541 struct tcf_t
*tm
= RTA_DATA(tb
[TCA_TUNNEL_KEY_TM
]);
547 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
552 struct action_util tunnel_key_action_util
= {
554 .parse_aopt
= parse_tunnel_key
,
555 .print_aopt
= print_tunnel_key
,