]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/m_tunnel_key.c
tc: m_tunnel_key: Add tunnel option support to act_tunnel_key
[mirror_iproute2.git] / tc / m_tunnel_key.c
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 {
24 fprintf(stderr, "Usage: tunnel_key unset\n");
25 fprintf(stderr, " tunnel_key set <TUNNEL_KEY>\n");
26 fprintf(stderr,
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");
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
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
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
100 static 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
115 static int tunnel_key_parse_geneve_opt(char *str, struct nlmsghdr *n)
116 {
117 char *token, *saveptr = NULL;
118 struct rtattr *nest;
119 int i, ret;
120
121 nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
122
123 token = strtok_r(str, ":", &saveptr);
124 i = 1;
125 while (token) {
126 switch (i) {
127 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS:
128 {
129 ret = tunnel_key_parse_be16(token, 16, i, n);
130 if (ret)
131 return ret;
132 break;
133 }
134 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE:
135 {
136 ret = tunnel_key_parse_u8(token, 16, i, n);
137 if (ret)
138 return ret;
139 break;
140 }
141 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA:
142 {
143 size_t token_len = strlen(token);
144 uint8_t *opts;
145
146 opts = malloc(token_len / 2);
147 if (!opts)
148 return -1;
149 if (hex2mem(token, opts, token_len / 2) < 0) {
150 free(opts);
151 return -1;
152 }
153 addattr_l(n, MAX_MSG, i, opts, token_len / 2);
154 free(opts);
155
156 break;
157 }
158 default:
159 return -1;
160 }
161
162 token = strtok_r(NULL, ":", &saveptr);
163 i++;
164 }
165
166 addattr_nest_end(n, nest);
167
168 return 0;
169 }
170
171 static int tunnel_key_parse_geneve_opts(char *str, struct nlmsghdr *n)
172 {
173 char *token, *saveptr = NULL;
174 struct rtattr *nest;
175 int ret;
176
177 nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS);
178
179 token = strtok_r(str, ",", &saveptr);
180 while (token) {
181 ret = tunnel_key_parse_geneve_opt(token, n);
182 if (ret)
183 return ret;
184
185 token = strtok_r(NULL, ",", &saveptr);
186 }
187
188 addattr_nest_end(n, nest);
189
190 return 0;
191 }
192
193 static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
194 int tca_id, struct nlmsghdr *n)
195 {
196 struct tc_tunnel_key parm = {};
197 char **argv = *argv_p;
198 int argc = *argc_p;
199 struct rtattr *tail;
200 int action = 0;
201 int ret;
202 int has_src_ip = 0;
203 int has_dst_ip = 0;
204 int has_key_id = 0;
205 int csum = 1;
206
207 if (matches(*argv, "tunnel_key") != 0)
208 return -1;
209
210 tail = addattr_nest(n, MAX_MSG, tca_id);
211
212 NEXT_ARG();
213
214 while (argc > 0) {
215 if (matches(*argv, "unset") == 0) {
216 if (action) {
217 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
218 *argv);
219 explain();
220 return -1;
221 }
222 action = TCA_TUNNEL_KEY_ACT_RELEASE;
223 } else if (matches(*argv, "set") == 0) {
224 if (action) {
225 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
226 *argv);
227 explain();
228 return -1;
229 }
230 action = TCA_TUNNEL_KEY_ACT_SET;
231 } else if (matches(*argv, "src_ip") == 0) {
232 NEXT_ARG();
233 ret = tunnel_key_parse_ip_addr(*argv,
234 TCA_TUNNEL_KEY_ENC_IPV4_SRC,
235 TCA_TUNNEL_KEY_ENC_IPV6_SRC,
236 n);
237 if (ret < 0) {
238 fprintf(stderr, "Illegal \"src_ip\"\n");
239 return -1;
240 }
241 has_src_ip = 1;
242 } else if (matches(*argv, "dst_ip") == 0) {
243 NEXT_ARG();
244 ret = tunnel_key_parse_ip_addr(*argv,
245 TCA_TUNNEL_KEY_ENC_IPV4_DST,
246 TCA_TUNNEL_KEY_ENC_IPV6_DST,
247 n);
248 if (ret < 0) {
249 fprintf(stderr, "Illegal \"dst_ip\"\n");
250 return -1;
251 }
252 has_dst_ip = 1;
253 } else if (matches(*argv, "id") == 0) {
254 NEXT_ARG();
255 ret = tunnel_key_parse_key_id(*argv, TCA_TUNNEL_KEY_ENC_KEY_ID, n);
256 if (ret < 0) {
257 fprintf(stderr, "Illegal \"id\"\n");
258 return -1;
259 }
260 has_key_id = 1;
261 } else if (matches(*argv, "dst_port") == 0) {
262 NEXT_ARG();
263 ret = tunnel_key_parse_dst_port(*argv,
264 TCA_TUNNEL_KEY_ENC_DST_PORT, n);
265 if (ret < 0) {
266 fprintf(stderr, "Illegal \"dst port\"\n");
267 return -1;
268 }
269 } else if (matches(*argv, "geneve_opts") == 0) {
270 NEXT_ARG();
271
272 if (tunnel_key_parse_geneve_opts(*argv, n)) {
273 fprintf(stderr, "Illegal \"geneve_opts\"\n");
274 return -1;
275 }
276 } else if (matches(*argv, "csum") == 0) {
277 csum = 1;
278 } else if (matches(*argv, "nocsum") == 0) {
279 csum = 0;
280 } else if (matches(*argv, "help") == 0) {
281 usage();
282 } else {
283 break;
284 }
285 NEXT_ARG_FWD();
286 }
287
288 addattr8(n, MAX_MSG, TCA_TUNNEL_KEY_NO_CSUM, !csum);
289
290 parse_action_control_dflt(&argc, &argv, &parm.action,
291 false, TC_ACT_PIPE);
292
293 if (argc) {
294 if (matches(*argv, "index") == 0) {
295 NEXT_ARG();
296 if (get_u32(&parm.index, *argv, 10)) {
297 fprintf(stderr, "tunnel_key: Illegal \"index\"\n");
298 return -1;
299 }
300
301 NEXT_ARG_FWD();
302 }
303 }
304
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");
308 explain();
309 return -1;
310 }
311
312 parm.t_action = action;
313 addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm));
314 addattr_nest_end(n, tail);
315
316 *argc_p = argc;
317 *argv_p = argv;
318
319 return 0;
320 }
321
322 static void tunnel_key_print_ip_addr(FILE *f, const char *name,
323 struct rtattr *attr)
324 {
325 int family;
326 size_t len;
327
328 if (!attr)
329 return;
330
331 len = RTA_PAYLOAD(attr);
332
333 if (len == 4)
334 family = AF_INET;
335 else if (len == 16)
336 family = AF_INET6;
337 else
338 return;
339
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));
347 }
348
349 static void tunnel_key_print_key_id(FILE *f, const char *name,
350 struct rtattr *attr)
351 {
352 if (!attr)
353 return;
354 print_string(PRINT_FP, NULL, "%s", _SL_);
355 print_uint(PRINT_ANY, "key_id", "\tkey_id %u", rta_getattr_be32(attr));
356 }
357
358 static void tunnel_key_print_dst_port(FILE *f, char *name,
359 struct rtattr *attr)
360 {
361 if (!attr)
362 return;
363 print_string(PRINT_FP, NULL, "%s", _SL_);
364 print_uint(PRINT_ANY, "dst_port", "\tdst_port %u",
365 rta_getattr_be16(attr));
366 }
367
368 static void tunnel_key_print_flag(FILE *f, const char *name_on,
369 const char *name_off,
370 struct rtattr *attr)
371 {
372 if (!attr)
373 return;
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);
377 }
378
379 static void tunnel_key_print_geneve_options(const char *name,
380 struct rtattr *attr)
381 {
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];
388 uint8_t data_r[rem];
389 uint16_t clss;
390 uint8_t type;
391
392 open_json_array(PRINT_JSON, name);
393 print_string(PRINT_FP, name, "\n\t%s ", "geneve_opt");
394
395 while (rem) {
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;
406
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");
414 close_json_object();
415
416 sprintf(strbuf, "%04x:%02x:%s", clss, type, data);
417 if (rem)
418 print_string(PRINT_FP, NULL, "%s,", strbuf);
419 else
420 print_string(PRINT_FP, NULL, "%s", strbuf);
421 }
422
423 close_json_array(PRINT_JSON, name);
424 }
425
426 static void tunnel_key_print_key_opt(const char *name, struct rtattr *attr)
427 {
428 struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
429
430 if (!attr)
431 return;
432
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]);
436 }
437
438 static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
439 {
440 struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1];
441 struct tc_tunnel_key *parm;
442
443 if (!arg)
444 return -1;
445
446 parse_rtattr_nested(tb, TCA_TUNNEL_KEY_MAX, arg);
447
448 if (!tb[TCA_TUNNEL_KEY_PARMS]) {
449 print_string(PRINT_FP, NULL, "%s",
450 "[NULL tunnel_key parameters]");
451 return -1;
452 }
453 parm = RTA_DATA(tb[TCA_TUNNEL_KEY_PARMS]);
454
455 print_string(PRINT_ANY, "kind", "%s ", "tunnel_key");
456
457 switch (parm->t_action) {
458 case TCA_TUNNEL_KEY_ACT_RELEASE:
459 print_string(PRINT_ANY, "mode", " %s", "unset");
460 break;
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]);
479 break;
480 }
481 print_action_control(f, " ", parm->action, "");
482
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);
487
488 if (show_stats) {
489 if (tb[TCA_TUNNEL_KEY_TM]) {
490 struct tcf_t *tm = RTA_DATA(tb[TCA_TUNNEL_KEY_TM]);
491
492 print_tm(f, tm);
493 }
494 }
495
496 print_string(PRINT_FP, NULL, "%s", _SL_);
497
498 return 0;
499 }
500
501 struct action_util tunnel_key_action_util = {
502 .id = "tunnel_key",
503 .parse_aopt = parse_tunnel_key,
504 .print_aopt = print_tunnel_key,
505 };