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 usage(void) __attribute__((noreturn));
     27 static void usage(void)
     28 {
     29 	fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
     30 	fprintf(stderr, "          type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
     31 	fprintf(stderr, "          [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
     32 	fprintf(stderr, "          [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
     33 	fprintf(stderr, "\n");
     34 	fprintf(stderr, "Where: NAME := STRING\n");
     35 	fprintf(stderr, "       ADDR := { IP_ADDRESS | any }\n");
     36 	fprintf(stderr, "       TOS  := { NUMBER | inherit }\n");
     37 	fprintf(stderr, "       TTL  := { 1..255 | inherit }\n");
     38 	fprintf(stderr, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
     39 	exit(-1);
     40 }
     41 
     42 static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
     43 			 struct nlmsghdr *n)
     44 {
     45 	struct {
     46 		struct nlmsghdr n;
     47 		struct ifinfomsg i;
     48 		char buf[1024];
     49 	} req;
     50 	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
     51 	struct rtattr *tb[IFLA_MAX + 1];
     52 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
     53 	struct rtattr *greinfo[IFLA_GRE_MAX + 1];
     54 	__u16 iflags = 0;
     55 	__u16 oflags = 0;
     56 	unsigned ikey = 0;
     57 	unsigned okey = 0;
     58 	unsigned saddr = 0;
     59 	unsigned daddr = 0;
     60 	unsigned link = 0;
     61 	__u8 pmtudisc = 1;
     62 	__u8 ttl = 0;
     63 	__u8 tos = 0;
     64 	int len;
     65 
     66 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
     67 		memset(&req, 0, sizeof(req));
     68 
     69 		req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
     70 		req.n.nlmsg_flags = NLM_F_REQUEST;
     71 		req.n.nlmsg_type = RTM_GETLINK;
     72 		req.i.ifi_family = preferred_family;
     73 		req.i.ifi_index = ifi->ifi_index;
     74 
     75 		if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
     76 get_failed:
     77 			fprintf(stderr,
     78 				"Failed to get existing tunnel info.\n");
     79 			return -1;
     80 		}
     81 
     82 		len = req.n.nlmsg_len;
     83 		len -= NLMSG_LENGTH(sizeof(*ifi));
     84 		if (len < 0)
     85 			goto get_failed;
     86 
     87 		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
     88 
     89 		if (!tb[IFLA_LINKINFO])
     90 			goto get_failed;
     91 
     92 		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
     93 
     94 		if (!linkinfo[IFLA_INFO_DATA])
     95 			goto get_failed;
     96 
     97 		parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
     98 				    linkinfo[IFLA_INFO_DATA]);
     99 
    100 		if (greinfo[IFLA_GRE_IKEY])
    101 			ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
    102 
    103 		if (greinfo[IFLA_GRE_OKEY])
    104 			okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]);
    105 
    106 		if (greinfo[IFLA_GRE_IFLAGS])
    107 			iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]);
    108 
    109 		if (greinfo[IFLA_GRE_OFLAGS])
    110 			oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
    111 
    112 		if (greinfo[IFLA_GRE_LOCAL])
    113 			saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]);
    114 
    115 		if (greinfo[IFLA_GRE_REMOTE])
    116 			daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]);
    117 
    118 		if (greinfo[IFLA_GRE_PMTUDISC])
    119 			pmtudisc = rta_getattr_u8(
    120 				greinfo[IFLA_GRE_PMTUDISC]);
    121 
    122 		if (greinfo[IFLA_GRE_TTL])
    123 			ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
    124 
    125 		if (greinfo[IFLA_GRE_TOS])
    126 			tos = rta_getattr_u8(greinfo[IFLA_GRE_TOS]);
    127 
    128 		if (greinfo[IFLA_GRE_LINK])
    129 			link = rta_getattr_u8(greinfo[IFLA_GRE_LINK]);
    130 	}
    131 
    132 	while (argc > 0) {
    133 		if (!matches(*argv, "key")) {
    134 			unsigned uval;
    135 
    136 			NEXT_ARG();
    137 			iflags |= GRE_KEY;
    138 			oflags |= GRE_KEY;
    139 			if (strchr(*argv, '.'))
    140 				uval = get_addr32(*argv);
    141 			else {
    142 				if (get_unsigned(&uval, *argv, 0) < 0) {
    143 					fprintf(stderr,
    144 						"Invalid value for \"key\"\n");
    145 					exit(-1);
    146 				}
    147 				uval = htonl(uval);
    148 			}
    149 
    150 			ikey = okey = uval;
    151 		} else if (!matches(*argv, "ikey")) {
    152 			unsigned uval;
    153 
    154 			NEXT_ARG();
    155 			iflags |= GRE_KEY;
    156 			if (strchr(*argv, '.'))
    157 				uval = get_addr32(*argv);
    158 			else {
    159 				if (get_unsigned(&uval, *argv, 0)<0) {
    160 					fprintf(stderr, "invalid value of \"ikey\"\n");
    161 					exit(-1);
    162 				}
    163 				uval = htonl(uval);
    164 			}
    165 			ikey = uval;
    166 		} else if (!matches(*argv, "okey")) {
    167 			unsigned uval;
    168 
    169 			NEXT_ARG();
    170 			oflags |= GRE_KEY;
    171 			if (strchr(*argv, '.'))
    172 				uval = get_addr32(*argv);
    173 			else {
    174 				if (get_unsigned(&uval, *argv, 0)<0) {
    175 					fprintf(stderr, "invalid value of \"okey\"\n");
    176 					exit(-1);
    177 				}
    178 				uval = htonl(uval);
    179 			}
    180 			okey = uval;
    181 		} else if (!matches(*argv, "seq")) {
    182 			iflags |= GRE_SEQ;
    183 			oflags |= GRE_SEQ;
    184 		} else if (!matches(*argv, "iseq")) {
    185 			iflags |= GRE_SEQ;
    186 		} else if (!matches(*argv, "oseq")) {
    187 			oflags |= GRE_SEQ;
    188 		} else if (!matches(*argv, "csum")) {
    189 			iflags |= GRE_CSUM;
    190 			oflags |= GRE_CSUM;
    191 		} else if (!matches(*argv, "icsum")) {
    192 			iflags |= GRE_CSUM;
    193 		} else if (!matches(*argv, "ocsum")) {
    194 			oflags |= GRE_CSUM;
    195 		} else if (!matches(*argv, "nopmtudisc")) {
    196 			pmtudisc = 0;
    197 		} else if (!matches(*argv, "pmtudisc")) {
    198 			pmtudisc = 1;
    199 		} else if (!matches(*argv, "remote")) {
    200 			NEXT_ARG();
    201 			if (strcmp(*argv, "any"))
    202 				daddr = get_addr32(*argv);
    203 		} else if (!matches(*argv, "local")) {
    204 			NEXT_ARG();
    205 			if (strcmp(*argv, "any"))
    206 				saddr = get_addr32(*argv);
    207 		} else if (!matches(*argv, "dev")) {
    208 			NEXT_ARG();
    209 			link = if_nametoindex(*argv);
    210 			if (link == 0)
    211 				exit(-1);
    212 		} else if (!matches(*argv, "ttl") ||
    213 			   !matches(*argv, "hoplimit")) {
    214 			unsigned uval;
    215 
    216 			NEXT_ARG();
    217 			if (strcmp(*argv, "inherit") != 0) {
    218 				if (get_unsigned(&uval, *argv, 0))
    219 					invarg("invalid TTL\n", *argv);
    220 				if (uval > 255)
    221 					invarg("TTL must be <= 255\n", *argv);
    222 				ttl = uval;
    223 			}
    224 		} else if (!matches(*argv, "tos") ||
    225 			   !matches(*argv, "tclass") ||
    226 			   !matches(*argv, "dsfield")) {
    227 			__u32 uval;
    228 
    229 			NEXT_ARG();
    230 			if (strcmp(*argv, "inherit") != 0) {
    231 				if (rtnl_dsfield_a2n(&uval, *argv))
    232 					invarg("bad TOS value", *argv);
    233 				tos = uval;
    234 			} else
    235 				tos = 1;
    236 		} else
    237 			usage();
    238 		argc--; argv++;
    239 	}
    240 
    241 	if (!ikey && IN_MULTICAST(ntohl(daddr))) {
    242 		ikey = daddr;
    243 		iflags |= GRE_KEY;
    244 	}
    245 	if (!okey && IN_MULTICAST(ntohl(daddr))) {
    246 		okey = daddr;
    247 		oflags |= GRE_KEY;
    248 	}
    249 	if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
    250 		fprintf(stderr, "Broadcast tunnel requires a source address.\n");
    251 		return -1;
    252 	}
    253 
    254 	addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
    255 	addattr32(n, 1024, IFLA_GRE_OKEY, okey);
    256 	addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
    257 	addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
    258 	addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
    259 	addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
    260 	addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
    261 	if (link)
    262 		addattr32(n, 1024, IFLA_GRE_LINK, link);
    263 	addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
    264 	addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
    265 
    266 	return 0;
    267 }
    268 
    269 static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
    270 {
    271 	char s1[1024];
    272 	char s2[64];
    273 	const char *local = "any";
    274 	const char *remote = "any";
    275 	unsigned iflags = 0;
    276 	unsigned oflags = 0;
    277 
    278 	if (!tb)
    279 		return;
    280 
    281 	if (tb[IFLA_GRE_REMOTE]) {
    282 		unsigned addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]);
    283 
    284 		if (addr)
    285 			remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
    286 	}
    287 
    288 	fprintf(f, "remote %s ", remote);
    289 
    290 	if (tb[IFLA_GRE_LOCAL]) {
    291 		unsigned addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]);
    292 
    293 		if (addr)
    294 			local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
    295 	}
    296 
    297 	fprintf(f, "local %s ", local);
    298 
    299 	if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
    300 		unsigned link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
    301 		const char *n = if_indextoname(link, s2);
    302 
    303 		if (n)
    304 			fprintf(f, "dev %s ", n);
    305 		else
    306 			fprintf(f, "dev %u ", link);
    307 	}
    308 
    309 	if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
    310 		fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));
    311 	else
    312 		fprintf(f, "ttl inherit ");
    313 
    314 	if (tb[IFLA_GRE_TOS] && rta_getattr_u8(tb[IFLA_GRE_TOS])) {
    315 		int tos = rta_getattr_u8(tb[IFLA_GRE_TOS]);
    316 
    317 		fputs("tos ", f);
    318 		if (tos == 1)
    319 			fputs("inherit ", f);
    320 		else
    321 			fprintf(f, "0x%x ", tos);
    322 	}
    323 
    324 	if (tb[IFLA_GRE_PMTUDISC] &&
    325 	    !rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
    326 		fputs("nopmtudisc ", f);
    327 
    328 	if (tb[IFLA_GRE_IFLAGS])
    329 		iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
    330 
    331 	if (tb[IFLA_GRE_OFLAGS])
    332 		oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]);
    333 
    334 	if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
    335 		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
    336 		fprintf(f, "ikey %s ", s2);
    337 	}
    338 
    339 	if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
    340 		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
    341 		fprintf(f, "okey %s ", s2);
    342 	}
    343 
    344 	if (iflags & GRE_SEQ)
    345 		fputs("iseq ", f);
    346 	if (oflags & GRE_SEQ)
    347 		fputs("oseq ", f);
    348 	if (iflags & GRE_CSUM)
    349 		fputs("icsum ", f);
    350 	if (oflags & GRE_CSUM)
    351 		fputs("ocsum ", f);
    352 }
    353 
    354 struct link_util gre_link_util = {
    355 	.id = "gre",
    356 	.maxattr = IFLA_GRE_MAX,
    357 	.parse_opt = gre_parse_opt,
    358 	.print_opt = gre_print_opt,
    359 };
    360 
    361 struct link_util gretap_link_util = {
    362 	.id = "gretap",
    363 	.maxattr = IFLA_GRE_MAX,
    364 	.parse_opt = gre_parse_opt,
    365 	.print_opt = gre_print_opt,
    366 };
    367