]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/m_tunnel_key.c
tc: m_tunnel_key: add options support for vxlan
[mirror_iproute2.git] / tc / m_tunnel_key.c
CommitLineData
d57639a4
AV
1/*
2 * m_tunnel_key.c ip tunnel manipulation module
3 *
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.
8 *
9 * Authors: Amir Vadai <amir@vadai.me>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <string.h>
16#include <linux/if_ether.h>
17#include "utils.h"
18#include "rt_names.h"
19#include "tc_util.h"
20#include <linux/tc_act/tc_tunnel_key.h>
21
22static void explain(void)
23{
50907a82 24 fprintf(stderr,
8589eb4e
MC
25 "Usage: tunnel_key unset\n"
26 " tunnel_key set <TUNNEL_KEY>\n"
50907a82 27 "Where TUNNEL_KEY is a combination of:\n"
dc0332b1 28 "id <TUNNELID>\n"
50907a82
JB
29 "src_ip <IP> (mandatory)\n"
30 "dst_ip <IP> (mandatory)\n"
59eb271d 31 "dst_port <UDP_PORT>\n"
f72c3ad0 32 "geneve_opts | vxlan_opts <OPTIONS>\n"
59eb271d 33 "csum | nocsum (default is \"csum\")\n");
d57639a4
AV
34}
35
36static void usage(void)
37{
38 explain();
39 exit(-1);
40}
41
42static int tunnel_key_parse_ip_addr(const char *str, int addr4_type,
43 int addr6_type, struct nlmsghdr *n)
44{
45 inet_prefix addr;
46 int ret;
47
48 ret = get_addr(&addr, str, AF_UNSPEC);
49 if (ret)
50 return ret;
51
52 addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type,
53 addr.data, addr.bytelen);
54
55 return 0;
56}
57
58static int tunnel_key_parse_key_id(const char *str, int type,
59 struct nlmsghdr *n)
60{
61 __be32 key_id;
62 int ret;
63
64 ret = get_be32(&key_id, str, 10);
65 if (!ret)
66 addattr32(n, MAX_MSG, type, key_id);
67
68 return ret;
69}
70
449c709c
HHZ
71static int tunnel_key_parse_dst_port(char *str, int type, struct nlmsghdr *n)
72{
73 int ret;
74 __be16 dst_port;
75
76 ret = get_be16(&dst_port, str, 10);
77 if (ret)
78 return -1;
79
80 addattr16(n, MAX_MSG, type, dst_port);
81
82 return 0;
83}
84
6217917a
SH
85static int tunnel_key_parse_be16(char *str, int base, int type,
86 struct nlmsghdr *n)
87{
88 int ret;
89 __be16 value;
90
91 ret = get_be16(&value, str, base);
92 if (ret)
93 return ret;
94
95 addattr16(n, MAX_MSG, type, value);
96
97 return 0;
98}
99
100static int tunnel_key_parse_u8(char *str, int base, int type,
101 struct nlmsghdr *n)
102{
103 int ret;
104 __u8 value;
105
106 ret = get_u8(&value, str, base);
107 if (ret)
108 return ret;
109
110 addattr8(n, MAX_MSG, type, value);
111
112 return 0;
113}
114
f72c3ad0
XL
115static int tunnel_key_parse_u32(char *str, int base, int type,
116 struct nlmsghdr *n)
117{
118 __u32 value;
119 int ret;
120
121 ret = get_u32(&value, str, base);
122 if (ret)
123 return ret;
124
125 addattr32(n, MAX_MSG, type, value);
126
127 return 0;
128}
129
6217917a
SH
130static int tunnel_key_parse_geneve_opt(char *str, struct nlmsghdr *n)
131{
132 char *token, *saveptr = NULL;
133 struct rtattr *nest;
134 int i, ret;
135
136 nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
137
138 token = strtok_r(str, ":", &saveptr);
139 i = 1;
140 while (token) {
141 switch (i) {
142 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS:
143 {
144 ret = tunnel_key_parse_be16(token, 16, i, n);
145 if (ret)
146 return ret;
147 break;
148 }
149 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE:
150 {
151 ret = tunnel_key_parse_u8(token, 16, i, n);
152 if (ret)
153 return ret;
154 break;
155 }
156 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA:
157 {
158 size_t token_len = strlen(token);
159 uint8_t *opts;
160
161 opts = malloc(token_len / 2);
162 if (!opts)
163 return -1;
164 if (hex2mem(token, opts, token_len / 2) < 0) {
165 free(opts);
166 return -1;
167 }
168 addattr_l(n, MAX_MSG, i, opts, token_len / 2);
169 free(opts);
170
171 break;
172 }
173 default:
174 return -1;
175 }
176
177 token = strtok_r(NULL, ":", &saveptr);
178 i++;
179 }
180
181 addattr_nest_end(n, nest);
182
183 return 0;
184}
185
186static int tunnel_key_parse_geneve_opts(char *str, struct nlmsghdr *n)
187{
188 char *token, *saveptr = NULL;
189 struct rtattr *nest;
190 int ret;
191
192 nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS);
193
194 token = strtok_r(str, ",", &saveptr);
195 while (token) {
196 ret = tunnel_key_parse_geneve_opt(token, n);
197 if (ret)
198 return ret;
199
200 token = strtok_r(NULL, ",", &saveptr);
201 }
202
203 addattr_nest_end(n, nest);
204
205 return 0;
206}
207
f72c3ad0
XL
208static int tunnel_key_parse_vxlan_opt(char *str, struct nlmsghdr *n)
209{
210 struct rtattr *encap, *nest;
211 int ret;
212
213 encap = addattr_nest(n, MAX_MSG,
214 TCA_TUNNEL_KEY_ENC_OPTS | NLA_F_NESTED);
215 nest = addattr_nest(n, MAX_MSG,
216 TCA_TUNNEL_KEY_ENC_OPTS_VXLAN | NLA_F_NESTED);
217
218 ret = tunnel_key_parse_u32(str, 0,
219 TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, n);
220 if (ret)
221 return ret;
222
223 addattr_nest_end(n, nest);
224 addattr_nest_end(n, encap);
225
226 return 0;
227}
228
9f89b0cc
OG
229static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n)
230{
231 int ret;
232 __u8 val;
233
234 ret = get_u8(&val, str, 10);
235 if (ret)
236 ret = get_u8(&val, str, 16);
237 if (ret)
238 return -1;
239
240 addattr8(n, MAX_MSG, type, val);
241
242 return 0;
243}
244
d57639a4
AV
245static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
246 int tca_id, struct nlmsghdr *n)
247{
e67aba55 248 struct tc_tunnel_key parm = {};
d57639a4
AV
249 char **argv = *argv_p;
250 int argc = *argc_p;
251 struct rtattr *tail;
252 int action = 0;
253 int ret;
254 int has_src_ip = 0;
255 int has_dst_ip = 0;
59eb271d 256 int csum = 1;
d57639a4
AV
257
258 if (matches(*argv, "tunnel_key") != 0)
259 return -1;
260
c14f9d92 261 tail = addattr_nest(n, MAX_MSG, tca_id);
d57639a4
AV
262
263 NEXT_ARG();
264
265 while (argc > 0) {
266 if (matches(*argv, "unset") == 0) {
267 if (action) {
268 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
269 *argv);
270 explain();
271 return -1;
272 }
273 action = TCA_TUNNEL_KEY_ACT_RELEASE;
274 } else if (matches(*argv, "set") == 0) {
275 if (action) {
276 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
277 *argv);
278 explain();
279 return -1;
280 }
281 action = TCA_TUNNEL_KEY_ACT_SET;
282 } else if (matches(*argv, "src_ip") == 0) {
283 NEXT_ARG();
284 ret = tunnel_key_parse_ip_addr(*argv,
285 TCA_TUNNEL_KEY_ENC_IPV4_SRC,
286 TCA_TUNNEL_KEY_ENC_IPV6_SRC,
287 n);
288 if (ret < 0) {
289 fprintf(stderr, "Illegal \"src_ip\"\n");
290 return -1;
291 }
292 has_src_ip = 1;
293 } else if (matches(*argv, "dst_ip") == 0) {
294 NEXT_ARG();
295 ret = tunnel_key_parse_ip_addr(*argv,
296 TCA_TUNNEL_KEY_ENC_IPV4_DST,
297 TCA_TUNNEL_KEY_ENC_IPV6_DST,
298 n);
299 if (ret < 0) {
300 fprintf(stderr, "Illegal \"dst_ip\"\n");
301 return -1;
302 }
303 has_dst_ip = 1;
304 } else if (matches(*argv, "id") == 0) {
305 NEXT_ARG();
306 ret = tunnel_key_parse_key_id(*argv, TCA_TUNNEL_KEY_ENC_KEY_ID, n);
307 if (ret < 0) {
308 fprintf(stderr, "Illegal \"id\"\n");
309 return -1;
310 }
449c709c
HHZ
311 } else if (matches(*argv, "dst_port") == 0) {
312 NEXT_ARG();
313 ret = tunnel_key_parse_dst_port(*argv,
314 TCA_TUNNEL_KEY_ENC_DST_PORT, n);
315 if (ret < 0) {
316 fprintf(stderr, "Illegal \"dst port\"\n");
317 return -1;
318 }
6217917a
SH
319 } else if (matches(*argv, "geneve_opts") == 0) {
320 NEXT_ARG();
321
322 if (tunnel_key_parse_geneve_opts(*argv, n)) {
323 fprintf(stderr, "Illegal \"geneve_opts\"\n");
324 return -1;
325 }
f72c3ad0
XL
326 } else if (matches(*argv, "vxlan_opts") == 0) {
327 NEXT_ARG();
328
329 if (tunnel_key_parse_vxlan_opt(*argv, n)) {
330 fprintf(stderr, "Illegal \"vxlan_opts\"\n");
331 return -1;
332 }
9f89b0cc
OG
333 } else if (matches(*argv, "tos") == 0) {
334 NEXT_ARG();
335 ret = tunnel_key_parse_tos_ttl(*argv,
336 TCA_TUNNEL_KEY_ENC_TOS, n);
337 if (ret < 0) {
338 fprintf(stderr, "Illegal \"tos\"\n");
339 return -1;
340 }
341 } else if (matches(*argv, "ttl") == 0) {
342 NEXT_ARG();
343 ret = tunnel_key_parse_tos_ttl(*argv,
344 TCA_TUNNEL_KEY_ENC_TTL, n);
345 if (ret < 0) {
346 fprintf(stderr, "Illegal \"ttl\"\n");
347 return -1;
348 }
59eb271d
JB
349 } else if (matches(*argv, "csum") == 0) {
350 csum = 1;
351 } else if (matches(*argv, "nocsum") == 0) {
352 csum = 0;
d57639a4
AV
353 } else if (matches(*argv, "help") == 0) {
354 usage();
355 } else {
356 break;
357 }
358 NEXT_ARG_FWD();
359 }
360
59eb271d
JB
361 addattr8(n, MAX_MSG, TCA_TUNNEL_KEY_NO_CSUM, !csum);
362
e67aba55
JP
363 parse_action_control_dflt(&argc, &argv, &parm.action,
364 false, TC_ACT_PIPE);
d57639a4
AV
365
366 if (argc) {
367 if (matches(*argv, "index") == 0) {
368 NEXT_ARG();
369 if (get_u32(&parm.index, *argv, 10)) {
370 fprintf(stderr, "tunnel_key: Illegal \"index\"\n");
371 return -1;
372 }
373
374 NEXT_ARG_FWD();
375 }
376 }
377
378 if (action == TCA_TUNNEL_KEY_ACT_SET &&
dc0332b1 379 (!has_src_ip || !has_dst_ip)) {
d57639a4
AV
380 fprintf(stderr, "set needs tunnel_key parameters\n");
381 explain();
382 return -1;
383 }
384
385 parm.t_action = action;
386 addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm));
c14f9d92 387 addattr_nest_end(n, tail);
d57639a4
AV
388
389 *argc_p = argc;
390 *argv_p = argv;
391
392 return 0;
393}
394
395static void tunnel_key_print_ip_addr(FILE *f, const char *name,
396 struct rtattr *attr)
397{
398 int family;
399 size_t len;
400
401 if (!attr)
402 return;
403
404 len = RTA_PAYLOAD(attr);
405
406 if (len == 4)
407 family = AF_INET;
408 else if (len == 16)
409 family = AF_INET6;
410 else
411 return;
412
8feb516b
RM
413 print_string(PRINT_FP, NULL, "%s", _SL_);
414 if (matches(name, "src_ip") == 0)
415 print_string(PRINT_ANY, "src_ip", "\tsrc_ip %s",
416 rt_addr_n2a_rta(family, attr));
417 else if (matches(name, "dst_ip") == 0)
418 print_string(PRINT_ANY, "dst_ip", "\tdst_ip %s",
419 rt_addr_n2a_rta(family, attr));
d57639a4
AV
420}
421
422static void tunnel_key_print_key_id(FILE *f, const char *name,
423 struct rtattr *attr)
424{
425 if (!attr)
426 return;
8feb516b
RM
427 print_string(PRINT_FP, NULL, "%s", _SL_);
428 print_uint(PRINT_ANY, "key_id", "\tkey_id %u", rta_getattr_be32(attr));
d57639a4
AV
429}
430
449c709c
HHZ
431static void tunnel_key_print_dst_port(FILE *f, char *name,
432 struct rtattr *attr)
433{
434 if (!attr)
435 return;
8feb516b
RM
436 print_string(PRINT_FP, NULL, "%s", _SL_);
437 print_uint(PRINT_ANY, "dst_port", "\tdst_port %u",
438 rta_getattr_be16(attr));
449c709c
HHZ
439}
440
59eb271d
JB
441static void tunnel_key_print_flag(FILE *f, const char *name_on,
442 const char *name_off,
443 struct rtattr *attr)
444{
445 if (!attr)
446 return;
8feb516b
RM
447 print_string(PRINT_FP, NULL, "%s", _SL_);
448 print_string(PRINT_ANY, "flag", "\t%s",
449 rta_getattr_u8(attr) ? name_on : name_off);
59eb271d
JB
450}
451
f72c3ad0 452static void tunnel_key_print_geneve_options(struct rtattr *attr)
6217917a
SH
453{
454 struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1];
455 struct rtattr *i = RTA_DATA(attr);
456 int ii, data_len = 0, offset = 0;
457 int rem = RTA_PAYLOAD(attr);
f72c3ad0 458 char *name = "geneve_opts";
6217917a
SH
459 char strbuf[rem * 2 + 1];
460 char data[rem * 2 + 1];
461 uint8_t data_r[rem];
462 uint16_t clss;
463 uint8_t type;
464
465 open_json_array(PRINT_JSON, name);
7b0d424a 466 print_nl();
f72c3ad0 467 print_string(PRINT_FP, name, "\t%s ", name);
6217917a
SH
468
469 while (rem) {
470 parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, i, rem);
471 clss = rta_getattr_be16(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS]);
472 type = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE]);
473 data_len = RTA_PAYLOAD(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]);
474 hexstring_n2a(RTA_DATA(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]),
475 data_len, data, sizeof(data));
476 hex2mem(data, data_r, data_len);
477 offset += data_len + 20;
478 rem -= data_len + 20;
479 i = RTA_DATA(attr) + offset;
480
481 open_json_object(NULL);
482 print_uint(PRINT_JSON, "class", NULL, clss);
483 print_uint(PRINT_JSON, "type", NULL, type);
484 open_json_array(PRINT_JSON, "data");
485 for (ii = 0; ii < data_len; ii++)
486 print_uint(PRINT_JSON, NULL, NULL, data_r[ii]);
487 close_json_array(PRINT_JSON, "data");
488 close_json_object();
489
490 sprintf(strbuf, "%04x:%02x:%s", clss, type, data);
491 if (rem)
492 print_string(PRINT_FP, NULL, "%s,", strbuf);
493 else
494 print_string(PRINT_FP, NULL, "%s", strbuf);
495 }
496
497 close_json_array(PRINT_JSON, name);
498}
499
f72c3ad0
XL
500static void tunnel_key_print_vxlan_options(struct rtattr *attr)
501{
502 struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1];
503 struct rtattr *i = RTA_DATA(attr);
504 int rem = RTA_PAYLOAD(attr);
505 char *name = "vxlan_opts";
506 __u32 gbp;
507
508 parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, i, rem);
509 gbp = rta_getattr_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]);
510
511 print_nl();
512 print_string(PRINT_FP, name, "\t%s ", name);
513 open_json_array(PRINT_JSON, name);
514 open_json_object(NULL);
515 print_uint(PRINT_ANY, "gbp", "%u", gbp);
516 close_json_object();
517 close_json_array(PRINT_JSON, name);
518}
519
520static void tunnel_key_print_key_opt(struct rtattr *attr)
6217917a
SH
521{
522 struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
523
524 if (!attr)
525 return;
526
527 parse_rtattr_nested(tb, TCA_TUNNEL_KEY_ENC_OPTS_MAX, attr);
f72c3ad0
XL
528 if (tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE])
529 tunnel_key_print_geneve_options(
530 tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]);
531 else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN])
532 tunnel_key_print_vxlan_options(
533 tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]);
6217917a
SH
534}
535
9f89b0cc
OG
536static void tunnel_key_print_tos_ttl(FILE *f, char *name,
537 struct rtattr *attr)
538{
539 if (!attr)
540 return;
541
542 if (matches(name, "tos") == 0 && rta_getattr_u8(attr) != 0) {
543 print_string(PRINT_FP, NULL, "%s", _SL_);
544 print_uint(PRINT_ANY, "tos", "\ttos 0x%x",
545 rta_getattr_u8(attr));
546 } else if (matches(name, "ttl") == 0 && rta_getattr_u8(attr) != 0) {
547 print_string(PRINT_FP, NULL, "%s", _SL_);
548 print_uint(PRINT_ANY, "ttl", "\tttl %u",
549 rta_getattr_u8(attr));
550 }
551}
552
d57639a4
AV
553static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
554{
555 struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1];
556 struct tc_tunnel_key *parm;
557
558 if (!arg)
559 return -1;
560
561 parse_rtattr_nested(tb, TCA_TUNNEL_KEY_MAX, arg);
562
563 if (!tb[TCA_TUNNEL_KEY_PARMS]) {
d5ddb441 564 fprintf(stderr, "Missing tunnel_key parameters\n");
d57639a4
AV
565 return -1;
566 }
567 parm = RTA_DATA(tb[TCA_TUNNEL_KEY_PARMS]);
568
8feb516b 569 print_string(PRINT_ANY, "kind", "%s ", "tunnel_key");
d57639a4
AV
570
571 switch (parm->t_action) {
572 case TCA_TUNNEL_KEY_ACT_RELEASE:
8feb516b 573 print_string(PRINT_ANY, "mode", " %s", "unset");
d57639a4
AV
574 break;
575 case TCA_TUNNEL_KEY_ACT_SET:
8feb516b 576 print_string(PRINT_ANY, "mode", " %s", "set");
d57639a4
AV
577 tunnel_key_print_ip_addr(f, "src_ip",
578 tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]);
579 tunnel_key_print_ip_addr(f, "dst_ip",
580 tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]);
581 tunnel_key_print_ip_addr(f, "src_ip",
582 tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]);
583 tunnel_key_print_ip_addr(f, "dst_ip",
584 tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]);
585 tunnel_key_print_key_id(f, "key_id",
586 tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
449c709c
HHZ
587 tunnel_key_print_dst_port(f, "dst_port",
588 tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
f72c3ad0 589 tunnel_key_print_key_opt(tb[TCA_TUNNEL_KEY_ENC_OPTS]);
59eb271d
JB
590 tunnel_key_print_flag(f, "nocsum", "csum",
591 tb[TCA_TUNNEL_KEY_NO_CSUM]);
9f89b0cc
OG
592 tunnel_key_print_tos_ttl(f, "tos",
593 tb[TCA_TUNNEL_KEY_ENC_TOS]);
594 tunnel_key_print_tos_ttl(f, "ttl",
595 tb[TCA_TUNNEL_KEY_ENC_TTL]);
d57639a4
AV
596 break;
597 }
e67aba55 598 print_action_control(f, " ", parm->action, "");
d57639a4 599
8feb516b
RM
600 print_string(PRINT_FP, NULL, "%s", _SL_);
601 print_uint(PRINT_ANY, "index", "\t index %u", parm->index);
602 print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt);
603 print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt);
d57639a4
AV
604
605 if (show_stats) {
606 if (tb[TCA_TUNNEL_KEY_TM]) {
607 struct tcf_t *tm = RTA_DATA(tb[TCA_TUNNEL_KEY_TM]);
608
609 print_tm(f, tm);
610 }
611 }
612
8feb516b 613 print_string(PRINT_FP, NULL, "%s", _SL_);
d57639a4
AV
614
615 return 0;
616}
617
618struct action_util tunnel_key_action_util = {
619 .id = "tunnel_key",
620 .parse_aopt = parse_tunnel_key,
621 .print_aopt = print_tunnel_key,
622};