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