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