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