]>
Commit | Line | Data |
---|---|---|
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 | ||
22 | static 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 | ||
36 | static void usage(void) | |
37 | { | |
38 | explain(); | |
39 | exit(-1); | |
40 | } | |
41 | ||
42 | static 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 | ||
58 | static 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 |
71 | static 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 |
85 | static 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 |
100 | static 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 |
115 | static 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 |
130 | static 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 |
145 | static 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 | ||
201 | static 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 |
223 | static 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 |
244 | static 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 |
301 | static 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 |
317 | static 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 | ||
474 | static 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 | ||
501 | static 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 |
510 | static 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 |
520 | static 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 | 531 | static 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 |
579 | static 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 |
599 | static 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 | 632 | static 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 |
651 | static 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 |
668 | static 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 | ||
732 | struct action_util tunnel_key_action_util = { | |
733 | .id = "tunnel_key", | |
734 | .parse_aopt = parse_tunnel_key, | |
735 | .print_aopt = print_tunnel_key, | |
736 | }; |