]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/m_tunnel_key.c
vdpa: add .gitignore
[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"
668fd9b2 32 "geneve_opts | vxlan_opts | erspan_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
668fd9b2
XL
100static int tunnel_key_parse_be32(char *str, int base, int type,
101 struct nlmsghdr *n)
102{
103 __be32 value;
104 int ret;
105
106 ret = get_be32(&value, str, base);
107 if (ret)
108 return ret;
109
110 addattr32(n, MAX_MSG, type, value);
111
112 return 0;
113}
114
6217917a
SH
115static int tunnel_key_parse_u8(char *str, int base, int type,
116 struct nlmsghdr *n)
117{
118 int ret;
119 __u8 value;
120
121 ret = get_u8(&value, str, base);
122 if (ret)
123 return ret;
124
125 addattr8(n, MAX_MSG, type, value);
126
127 return 0;
128}
129
f72c3ad0
XL
130static int tunnel_key_parse_u32(char *str, int base, int type,
131 struct nlmsghdr *n)
132{
133 __u32 value;
134 int ret;
135
136 ret = get_u32(&value, str, base);
137 if (ret)
138 return ret;
139
140 addattr32(n, MAX_MSG, type, value);
141
142 return 0;
143}
144
6217917a
SH
145static int tunnel_key_parse_geneve_opt(char *str, struct nlmsghdr *n)
146{
147 char *token, *saveptr = NULL;
148 struct rtattr *nest;
149 int i, ret;
150
151 nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
152
153 token = strtok_r(str, ":", &saveptr);
154 i = 1;
155 while (token) {
156 switch (i) {
157 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS:
158 {
159 ret = tunnel_key_parse_be16(token, 16, i, n);
160 if (ret)
161 return ret;
162 break;
163 }
164 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE:
165 {
166 ret = tunnel_key_parse_u8(token, 16, i, n);
167 if (ret)
168 return ret;
169 break;
170 }
171 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA:
172 {
173 size_t token_len = strlen(token);
174 uint8_t *opts;
175
176 opts = malloc(token_len / 2);
177 if (!opts)
178 return -1;
179 if (hex2mem(token, opts, token_len / 2) < 0) {
180 free(opts);
181 return -1;
182 }
183 addattr_l(n, MAX_MSG, i, opts, token_len / 2);
184 free(opts);
185
186 break;
187 }
188 default:
189 return -1;
190 }
191
192 token = strtok_r(NULL, ":", &saveptr);
193 i++;
194 }
195
196 addattr_nest_end(n, nest);
197
198 return 0;
199}
200
201static int tunnel_key_parse_geneve_opts(char *str, struct nlmsghdr *n)
202{
203 char *token, *saveptr = NULL;
204 struct rtattr *nest;
205 int ret;
206
207 nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS);
208
209 token = strtok_r(str, ",", &saveptr);
210 while (token) {
211 ret = tunnel_key_parse_geneve_opt(token, n);
212 if (ret)
213 return ret;
214
215 token = strtok_r(NULL, ",", &saveptr);
216 }
217
218 addattr_nest_end(n, nest);
219
220 return 0;
221}
222
f72c3ad0
XL
223static int tunnel_key_parse_vxlan_opt(char *str, struct nlmsghdr *n)
224{
225 struct rtattr *encap, *nest;
226 int ret;
227
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);
232
233 ret = tunnel_key_parse_u32(str, 0,
234 TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, n);
235 if (ret)
236 return ret;
237
238 addattr_nest_end(n, nest);
239 addattr_nest_end(n, encap);
240
241 return 0;
242}
243
668fd9b2
XL
244static int tunnel_key_parse_erspan_opt(char *str, struct nlmsghdr *n)
245{
246 char *token, *saveptr = NULL;
247 struct rtattr *encap, *nest;
248 int i, ret;
249
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);
254
255 token = strtok_r(str, ":", &saveptr);
256 i = 1;
257 while (token) {
258 switch (i) {
259 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER:
260 {
261 ret = tunnel_key_parse_u8(token, 0, i, n);
262 if (ret)
263 return ret;
264 break;
265 }
266 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX:
267 {
268 ret = tunnel_key_parse_be32(token, 0, i, n);
269 if (ret)
270 return ret;
271 break;
272 }
273 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR:
274 {
275 ret = tunnel_key_parse_u8(token, 0, i, n);
276 if (ret)
277 return ret;
278 break;
279 }
280 case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID:
281 {
282 ret = tunnel_key_parse_u8(token, 0, i, n);
283 if (ret)
284 return ret;
285 break;
286 }
287 default:
288 return -1;
289 }
290
291 token = strtok_r(NULL, ":", &saveptr);
292 i++;
293 }
294
295 addattr_nest_end(n, nest);
296 addattr_nest_end(n, encap);
297
298 return 0;
299}
300
9f89b0cc
OG
301static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n)
302{
303 int ret;
304 __u8 val;
305
306 ret = get_u8(&val, str, 10);
307 if (ret)
308 ret = get_u8(&val, str, 16);
309 if (ret)
310 return -1;
311
312 addattr8(n, MAX_MSG, type, val);
313
314 return 0;
315}
316
d57639a4
AV
317static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
318 int tca_id, struct nlmsghdr *n)
319{
e67aba55 320 struct tc_tunnel_key parm = {};
d57639a4
AV
321 char **argv = *argv_p;
322 int argc = *argc_p;
323 struct rtattr *tail;
324 int action = 0;
325 int ret;
326 int has_src_ip = 0;
327 int has_dst_ip = 0;
59eb271d 328 int csum = 1;
d57639a4
AV
329
330 if (matches(*argv, "tunnel_key") != 0)
331 return -1;
332
c14f9d92 333 tail = addattr_nest(n, MAX_MSG, tca_id);
d57639a4
AV
334
335 NEXT_ARG();
336
337 while (argc > 0) {
338 if (matches(*argv, "unset") == 0) {
339 if (action) {
340 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
341 *argv);
342 explain();
343 return -1;
344 }
345 action = TCA_TUNNEL_KEY_ACT_RELEASE;
346 } else if (matches(*argv, "set") == 0) {
347 if (action) {
348 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
349 *argv);
350 explain();
351 return -1;
352 }
353 action = TCA_TUNNEL_KEY_ACT_SET;
354 } else if (matches(*argv, "src_ip") == 0) {
355 NEXT_ARG();
356 ret = tunnel_key_parse_ip_addr(*argv,
357 TCA_TUNNEL_KEY_ENC_IPV4_SRC,
358 TCA_TUNNEL_KEY_ENC_IPV6_SRC,
359 n);
360 if (ret < 0) {
361 fprintf(stderr, "Illegal \"src_ip\"\n");
362 return -1;
363 }
364 has_src_ip = 1;
365 } else if (matches(*argv, "dst_ip") == 0) {
366 NEXT_ARG();
367 ret = tunnel_key_parse_ip_addr(*argv,
368 TCA_TUNNEL_KEY_ENC_IPV4_DST,
369 TCA_TUNNEL_KEY_ENC_IPV6_DST,
370 n);
371 if (ret < 0) {
372 fprintf(stderr, "Illegal \"dst_ip\"\n");
373 return -1;
374 }
375 has_dst_ip = 1;
376 } else if (matches(*argv, "id") == 0) {
377 NEXT_ARG();
378 ret = tunnel_key_parse_key_id(*argv, TCA_TUNNEL_KEY_ENC_KEY_ID, n);
379 if (ret < 0) {
380 fprintf(stderr, "Illegal \"id\"\n");
381 return -1;
382 }
449c709c
HHZ
383 } else if (matches(*argv, "dst_port") == 0) {
384 NEXT_ARG();
385 ret = tunnel_key_parse_dst_port(*argv,
386 TCA_TUNNEL_KEY_ENC_DST_PORT, n);
387 if (ret < 0) {
388 fprintf(stderr, "Illegal \"dst port\"\n");
389 return -1;
390 }
6217917a
SH
391 } else if (matches(*argv, "geneve_opts") == 0) {
392 NEXT_ARG();
393
394 if (tunnel_key_parse_geneve_opts(*argv, n)) {
395 fprintf(stderr, "Illegal \"geneve_opts\"\n");
396 return -1;
397 }
f72c3ad0
XL
398 } else if (matches(*argv, "vxlan_opts") == 0) {
399 NEXT_ARG();
400
401 if (tunnel_key_parse_vxlan_opt(*argv, n)) {
402 fprintf(stderr, "Illegal \"vxlan_opts\"\n");
403 return -1;
404 }
668fd9b2
XL
405 } else if (matches(*argv, "erspan_opts") == 0) {
406 NEXT_ARG();
407
408 if (tunnel_key_parse_erspan_opt(*argv, n)) {
409 fprintf(stderr, "Illegal \"erspan_opts\"\n");
410 return -1;
411 }
9f89b0cc
OG
412 } else if (matches(*argv, "tos") == 0) {
413 NEXT_ARG();
414 ret = tunnel_key_parse_tos_ttl(*argv,
415 TCA_TUNNEL_KEY_ENC_TOS, n);
416 if (ret < 0) {
417 fprintf(stderr, "Illegal \"tos\"\n");
418 return -1;
419 }
420 } else if (matches(*argv, "ttl") == 0) {
421 NEXT_ARG();
422 ret = tunnel_key_parse_tos_ttl(*argv,
423 TCA_TUNNEL_KEY_ENC_TTL, n);
424 if (ret < 0) {
425 fprintf(stderr, "Illegal \"ttl\"\n");
426 return -1;
427 }
59eb271d
JB
428 } else if (matches(*argv, "csum") == 0) {
429 csum = 1;
430 } else if (matches(*argv, "nocsum") == 0) {
431 csum = 0;
d57639a4
AV
432 } else if (matches(*argv, "help") == 0) {
433 usage();
434 } else {
435 break;
436 }
437 NEXT_ARG_FWD();
438 }
439
59eb271d
JB
440 addattr8(n, MAX_MSG, TCA_TUNNEL_KEY_NO_CSUM, !csum);
441
e67aba55
JP
442 parse_action_control_dflt(&argc, &argv, &parm.action,
443 false, TC_ACT_PIPE);
d57639a4
AV
444
445 if (argc) {
446 if (matches(*argv, "index") == 0) {
447 NEXT_ARG();
448 if (get_u32(&parm.index, *argv, 10)) {
449 fprintf(stderr, "tunnel_key: Illegal \"index\"\n");
450 return -1;
451 }
452
453 NEXT_ARG_FWD();
454 }
455 }
456
457 if (action == TCA_TUNNEL_KEY_ACT_SET &&
dc0332b1 458 (!has_src_ip || !has_dst_ip)) {
d57639a4
AV
459 fprintf(stderr, "set needs tunnel_key parameters\n");
460 explain();
461 return -1;
462 }
463
464 parm.t_action = action;
465 addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm));
c14f9d92 466 addattr_nest_end(n, tail);
d57639a4
AV
467
468 *argc_p = argc;
469 *argv_p = argv;
470
471 return 0;
472}
473
474static void tunnel_key_print_ip_addr(FILE *f, const char *name,
475 struct rtattr *attr)
476{
477 int family;
478 size_t len;
479
480 if (!attr)
481 return;
482
483 len = RTA_PAYLOAD(attr);
484
485 if (len == 4)
486 family = AF_INET;
487 else if (len == 16)
488 family = AF_INET6;
489 else
490 return;
491
0501fe73 492 print_nl();
8feb516b
RM
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));
d57639a4
AV
499}
500
501static void tunnel_key_print_key_id(FILE *f, const char *name,
502 struct rtattr *attr)
503{
504 if (!attr)
505 return;
0501fe73 506 print_nl();
8feb516b 507 print_uint(PRINT_ANY, "key_id", "\tkey_id %u", rta_getattr_be32(attr));
d57639a4
AV
508}
509
449c709c
HHZ
510static void tunnel_key_print_dst_port(FILE *f, char *name,
511 struct rtattr *attr)
512{
513 if (!attr)
514 return;
0501fe73 515 print_nl();
8feb516b
RM
516 print_uint(PRINT_ANY, "dst_port", "\tdst_port %u",
517 rta_getattr_be16(attr));
449c709c
HHZ
518}
519
59eb271d
JB
520static void tunnel_key_print_flag(FILE *f, const char *name_on,
521 const char *name_off,
522 struct rtattr *attr)
523{
524 if (!attr)
525 return;
0501fe73 526 print_nl();
8feb516b
RM
527 print_string(PRINT_ANY, "flag", "\t%s",
528 rta_getattr_u8(attr) ? name_on : name_off);
59eb271d
JB
529}
530
f72c3ad0 531static void tunnel_key_print_geneve_options(struct rtattr *attr)
6217917a
SH
532{
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);
f72c3ad0 537 char *name = "geneve_opts";
6217917a
SH
538 char strbuf[rem * 2 + 1];
539 char data[rem * 2 + 1];
540 uint8_t data_r[rem];
541 uint16_t clss;
542 uint8_t type;
543
544 open_json_array(PRINT_JSON, name);
7b0d424a 545 print_nl();
f72c3ad0 546 print_string(PRINT_FP, name, "\t%s ", name);
6217917a
SH
547
548 while (rem) {
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;
559
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");
567 close_json_object();
568
569 sprintf(strbuf, "%04x:%02x:%s", clss, type, data);
570 if (rem)
571 print_string(PRINT_FP, NULL, "%s,", strbuf);
572 else
573 print_string(PRINT_FP, NULL, "%s", strbuf);
574 }
575
576 close_json_array(PRINT_JSON, name);
577}
578
f72c3ad0
XL
579static void tunnel_key_print_vxlan_options(struct rtattr *attr)
580{
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";
585 __u32 gbp;
586
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]);
589
590 print_nl();
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);
595 close_json_object();
596 close_json_array(PRINT_JSON, name);
597}
598
668fd9b2
XL
599static void tunnel_key_print_erspan_options(struct rtattr *attr)
600{
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";
605 __u8 ver, hwid, dir;
606 __u32 idx;
607
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]);
610 if (ver == 1) {
611 idx = rta_getattr_be32(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]);
612 dir = 0;
613 hwid = 0;
614 } else {
615 idx = 0;
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]);
618 }
619
620 print_nl();
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);
628 close_json_object();
629 close_json_array(PRINT_JSON, name);
630}
631
f72c3ad0 632static void tunnel_key_print_key_opt(struct rtattr *attr)
6217917a
SH
633{
634 struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
635
636 if (!attr)
637 return;
638
639 parse_rtattr_nested(tb, TCA_TUNNEL_KEY_ENC_OPTS_MAX, attr);
f72c3ad0
XL
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]);
668fd9b2
XL
646 else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN])
647 tunnel_key_print_erspan_options(
648 tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN]);
6217917a
SH
649}
650
9f89b0cc
OG
651static void tunnel_key_print_tos_ttl(FILE *f, char *name,
652 struct rtattr *attr)
653{
654 if (!attr)
655 return;
656
657 if (matches(name, "tos") == 0 && rta_getattr_u8(attr) != 0) {
0501fe73 658 print_nl();
9f89b0cc
OG
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) {
0501fe73 662 print_nl();
9f89b0cc
OG
663 print_uint(PRINT_ANY, "ttl", "\tttl %u",
664 rta_getattr_u8(attr));
665 }
666}
667
d57639a4
AV
668static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
669{
670 struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1];
671 struct tc_tunnel_key *parm;
672
a99ebeee 673 print_string(PRINT_ANY, "kind", "%s ", "tunnel_key");
d57639a4 674 if (!arg)
a99ebeee 675 return 0;
d57639a4
AV
676
677 parse_rtattr_nested(tb, TCA_TUNNEL_KEY_MAX, arg);
678
679 if (!tb[TCA_TUNNEL_KEY_PARMS]) {
d5ddb441 680 fprintf(stderr, "Missing tunnel_key parameters\n");
d57639a4
AV
681 return -1;
682 }
683 parm = RTA_DATA(tb[TCA_TUNNEL_KEY_PARMS]);
684
d57639a4
AV
685 switch (parm->t_action) {
686 case TCA_TUNNEL_KEY_ACT_RELEASE:
8feb516b 687 print_string(PRINT_ANY, "mode", " %s", "unset");
d57639a4
AV
688 break;
689 case TCA_TUNNEL_KEY_ACT_SET:
8feb516b 690 print_string(PRINT_ANY, "mode", " %s", "set");
d57639a4
AV
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]);
449c709c
HHZ
701 tunnel_key_print_dst_port(f, "dst_port",
702 tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
f72c3ad0 703 tunnel_key_print_key_opt(tb[TCA_TUNNEL_KEY_ENC_OPTS]);
59eb271d
JB
704 tunnel_key_print_flag(f, "nocsum", "csum",
705 tb[TCA_TUNNEL_KEY_NO_CSUM]);
9f89b0cc
OG
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]);
d57639a4
AV
710 break;
711 }
e67aba55 712 print_action_control(f, " ", parm->action, "");
d57639a4 713
0501fe73 714 print_nl();
8feb516b
RM
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);
d57639a4
AV
718
719 if (show_stats) {
720 if (tb[TCA_TUNNEL_KEY_TM]) {
721 struct tcf_t *tm = RTA_DATA(tb[TCA_TUNNEL_KEY_TM]);
722
723 print_tm(f, tm);
724 }
725 }
726
0501fe73 727 print_nl();
d57639a4
AV
728
729 return 0;
730}
731
732struct action_util tunnel_key_action_util = {
733 .id = "tunnel_key",
734 .parse_aopt = parse_tunnel_key,
735 .print_aopt = print_tunnel_key,
736};