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"
28 "id <TUNNELID> (mandatory)\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
;
223 if (matches(*argv
, "tunnel_key") != 0)
226 tail
= addattr_nest(n
, MAX_MSG
, tca_id
);
231 if (matches(*argv
, "unset") == 0) {
233 fprintf(stderr
, "unexpected \"%s\" - action already specified\n",
238 action
= TCA_TUNNEL_KEY_ACT_RELEASE
;
239 } else if (matches(*argv
, "set") == 0) {
241 fprintf(stderr
, "unexpected \"%s\" - action already specified\n",
246 action
= TCA_TUNNEL_KEY_ACT_SET
;
247 } else if (matches(*argv
, "src_ip") == 0) {
249 ret
= tunnel_key_parse_ip_addr(*argv
,
250 TCA_TUNNEL_KEY_ENC_IPV4_SRC
,
251 TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
254 fprintf(stderr
, "Illegal \"src_ip\"\n");
258 } else if (matches(*argv
, "dst_ip") == 0) {
260 ret
= tunnel_key_parse_ip_addr(*argv
,
261 TCA_TUNNEL_KEY_ENC_IPV4_DST
,
262 TCA_TUNNEL_KEY_ENC_IPV6_DST
,
265 fprintf(stderr
, "Illegal \"dst_ip\"\n");
269 } else if (matches(*argv
, "id") == 0) {
271 ret
= tunnel_key_parse_key_id(*argv
, TCA_TUNNEL_KEY_ENC_KEY_ID
, n
);
273 fprintf(stderr
, "Illegal \"id\"\n");
277 } else if (matches(*argv
, "dst_port") == 0) {
279 ret
= tunnel_key_parse_dst_port(*argv
,
280 TCA_TUNNEL_KEY_ENC_DST_PORT
, n
);
282 fprintf(stderr
, "Illegal \"dst port\"\n");
285 } else if (matches(*argv
, "geneve_opts") == 0) {
288 if (tunnel_key_parse_geneve_opts(*argv
, n
)) {
289 fprintf(stderr
, "Illegal \"geneve_opts\"\n");
292 } else if (matches(*argv
, "tos") == 0) {
294 ret
= tunnel_key_parse_tos_ttl(*argv
,
295 TCA_TUNNEL_KEY_ENC_TOS
, n
);
297 fprintf(stderr
, "Illegal \"tos\"\n");
300 } else if (matches(*argv
, "ttl") == 0) {
302 ret
= tunnel_key_parse_tos_ttl(*argv
,
303 TCA_TUNNEL_KEY_ENC_TTL
, n
);
305 fprintf(stderr
, "Illegal \"ttl\"\n");
308 } else if (matches(*argv
, "csum") == 0) {
310 } else if (matches(*argv
, "nocsum") == 0) {
312 } else if (matches(*argv
, "help") == 0) {
320 addattr8(n
, MAX_MSG
, TCA_TUNNEL_KEY_NO_CSUM
, !csum
);
322 parse_action_control_dflt(&argc
, &argv
, &parm
.action
,
326 if (matches(*argv
, "index") == 0) {
328 if (get_u32(&parm
.index
, *argv
, 10)) {
329 fprintf(stderr
, "tunnel_key: Illegal \"index\"\n");
337 if (action
== TCA_TUNNEL_KEY_ACT_SET
&&
338 (!has_src_ip
|| !has_dst_ip
|| !has_key_id
)) {
339 fprintf(stderr
, "set needs tunnel_key parameters\n");
344 parm
.t_action
= action
;
345 addattr_l(n
, MAX_MSG
, TCA_TUNNEL_KEY_PARMS
, &parm
, sizeof(parm
));
346 addattr_nest_end(n
, tail
);
354 static void tunnel_key_print_ip_addr(FILE *f
, const char *name
,
363 len
= RTA_PAYLOAD(attr
);
372 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
373 if (matches(name
, "src_ip") == 0)
374 print_string(PRINT_ANY
, "src_ip", "\tsrc_ip %s",
375 rt_addr_n2a_rta(family
, attr
));
376 else if (matches(name
, "dst_ip") == 0)
377 print_string(PRINT_ANY
, "dst_ip", "\tdst_ip %s",
378 rt_addr_n2a_rta(family
, attr
));
381 static void tunnel_key_print_key_id(FILE *f
, const char *name
,
386 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
387 print_uint(PRINT_ANY
, "key_id", "\tkey_id %u", rta_getattr_be32(attr
));
390 static void tunnel_key_print_dst_port(FILE *f
, char *name
,
395 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
396 print_uint(PRINT_ANY
, "dst_port", "\tdst_port %u",
397 rta_getattr_be16(attr
));
400 static void tunnel_key_print_flag(FILE *f
, const char *name_on
,
401 const char *name_off
,
406 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
407 print_string(PRINT_ANY
, "flag", "\t%s",
408 rta_getattr_u8(attr
) ? name_on
: name_off
);
411 static void tunnel_key_print_geneve_options(const char *name
,
414 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX
+ 1];
415 struct rtattr
*i
= RTA_DATA(attr
);
416 int ii
, data_len
= 0, offset
= 0;
417 int rem
= RTA_PAYLOAD(attr
);
418 char strbuf
[rem
* 2 + 1];
419 char data
[rem
* 2 + 1];
424 open_json_array(PRINT_JSON
, name
);
425 print_string(PRINT_FP
, name
, "\n\t%s ", "geneve_opt");
428 parse_rtattr(tb
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX
, i
, rem
);
429 clss
= rta_getattr_be16(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
]);
430 type
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
]);
431 data_len
= RTA_PAYLOAD(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
]);
432 hexstring_n2a(RTA_DATA(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
]),
433 data_len
, data
, sizeof(data
));
434 hex2mem(data
, data_r
, data_len
);
435 offset
+= data_len
+ 20;
436 rem
-= data_len
+ 20;
437 i
= RTA_DATA(attr
) + offset
;
439 open_json_object(NULL
);
440 print_uint(PRINT_JSON
, "class", NULL
, clss
);
441 print_uint(PRINT_JSON
, "type", NULL
, type
);
442 open_json_array(PRINT_JSON
, "data");
443 for (ii
= 0; ii
< data_len
; ii
++)
444 print_uint(PRINT_JSON
, NULL
, NULL
, data_r
[ii
]);
445 close_json_array(PRINT_JSON
, "data");
448 sprintf(strbuf
, "%04x:%02x:%s", clss
, type
, data
);
450 print_string(PRINT_FP
, NULL
, "%s,", strbuf
);
452 print_string(PRINT_FP
, NULL
, "%s", strbuf
);
455 close_json_array(PRINT_JSON
, name
);
458 static void tunnel_key_print_key_opt(const char *name
, struct rtattr
*attr
)
460 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPTS_MAX
+ 1];
465 parse_rtattr_nested(tb
, TCA_TUNNEL_KEY_ENC_OPTS_MAX
, attr
);
466 tunnel_key_print_geneve_options(name
,
467 tb
[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
]);
470 static void tunnel_key_print_tos_ttl(FILE *f
, char *name
,
476 if (matches(name
, "tos") == 0 && rta_getattr_u8(attr
) != 0) {
477 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
478 print_uint(PRINT_ANY
, "tos", "\ttos 0x%x",
479 rta_getattr_u8(attr
));
480 } else if (matches(name
, "ttl") == 0 && rta_getattr_u8(attr
) != 0) {
481 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
482 print_uint(PRINT_ANY
, "ttl", "\tttl %u",
483 rta_getattr_u8(attr
));
487 static int print_tunnel_key(struct action_util
*au
, FILE *f
, struct rtattr
*arg
)
489 struct rtattr
*tb
[TCA_TUNNEL_KEY_MAX
+ 1];
490 struct tc_tunnel_key
*parm
;
495 parse_rtattr_nested(tb
, TCA_TUNNEL_KEY_MAX
, arg
);
497 if (!tb
[TCA_TUNNEL_KEY_PARMS
]) {
498 print_string(PRINT_FP
, NULL
, "%s",
499 "[NULL tunnel_key parameters]");
502 parm
= RTA_DATA(tb
[TCA_TUNNEL_KEY_PARMS
]);
504 print_string(PRINT_ANY
, "kind", "%s ", "tunnel_key");
506 switch (parm
->t_action
) {
507 case TCA_TUNNEL_KEY_ACT_RELEASE
:
508 print_string(PRINT_ANY
, "mode", " %s", "unset");
510 case TCA_TUNNEL_KEY_ACT_SET
:
511 print_string(PRINT_ANY
, "mode", " %s", "set");
512 tunnel_key_print_ip_addr(f
, "src_ip",
513 tb
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
]);
514 tunnel_key_print_ip_addr(f
, "dst_ip",
515 tb
[TCA_TUNNEL_KEY_ENC_IPV4_DST
]);
516 tunnel_key_print_ip_addr(f
, "src_ip",
517 tb
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
]);
518 tunnel_key_print_ip_addr(f
, "dst_ip",
519 tb
[TCA_TUNNEL_KEY_ENC_IPV6_DST
]);
520 tunnel_key_print_key_id(f
, "key_id",
521 tb
[TCA_TUNNEL_KEY_ENC_KEY_ID
]);
522 tunnel_key_print_dst_port(f
, "dst_port",
523 tb
[TCA_TUNNEL_KEY_ENC_DST_PORT
]);
524 tunnel_key_print_key_opt("geneve_opts",
525 tb
[TCA_TUNNEL_KEY_ENC_OPTS
]);
526 tunnel_key_print_flag(f
, "nocsum", "csum",
527 tb
[TCA_TUNNEL_KEY_NO_CSUM
]);
528 tunnel_key_print_tos_ttl(f
, "tos",
529 tb
[TCA_TUNNEL_KEY_ENC_TOS
]);
530 tunnel_key_print_tos_ttl(f
, "ttl",
531 tb
[TCA_TUNNEL_KEY_ENC_TTL
]);
534 print_action_control(f
, " ", parm
->action
, "");
536 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
537 print_uint(PRINT_ANY
, "index", "\t index %u", parm
->index
);
538 print_int(PRINT_ANY
, "ref", " ref %d", parm
->refcnt
);
539 print_int(PRINT_ANY
, "bind", " bind %d", parm
->bindcnt
);
542 if (tb
[TCA_TUNNEL_KEY_TM
]) {
543 struct tcf_t
*tm
= RTA_DATA(tb
[TCA_TUNNEL_KEY_TM
]);
549 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
554 struct action_util tunnel_key_action_util
= {
556 .parse_aopt
= parse_tunnel_key
,
557 .print_aopt
= print_tunnel_key
,