Home | History | Annotate | Download | only in ip
      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 (at) 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, "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));
     44 static void usage(void)
     45 {
     46 	print_usage(stderr);
     47 	exit(-1);
     48 }
     49 
     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 
    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 
    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