]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/link_gre.c
Merge branch 'unify_tunnel_help' into next
[mirror_iproute2.git] / ip / link_gre.c
1 /*
2 * link_gre.c gre driver 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: Herbert Xu <herbert@gondor.apana.org.au>
10 *
11 */
12
13 #include <string.h>
14 #include <net/if.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <arpa/inet.h>
18
19 #include <linux/ip.h>
20 #include <linux/if_tunnel.h>
21 #include "rt_names.h"
22 #include "utils.h"
23 #include "ip_common.h"
24 #include "tunnel.h"
25
26 static void gre_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
27 {
28 fprintf(f,
29 "Usage: ... %-9s [ remote ADDR ]\n",
30 lu->id
31 );
32 fprintf(f,
33 " [ local ADDR ]\n"
34 " [ [i|o]seq ]\n"
35 " [ [i|o]key KEY ]\n"
36 " [ [i|o]csum ]\n"
37 " [ ttl TTL ]\n"
38 " [ tos TOS ]\n"
39 " [ [no]pmtudisc ]\n"
40 " [ [no]ignore-df ]\n"
41 " [ dev PHYS_DEV ]\n"
42 " [ fwmark MARK ]\n"
43 " [ external ]\n"
44 " [ noencap ]\n"
45 " [ encap { fou | gue | none } ]\n"
46 " [ encap-sport PORT ]\n"
47 " [ encap-dport PORT ]\n"
48 " [ [no]encap-csum ]\n"
49 " [ [no]encap-csum6 ]\n"
50 " [ [no]encap-remcsum ]\n"
51 " [ erspan_ver version ]\n"
52 " [ erspan IDX ]\n"
53 " [ erspan_dir { ingress | egress } ]\n"
54 " [ erspan_hwid hwid ]\n"
55 "\n"
56 );
57 fprintf(f,
58 "Where: ADDR := { IP_ADDRESS | any }\n"
59 " TOS := { NUMBER | inherit }\n"
60 " TTL := { 1..255 | inherit }\n"
61 " KEY := { DOTTED_QUAD | NUMBER }\n"
62 " MARK := { 0x0..0xffffffff }\n"
63 );
64 }
65
66 static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
67 struct nlmsghdr *n)
68 {
69 struct ifinfomsg *ifi = NLMSG_DATA(n);
70 struct {
71 struct nlmsghdr n;
72 struct ifinfomsg i;
73 } req = {
74 .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
75 .n.nlmsg_flags = NLM_F_REQUEST,
76 .n.nlmsg_type = RTM_GETLINK,
77 .i.ifi_family = preferred_family,
78 .i.ifi_index = ifi->ifi_index,
79 };
80 struct nlmsghdr *answer;
81 struct rtattr *tb[IFLA_MAX + 1];
82 struct rtattr *linkinfo[IFLA_INFO_MAX+1];
83 struct rtattr *greinfo[IFLA_GRE_MAX + 1];
84 __u16 iflags = 0;
85 __u16 oflags = 0;
86 __be32 ikey = 0;
87 __be32 okey = 0;
88 unsigned int saddr = 0;
89 unsigned int daddr = 0;
90 unsigned int link = 0;
91 __u8 pmtudisc = 1;
92 __u8 ttl = 0;
93 __u8 tos = 0;
94 int len;
95 __u16 encaptype = 0;
96 __u16 encapflags = 0;
97 __u16 encapsport = 0;
98 __u16 encapdport = 0;
99 __u8 metadata = 0;
100 __u8 ignore_df = 0;
101 __u32 fwmark = 0;
102 __u32 erspan_idx = 0;
103 __u8 erspan_ver = 0;
104 __u8 erspan_dir = 0;
105 __u16 erspan_hwid = 0;
106
107 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
108 if (rtnl_talk(&rth, &req.n, &answer) < 0) {
109 get_failed:
110 fprintf(stderr,
111 "Failed to get existing tunnel info.\n");
112 return -1;
113 }
114
115 len = answer->nlmsg_len;
116 len -= NLMSG_LENGTH(sizeof(*ifi));
117 if (len < 0)
118 goto get_failed;
119
120 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
121
122 if (!tb[IFLA_LINKINFO])
123 goto get_failed;
124
125 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
126
127 if (!linkinfo[IFLA_INFO_DATA])
128 goto get_failed;
129
130 parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
131 linkinfo[IFLA_INFO_DATA]);
132
133 if (greinfo[IFLA_GRE_IKEY])
134 ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
135
136 if (greinfo[IFLA_GRE_OKEY])
137 okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]);
138
139 if (greinfo[IFLA_GRE_IFLAGS])
140 iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]);
141
142 if (greinfo[IFLA_GRE_OFLAGS])
143 oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
144
145 if (greinfo[IFLA_GRE_LOCAL])
146 saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]);
147
148 if (greinfo[IFLA_GRE_REMOTE])
149 daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]);
150
151 if (greinfo[IFLA_GRE_PMTUDISC])
152 pmtudisc = rta_getattr_u8(
153 greinfo[IFLA_GRE_PMTUDISC]);
154
155 if (greinfo[IFLA_GRE_TTL])
156 ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
157
158 if (greinfo[IFLA_GRE_TOS])
159 tos = rta_getattr_u8(greinfo[IFLA_GRE_TOS]);
160
161 if (greinfo[IFLA_GRE_LINK])
162 link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]);
163
164 if (greinfo[IFLA_GRE_ENCAP_TYPE])
165 encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]);
166 if (greinfo[IFLA_GRE_ENCAP_FLAGS])
167 encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]);
168 if (greinfo[IFLA_GRE_ENCAP_SPORT])
169 encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]);
170 if (greinfo[IFLA_GRE_ENCAP_DPORT])
171 encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);
172
173 if (greinfo[IFLA_GRE_COLLECT_METADATA])
174 metadata = 1;
175
176 if (greinfo[IFLA_GRE_IGNORE_DF])
177 ignore_df =
178 !!rta_getattr_u8(greinfo[IFLA_GRE_IGNORE_DF]);
179
180 if (greinfo[IFLA_GRE_FWMARK])
181 fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]);
182
183 if (greinfo[IFLA_GRE_ERSPAN_INDEX])
184 erspan_idx = rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]);
185
186 if (greinfo[IFLA_GRE_ERSPAN_VER])
187 erspan_ver = rta_getattr_u8(greinfo[IFLA_GRE_ERSPAN_VER]);
188
189 if (greinfo[IFLA_GRE_ERSPAN_DIR])
190 erspan_dir = rta_getattr_u8(greinfo[IFLA_GRE_ERSPAN_DIR]);
191
192 if (greinfo[IFLA_GRE_ERSPAN_HWID])
193 erspan_hwid = rta_getattr_u16(greinfo[IFLA_GRE_ERSPAN_HWID]);
194
195 free(answer);
196 }
197
198 while (argc > 0) {
199 if (!matches(*argv, "key")) {
200 NEXT_ARG();
201 iflags |= GRE_KEY;
202 oflags |= GRE_KEY;
203 ikey = okey = tnl_parse_key("key", *argv);
204 } else if (!matches(*argv, "ikey")) {
205 NEXT_ARG();
206 iflags |= GRE_KEY;
207 ikey = tnl_parse_key("ikey", *argv);
208 } else if (!matches(*argv, "okey")) {
209 NEXT_ARG();
210 oflags |= GRE_KEY;
211 okey = tnl_parse_key("okey", *argv);
212 } else if (!matches(*argv, "seq")) {
213 iflags |= GRE_SEQ;
214 oflags |= GRE_SEQ;
215 } else if (!matches(*argv, "iseq")) {
216 iflags |= GRE_SEQ;
217 } else if (!matches(*argv, "oseq")) {
218 oflags |= GRE_SEQ;
219 } else if (!matches(*argv, "csum")) {
220 iflags |= GRE_CSUM;
221 oflags |= GRE_CSUM;
222 } else if (!matches(*argv, "icsum")) {
223 iflags |= GRE_CSUM;
224 } else if (!matches(*argv, "ocsum")) {
225 oflags |= GRE_CSUM;
226 } else if (!matches(*argv, "nopmtudisc")) {
227 pmtudisc = 0;
228 } else if (!matches(*argv, "pmtudisc")) {
229 pmtudisc = 1;
230 } else if (!matches(*argv, "remote")) {
231 NEXT_ARG();
232 daddr = get_addr32(*argv);
233 } else if (!matches(*argv, "local")) {
234 NEXT_ARG();
235 saddr = get_addr32(*argv);
236 } else if (!matches(*argv, "dev")) {
237 NEXT_ARG();
238 link = ll_name_to_index(*argv);
239 if (link == 0) {
240 fprintf(stderr, "Cannot find device \"%s\"\n",
241 *argv);
242 exit(-1);
243 }
244 } else if (!matches(*argv, "ttl") ||
245 !matches(*argv, "hoplimit") ||
246 !matches(*argv, "hlim")) {
247 NEXT_ARG();
248 if (strcmp(*argv, "inherit") != 0) {
249 if (get_u8(&ttl, *argv, 0))
250 invarg("invalid TTL\n", *argv);
251 } else
252 ttl = 0;
253 } else if (!matches(*argv, "tos") ||
254 !matches(*argv, "tclass") ||
255 !matches(*argv, "dsfield")) {
256 __u32 uval;
257
258 NEXT_ARG();
259 if (strcmp(*argv, "inherit") != 0) {
260 if (rtnl_dsfield_a2n(&uval, *argv))
261 invarg("bad TOS value", *argv);
262 tos = uval;
263 } else
264 tos = 1;
265 } else if (strcmp(*argv, "noencap") == 0) {
266 encaptype = TUNNEL_ENCAP_NONE;
267 } else if (strcmp(*argv, "encap") == 0) {
268 NEXT_ARG();
269 if (strcmp(*argv, "fou") == 0)
270 encaptype = TUNNEL_ENCAP_FOU;
271 else if (strcmp(*argv, "gue") == 0)
272 encaptype = TUNNEL_ENCAP_GUE;
273 else if (strcmp(*argv, "none") == 0)
274 encaptype = TUNNEL_ENCAP_NONE;
275 else
276 invarg("Invalid encap type.", *argv);
277 } else if (strcmp(*argv, "encap-sport") == 0) {
278 NEXT_ARG();
279 if (strcmp(*argv, "auto") == 0)
280 encapsport = 0;
281 else if (get_u16(&encapsport, *argv, 0))
282 invarg("Invalid source port.", *argv);
283 } else if (strcmp(*argv, "encap-dport") == 0) {
284 NEXT_ARG();
285 if (get_u16(&encapdport, *argv, 0))
286 invarg("Invalid destination port.", *argv);
287 } else if (strcmp(*argv, "encap-csum") == 0) {
288 encapflags |= TUNNEL_ENCAP_FLAG_CSUM;
289 } else if (strcmp(*argv, "noencap-csum") == 0) {
290 encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM;
291 } else if (strcmp(*argv, "encap-udp6-csum") == 0) {
292 encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
293 } else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
294 encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM6;
295 } else if (strcmp(*argv, "encap-remcsum") == 0) {
296 encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
297 } else if (strcmp(*argv, "noencap-remcsum") == 0) {
298 encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM;
299 } else if (strcmp(*argv, "external") == 0) {
300 metadata = 1;
301 } else if (strcmp(*argv, "ignore-df") == 0) {
302 ignore_df = 1;
303 } else if (strcmp(*argv, "noignore-df") == 0) {
304 /*
305 *only the lsb is significant, use 2 for presence
306 */
307 ignore_df = 2;
308 } else if (strcmp(*argv, "fwmark") == 0) {
309 NEXT_ARG();
310 if (get_u32(&fwmark, *argv, 0))
311 invarg("invalid fwmark\n", *argv);
312 } else if (strcmp(*argv, "erspan") == 0) {
313 NEXT_ARG();
314 if (get_u32(&erspan_idx, *argv, 0))
315 invarg("invalid erspan index\n", *argv);
316 if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0)
317 invarg("erspan index must be > 0 and <= 20-bit\n", *argv);
318 } else if (strcmp(*argv, "erspan_ver") == 0) {
319 NEXT_ARG();
320 if (get_u8(&erspan_ver, *argv, 0))
321 invarg("invalid erspan version\n", *argv);
322 if (erspan_ver != 1 && erspan_ver != 2)
323 invarg("erspan version must be 1 or 2\n", *argv);
324 } else if (strcmp(*argv, "erspan_dir") == 0) {
325 NEXT_ARG();
326 if (matches(*argv, "ingress") == 0)
327 erspan_dir = 0;
328 else if (matches(*argv, "egress") == 0)
329 erspan_dir = 1;
330 else
331 invarg("Invalid erspan direction.", *argv);
332 } else if (strcmp(*argv, "erspan_hwid") == 0) {
333 NEXT_ARG();
334 if (get_u16(&erspan_hwid, *argv, 0))
335 invarg("invalid erspan hwid\n", *argv);
336 } else {
337 gre_print_help(lu, argc, argv, stderr);
338 return -1;
339 }
340 argc--; argv++;
341 }
342
343 if (!ikey && IN_MULTICAST(ntohl(daddr))) {
344 ikey = daddr;
345 iflags |= GRE_KEY;
346 }
347 if (!okey && IN_MULTICAST(ntohl(daddr))) {
348 okey = daddr;
349 oflags |= GRE_KEY;
350 }
351 if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
352 fprintf(stderr, "A broadcast tunnel requires a source address.\n");
353 return -1;
354 }
355
356 if (!metadata) {
357 addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
358 addattr32(n, 1024, IFLA_GRE_OKEY, okey);
359 addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
360 addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
361 addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
362 addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
363 addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
364 if (ignore_df)
365 addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1);
366 if (link)
367 addattr32(n, 1024, IFLA_GRE_LINK, link);
368 addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
369 addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
370 addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
371 if (erspan_ver) {
372 addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
373 if (erspan_ver == 1 && erspan_idx != 0) {
374 addattr32(n, 1024,
375 IFLA_GRE_ERSPAN_INDEX, erspan_idx);
376 } else if (erspan_ver == 2) {
377 addattr8(n, 1024,
378 IFLA_GRE_ERSPAN_DIR, erspan_dir);
379 addattr16(n, 1024,
380 IFLA_GRE_ERSPAN_HWID, erspan_hwid);
381 }
382 }
383 addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
384 addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
385 addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
386 addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
387 } else {
388 addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
389 }
390
391 return 0;
392 }
393
394 static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
395 {
396 char s2[64];
397 unsigned int iflags = 0;
398 unsigned int oflags = 0;
399 __u8 ttl = 0;
400 __u8 tos = 0;
401
402 if (!tb)
403 return;
404
405 if (tb[IFLA_GRE_COLLECT_METADATA]) {
406 print_bool(PRINT_ANY, "external", "external", true);
407 return;
408 }
409
410 tnl_print_endpoint("remote", tb[IFLA_GRE_REMOTE], AF_INET);
411 tnl_print_endpoint("local", tb[IFLA_GRE_LOCAL], AF_INET);
412
413 if (tb[IFLA_GRE_LINK]) {
414 unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
415
416 if (link) {
417 print_string(PRINT_ANY, "link", "dev %s ",
418 ll_index_to_name(link));
419 }
420 }
421
422 if (tb[IFLA_GRE_TTL])
423 ttl = rta_getattr_u8(tb[IFLA_GRE_TTL]);
424 if (is_json_context() || ttl)
425 print_uint(PRINT_ANY, "ttl", "ttl %u ", ttl);
426 else
427 print_string(PRINT_FP, NULL, "ttl %s ", "inherit");
428
429 if (tb[IFLA_GRE_TOS])
430 tos = rta_getattr_u8(tb[IFLA_GRE_TOS]);
431 if (tos) {
432 if (is_json_context() || tos != 1)
433 print_0xhex(PRINT_ANY, "tos", "tos 0x%x ", tos);
434 else
435 print_string(PRINT_FP, NULL, "tos %s ", "inherit");
436 }
437
438 if (tb[IFLA_GRE_PMTUDISC]) {
439 if (!rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
440 print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false);
441 else
442 print_bool(PRINT_JSON, "pmtudisc", NULL, true);
443 }
444
445 if (tb[IFLA_GRE_IGNORE_DF] && rta_getattr_u8(tb[IFLA_GRE_IGNORE_DF]))
446 print_bool(PRINT_ANY, "ignore_df", "ignore-df ", true);
447
448 if (tb[IFLA_GRE_IFLAGS])
449 iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
450
451 if (tb[IFLA_GRE_OFLAGS])
452 oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]);
453
454 if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
455 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
456 print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
457 }
458
459 if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
460 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
461 print_string(PRINT_ANY, "okey", "okey %s ", s2);
462 }
463
464 if (iflags & GRE_SEQ)
465 print_bool(PRINT_ANY, "iseq", "iseq ", true);
466 if (oflags & GRE_SEQ)
467 print_bool(PRINT_ANY, "oseq", "oseq ", true);
468 if (iflags & GRE_CSUM)
469 print_bool(PRINT_ANY, "icsum", "icsum ", true);
470 if (oflags & GRE_CSUM)
471 print_bool(PRINT_ANY, "ocsum", "ocsum ", true);
472
473 if (tb[IFLA_GRE_FWMARK]) {
474 __u32 fwmark = rta_getattr_u32(tb[IFLA_GRE_FWMARK]);
475
476 if (fwmark) {
477 print_0xhex(PRINT_ANY,
478 "fwmark", "fwmark 0x%x ", fwmark);
479 }
480 }
481
482 if (tb[IFLA_GRE_ERSPAN_INDEX]) {
483 __u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]);
484
485 print_uint(PRINT_ANY,
486 "erspan_index", "erspan_index %u ", erspan_idx);
487 }
488
489 if (tb[IFLA_GRE_ERSPAN_VER]) {
490 __u8 erspan_ver = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_VER]);
491
492 print_uint(PRINT_ANY, "erspan_ver", "erspan_ver %u ", erspan_ver);
493 }
494
495 if (tb[IFLA_GRE_ERSPAN_DIR]) {
496 __u8 erspan_dir = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_DIR]);
497
498 if (erspan_dir == 0)
499 print_string(PRINT_ANY, "erspan_dir",
500 "erspan_dir ingress ", NULL);
501 else
502 print_string(PRINT_ANY, "erspan_dir",
503 "erspan_dir egress ", NULL);
504 }
505
506 if (tb[IFLA_GRE_ERSPAN_HWID]) {
507 __u16 erspan_hwid = rta_getattr_u16(tb[IFLA_GRE_ERSPAN_HWID]);
508
509 print_hex(PRINT_ANY, "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
510 }
511
512 tnl_print_encap(tb,
513 IFLA_GRE_ENCAP_TYPE,
514 IFLA_GRE_ENCAP_FLAGS,
515 IFLA_GRE_ENCAP_SPORT,
516 IFLA_GRE_ENCAP_DPORT);
517 }
518
519 struct link_util gre_link_util = {
520 .id = "gre",
521 .maxattr = IFLA_GRE_MAX,
522 .parse_opt = gre_parse_opt,
523 .print_opt = gre_print_opt,
524 .print_help = gre_print_help,
525 };
526
527 struct link_util gretap_link_util = {
528 .id = "gretap",
529 .maxattr = IFLA_GRE_MAX,
530 .parse_opt = gre_parse_opt,
531 .print_opt = gre_print_opt,
532 .print_help = gre_print_help,
533 };
534
535 struct link_util erspan_link_util = {
536 .id = "erspan",
537 .maxattr = IFLA_GRE_MAX,
538 .parse_opt = gre_parse_opt,
539 .print_opt = gre_print_opt,
540 .print_help = gre_print_help,
541 };