Home | History | Annotate | Download | only in ip
      1 /*
      2  * link_vti6.c	VTI 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  *		Saurabh Mohan <saurabh.mohan (at) vyatta.com> Modified link_gre.c for VTI
     11  *		Steffen Klassert <steffen.klassert (at) secunet.com> Modified link_vti.c for IPv6
     12  */
     13 
     14 #include <string.h>
     15 #include <net/if.h>
     16 #include <sys/types.h>
     17 #include <sys/socket.h>
     18 #include <arpa/inet.h>
     19 
     20 #include <linux/ip.h>
     21 #include <linux/if_tunnel.h>
     22 #include "rt_names.h"
     23 #include "utils.h"
     24 #include "ip_common.h"
     25 #include "tunnel.h"
     26 
     27 
     28 static void usage(void) __attribute__((noreturn));
     29 static void usage(void)
     30 {
     31 	fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
     32 	fprintf(stderr, "          type { vti6 } [ remote ADDR ] [ local ADDR ]\n");
     33 	fprintf(stderr, "          [ [i|o]key KEY ]\n");
     34 	fprintf(stderr, "          [ dev PHYS_DEV ]\n");
     35 	fprintf(stderr, "          [ fwmark MARK ]\n");
     36 	fprintf(stderr, "\n");
     37 	fprintf(stderr, "Where: NAME := STRING\n");
     38 	fprintf(stderr, "       ADDR := { IPV6_ADDRESS }\n");
     39 	fprintf(stderr, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
     40 	fprintf(stderr, "       MARK := { 0x0..0xffffffff }\n");
     41 	exit(-1);
     42 }
     43 
     44 static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
     45 			  struct nlmsghdr *n)
     46 {
     47 	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
     48 	struct {
     49 		struct nlmsghdr n;
     50 		struct ifinfomsg i;
     51 		char buf[1024];
     52 	} req = {
     53 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
     54 		.n.nlmsg_flags = NLM_F_REQUEST,
     55 		.n.nlmsg_type = RTM_GETLINK,
     56 		.i.ifi_family = preferred_family,
     57 		.i.ifi_index = ifi->ifi_index,
     58 	};
     59 	struct rtattr *tb[IFLA_MAX + 1];
     60 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
     61 	struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
     62 	struct in6_addr saddr = IN6ADDR_ANY_INIT;
     63 	struct in6_addr daddr = IN6ADDR_ANY_INIT;
     64 	unsigned int ikey = 0;
     65 	unsigned int okey = 0;
     66 	unsigned int link = 0;
     67 	__u32 fwmark = 0;
     68 	int len;
     69 
     70 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
     71 		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
     72 get_failed:
     73 			fprintf(stderr,
     74 				"Failed to get existing tunnel info.\n");
     75 			return -1;
     76 		}
     77 
     78 		len = req.n.nlmsg_len;
     79 		len -= NLMSG_LENGTH(sizeof(*ifi));
     80 		if (len < 0)
     81 			goto get_failed;
     82 
     83 		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
     84 
     85 		if (!tb[IFLA_LINKINFO])
     86 			goto get_failed;
     87 
     88 		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
     89 
     90 		if (!linkinfo[IFLA_INFO_DATA])
     91 			goto get_failed;
     92 
     93 		parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
     94 				    linkinfo[IFLA_INFO_DATA]);
     95 
     96 		if (vtiinfo[IFLA_VTI_IKEY])
     97 			ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
     98 
     99 		if (vtiinfo[IFLA_VTI_OKEY])
    100 			okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
    101 
    102 		if (vtiinfo[IFLA_VTI_LOCAL])
    103 			memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr));
    104 
    105 		if (vtiinfo[IFLA_VTI_REMOTE])
    106 			memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr));
    107 
    108 		if (vtiinfo[IFLA_VTI_LINK])
    109 			link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
    110 
    111 		if (vtiinfo[IFLA_VTI_FWMARK])
    112 			fwmark = rta_getattr_u32(vtiinfo[IFLA_VTI_FWMARK]);
    113 	}
    114 
    115 	while (argc > 0) {
    116 		if (!matches(*argv, "key")) {
    117 			unsigned int uval;
    118 
    119 			NEXT_ARG();
    120 			if (strchr(*argv, '.'))
    121 				uval = get_addr32(*argv);
    122 			else {
    123 				if (get_unsigned(&uval, *argv, 0) < 0) {
    124 					fprintf(stderr,
    125 						"Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv);
    126 					exit(-1);
    127 				}
    128 				uval = htonl(uval);
    129 			}
    130 
    131 			ikey = okey = uval;
    132 		} else if (!matches(*argv, "ikey")) {
    133 			unsigned int uval;
    134 
    135 			NEXT_ARG();
    136 			if (strchr(*argv, '.'))
    137 				uval = get_addr32(*argv);
    138 			else {
    139 				if (get_unsigned(&uval, *argv, 0) < 0) {
    140 					fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv);
    141 					exit(-1);
    142 				}
    143 				uval = htonl(uval);
    144 			}
    145 			ikey = uval;
    146 		} else if (!matches(*argv, "okey")) {
    147 			unsigned int uval;
    148 
    149 			NEXT_ARG();
    150 			if (strchr(*argv, '.'))
    151 				uval = get_addr32(*argv);
    152 			else {
    153 				if (get_unsigned(&uval, *argv, 0) < 0) {
    154 					fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv);
    155 					exit(-1);
    156 				}
    157 				uval = htonl(uval);
    158 			}
    159 			okey = uval;
    160 		} else if (!matches(*argv, "remote")) {
    161 			NEXT_ARG();
    162 			if (!strcmp(*argv, "any")) {
    163 				fprintf(stderr, "invalid value for \"remote\": \"%s\"\n", *argv);
    164 				exit(-1);
    165 			} else {
    166 				inet_prefix addr;
    167 
    168 				get_prefix(&addr, *argv, AF_INET6);
    169 				memcpy(&daddr, addr.data, addr.bytelen);
    170 			}
    171 		} else if (!matches(*argv, "local")) {
    172 			NEXT_ARG();
    173 			if (!strcmp(*argv, "any")) {
    174 				fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv);
    175 				exit(-1);
    176 			} else {
    177 				inet_prefix addr;
    178 
    179 				get_prefix(&addr, *argv, AF_INET6);
    180 				memcpy(&saddr, addr.data, addr.bytelen);
    181 			}
    182 		} else if (!matches(*argv, "dev")) {
    183 			NEXT_ARG();
    184 			link = if_nametoindex(*argv);
    185 			if (link == 0)
    186 				exit(-1);
    187 		} else if (strcmp(*argv, "fwmark") == 0) {
    188 			NEXT_ARG();
    189 			if (get_u32(&fwmark, *argv, 0))
    190 				invarg("invalid fwmark\n", *argv);
    191 		} else
    192 			usage();
    193 		argc--; argv++;
    194 	}
    195 
    196 	addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
    197 	addattr32(n, 1024, IFLA_VTI_OKEY, okey);
    198 
    199 	if (memcmp(&saddr, &in6addr_any, sizeof(in6addr_any)))
    200 	    addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr));
    201 	if (memcmp(&daddr, &in6addr_any, sizeof(in6addr_any)))
    202 	    addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr));
    203 	addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark);
    204 	if (link)
    205 		addattr32(n, 1024, IFLA_VTI_LINK, link);
    206 
    207 	return 0;
    208 }
    209 
    210 static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
    211 {
    212 	const char *local = "any";
    213 	const char *remote = "any";
    214 	struct in6_addr saddr;
    215 	struct in6_addr daddr;
    216 	unsigned int link;
    217 	char s2[64];
    218 
    219 	if (!tb)
    220 		return;
    221 
    222 	if (tb[IFLA_VTI_REMOTE]) {
    223 		memcpy(&daddr, RTA_DATA(tb[IFLA_VTI_REMOTE]), sizeof(daddr));
    224 
    225 		remote = format_host(AF_INET6, 16, &daddr);
    226 	}
    227 
    228 	print_string(PRINT_ANY, "remote", "remote %s ", remote);
    229 
    230 	if (tb[IFLA_VTI_LOCAL]) {
    231 		memcpy(&saddr, RTA_DATA(tb[IFLA_VTI_LOCAL]), sizeof(saddr));
    232 
    233 		local = format_host(AF_INET6, 16, &saddr);
    234 	}
    235 
    236 	print_string(PRINT_ANY, "local", "local %s ", local);
    237 
    238 	if (tb[IFLA_VTI_LINK] && (link = rta_getattr_u32(tb[IFLA_VTI_LINK]))) {
    239 		const char *n = if_indextoname(link, s2);
    240 
    241 		if (n)
    242 			print_string(PRINT_ANY, "link", "dev %s ", n);
    243 		else
    244 			print_uint(PRINT_ANY, "link_index", "dev %u ", link);
    245 	}
    246 
    247 	if (tb[IFLA_VTI_IKEY]) {
    248 		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2));
    249 		print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
    250 	}
    251 
    252 	if (tb[IFLA_VTI_OKEY]) {
    253 		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2));
    254 		print_string(PRINT_ANY, "okey", "okey %s ", s2);
    255 	}
    256 
    257 	if (tb[IFLA_VTI_FWMARK]) {
    258 		__u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]);
    259 
    260 		if (fwmark) {
    261 			snprintf(s2, sizeof(s2), "0x%x", fwmark);
    262 
    263 			print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
    264 		}
    265 	}
    266 }
    267 
    268 struct link_util vti6_link_util = {
    269 	.id = "vti6",
    270 	.maxattr = IFLA_VTI_MAX,
    271 	.parse_opt = vti6_parse_opt,
    272 	.print_opt = vti6_print_opt,
    273 };
    274