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 parse_tunnel_key(struct action_util
*a
, int *argc_p
, char ***argv_p
,
194 int tca_id
, struct nlmsghdr
*n
)
196 struct tc_tunnel_key parm
= {};
197 char **argv
= *argv_p
;
207 if (matches(*argv
, "tunnel_key") != 0)
210 tail
= addattr_nest(n
, MAX_MSG
, tca_id
);
215 if (matches(*argv
, "unset") == 0) {
217 fprintf(stderr
, "unexpected \"%s\" - action already specified\n",
222 action
= TCA_TUNNEL_KEY_ACT_RELEASE
;
223 } else if (matches(*argv
, "set") == 0) {
225 fprintf(stderr
, "unexpected \"%s\" - action already specified\n",
230 action
= TCA_TUNNEL_KEY_ACT_SET
;
231 } else if (matches(*argv
, "src_ip") == 0) {
233 ret
= tunnel_key_parse_ip_addr(*argv
,
234 TCA_TUNNEL_KEY_ENC_IPV4_SRC
,
235 TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
238 fprintf(stderr
, "Illegal \"src_ip\"\n");
242 } else if (matches(*argv
, "dst_ip") == 0) {
244 ret
= tunnel_key_parse_ip_addr(*argv
,
245 TCA_TUNNEL_KEY_ENC_IPV4_DST
,
246 TCA_TUNNEL_KEY_ENC_IPV6_DST
,
249 fprintf(stderr
, "Illegal \"dst_ip\"\n");
253 } else if (matches(*argv
, "id") == 0) {
255 ret
= tunnel_key_parse_key_id(*argv
, TCA_TUNNEL_KEY_ENC_KEY_ID
, n
);
257 fprintf(stderr
, "Illegal \"id\"\n");
261 } else if (matches(*argv
, "dst_port") == 0) {
263 ret
= tunnel_key_parse_dst_port(*argv
,
264 TCA_TUNNEL_KEY_ENC_DST_PORT
, n
);
266 fprintf(stderr
, "Illegal \"dst port\"\n");
269 } else if (matches(*argv
, "geneve_opts") == 0) {
272 if (tunnel_key_parse_geneve_opts(*argv
, n
)) {
273 fprintf(stderr
, "Illegal \"geneve_opts\"\n");
276 } else if (matches(*argv
, "csum") == 0) {
278 } else if (matches(*argv
, "nocsum") == 0) {
280 } else if (matches(*argv
, "help") == 0) {
288 addattr8(n
, MAX_MSG
, TCA_TUNNEL_KEY_NO_CSUM
, !csum
);
290 parse_action_control_dflt(&argc
, &argv
, &parm
.action
,
294 if (matches(*argv
, "index") == 0) {
296 if (get_u32(&parm
.index
, *argv
, 10)) {
297 fprintf(stderr
, "tunnel_key: Illegal \"index\"\n");
305 if (action
== TCA_TUNNEL_KEY_ACT_SET
&&
306 (!has_src_ip
|| !has_dst_ip
|| !has_key_id
)) {
307 fprintf(stderr
, "set needs tunnel_key parameters\n");
312 parm
.t_action
= action
;
313 addattr_l(n
, MAX_MSG
, TCA_TUNNEL_KEY_PARMS
, &parm
, sizeof(parm
));
314 addattr_nest_end(n
, tail
);
322 static void tunnel_key_print_ip_addr(FILE *f
, const char *name
,
331 len
= RTA_PAYLOAD(attr
);
340 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
341 if (matches(name
, "src_ip") == 0)
342 print_string(PRINT_ANY
, "src_ip", "\tsrc_ip %s",
343 rt_addr_n2a_rta(family
, attr
));
344 else if (matches(name
, "dst_ip") == 0)
345 print_string(PRINT_ANY
, "dst_ip", "\tdst_ip %s",
346 rt_addr_n2a_rta(family
, attr
));
349 static void tunnel_key_print_key_id(FILE *f
, const char *name
,
354 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
355 print_uint(PRINT_ANY
, "key_id", "\tkey_id %u", rta_getattr_be32(attr
));
358 static void tunnel_key_print_dst_port(FILE *f
, char *name
,
363 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
364 print_uint(PRINT_ANY
, "dst_port", "\tdst_port %u",
365 rta_getattr_be16(attr
));
368 static void tunnel_key_print_flag(FILE *f
, const char *name_on
,
369 const char *name_off
,
374 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
375 print_string(PRINT_ANY
, "flag", "\t%s",
376 rta_getattr_u8(attr
) ? name_on
: name_off
);
379 static void tunnel_key_print_geneve_options(const char *name
,
382 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX
+ 1];
383 struct rtattr
*i
= RTA_DATA(attr
);
384 int ii
, data_len
= 0, offset
= 0;
385 int rem
= RTA_PAYLOAD(attr
);
386 char strbuf
[rem
* 2 + 1];
387 char data
[rem
* 2 + 1];
392 open_json_array(PRINT_JSON
, name
);
393 print_string(PRINT_FP
, name
, "\n\t%s ", "geneve_opt");
396 parse_rtattr(tb
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX
, i
, rem
);
397 clss
= rta_getattr_be16(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
]);
398 type
= rta_getattr_u8(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
]);
399 data_len
= RTA_PAYLOAD(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
]);
400 hexstring_n2a(RTA_DATA(tb
[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
]),
401 data_len
, data
, sizeof(data
));
402 hex2mem(data
, data_r
, data_len
);
403 offset
+= data_len
+ 20;
404 rem
-= data_len
+ 20;
405 i
= RTA_DATA(attr
) + offset
;
407 open_json_object(NULL
);
408 print_uint(PRINT_JSON
, "class", NULL
, clss
);
409 print_uint(PRINT_JSON
, "type", NULL
, type
);
410 open_json_array(PRINT_JSON
, "data");
411 for (ii
= 0; ii
< data_len
; ii
++)
412 print_uint(PRINT_JSON
, NULL
, NULL
, data_r
[ii
]);
413 close_json_array(PRINT_JSON
, "data");
416 sprintf(strbuf
, "%04x:%02x:%s", clss
, type
, data
);
418 print_string(PRINT_FP
, NULL
, "%s,", strbuf
);
420 print_string(PRINT_FP
, NULL
, "%s", strbuf
);
423 close_json_array(PRINT_JSON
, name
);
426 static void tunnel_key_print_key_opt(const char *name
, struct rtattr
*attr
)
428 struct rtattr
*tb
[TCA_TUNNEL_KEY_ENC_OPTS_MAX
+ 1];
433 parse_rtattr_nested(tb
, TCA_TUNNEL_KEY_ENC_OPTS_MAX
, attr
);
434 tunnel_key_print_geneve_options(name
,
435 tb
[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
]);
438 static int print_tunnel_key(struct action_util
*au
, FILE *f
, struct rtattr
*arg
)
440 struct rtattr
*tb
[TCA_TUNNEL_KEY_MAX
+ 1];
441 struct tc_tunnel_key
*parm
;
446 parse_rtattr_nested(tb
, TCA_TUNNEL_KEY_MAX
, arg
);
448 if (!tb
[TCA_TUNNEL_KEY_PARMS
]) {
449 print_string(PRINT_FP
, NULL
, "%s",
450 "[NULL tunnel_key parameters]");
453 parm
= RTA_DATA(tb
[TCA_TUNNEL_KEY_PARMS
]);
455 print_string(PRINT_ANY
, "kind", "%s ", "tunnel_key");
457 switch (parm
->t_action
) {
458 case TCA_TUNNEL_KEY_ACT_RELEASE
:
459 print_string(PRINT_ANY
, "mode", " %s", "unset");
461 case TCA_TUNNEL_KEY_ACT_SET
:
462 print_string(PRINT_ANY
, "mode", " %s", "set");
463 tunnel_key_print_ip_addr(f
, "src_ip",
464 tb
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
]);
465 tunnel_key_print_ip_addr(f
, "dst_ip",
466 tb
[TCA_TUNNEL_KEY_ENC_IPV4_DST
]);
467 tunnel_key_print_ip_addr(f
, "src_ip",
468 tb
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
]);
469 tunnel_key_print_ip_addr(f
, "dst_ip",
470 tb
[TCA_TUNNEL_KEY_ENC_IPV6_DST
]);
471 tunnel_key_print_key_id(f
, "key_id",
472 tb
[TCA_TUNNEL_KEY_ENC_KEY_ID
]);
473 tunnel_key_print_dst_port(f
, "dst_port",
474 tb
[TCA_TUNNEL_KEY_ENC_DST_PORT
]);
475 tunnel_key_print_key_opt("geneve_opts",
476 tb
[TCA_TUNNEL_KEY_ENC_OPTS
]);
477 tunnel_key_print_flag(f
, "nocsum", "csum",
478 tb
[TCA_TUNNEL_KEY_NO_CSUM
]);
481 print_action_control(f
, " ", parm
->action
, "");
483 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
484 print_uint(PRINT_ANY
, "index", "\t index %u", parm
->index
);
485 print_int(PRINT_ANY
, "ref", " ref %d", parm
->refcnt
);
486 print_int(PRINT_ANY
, "bind", " bind %d", parm
->bindcnt
);
489 if (tb
[TCA_TUNNEL_KEY_TM
]) {
490 struct tcf_t
*tm
= RTA_DATA(tb
[TCA_TUNNEL_KEY_TM
]);
496 print_string(PRINT_FP
, NULL
, "%s", _SL_
);
501 struct action_util tunnel_key_action_util
= {
503 .parse_aopt
= parse_tunnel_key
,
504 .print_aopt
= print_tunnel_key
,