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, "\n");
     36 	fprintf(stderr, "Where: NAME := STRING\n");
     37 	fprintf(stderr, "       ADDR := { IPV6_ADDRESS }\n");
     38 	fprintf(stderr, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
     39 	exit(-1);
     40 }
     41 
     42 static int vti6_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 *vtiinfo[IFLA_VTI_MAX + 1];
     54 	struct in6_addr saddr;
     55 	struct in6_addr daddr;
     56 	unsigned ikey = 0;
     57 	unsigned okey = 0;
     58 	unsigned link = 0;
     59 	int len;
     60 
     61 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
     62 		memset(&req, 0, sizeof(req));
     63 
     64 		req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
     65 		req.n.nlmsg_flags = NLM_F_REQUEST;
     66 		req.n.nlmsg_type = RTM_GETLINK;
     67 		req.i.ifi_family = preferred_family;
     68 		req.i.ifi_index = ifi->ifi_index;
     69 
     70 		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
     71 get_failed:
     72 			fprintf(stderr,
     73 				"Failed to get existing tunnel info.\n");
     74 			return -1;
     75 		}
     76 
     77 		len = req.n.nlmsg_len;
     78 		len -= NLMSG_LENGTH(sizeof(*ifi));
     79 		if (len < 0)
     80 			goto get_failed;
     81 
     82 		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
     83 
     84 		if (!tb[IFLA_LINKINFO])
     85 			goto get_failed;
     86 
     87 		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
     88 
     89 		if (!linkinfo[IFLA_INFO_DATA])
     90 			goto get_failed;
     91 
     92 		parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
     93 				    linkinfo[IFLA_INFO_DATA]);
     94 
     95 		if (vtiinfo[IFLA_VTI_IKEY])
     96 			ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
     97 
     98 		if (vtiinfo[IFLA_VTI_OKEY])
     99 			okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
    100 
    101 		if (vtiinfo[IFLA_VTI_LOCAL])
    102 			memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr));
    103 
    104 		if (vtiinfo[IFLA_VTI_REMOTE])
    105 			memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr));
    106 
    107 		if (vtiinfo[IFLA_VTI_LINK])
    108 			link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
    109 	}
    110 
    111 	while (argc > 0) {
    112 		if (!matches(*argv, "key")) {
    113 			unsigned uval;
    114 
    115 			NEXT_ARG();
    116 			if (strchr(*argv, '.'))
    117 				uval = get_addr32(*argv);
    118 			else {
    119 				if (get_unsigned(&uval, *argv, 0) < 0) {
    120 					fprintf(stderr,
    121 						"Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv);
    122 					exit(-1);
    123 				}
    124 				uval = htonl(uval);
    125 			}
    126 
    127 			ikey = okey = uval;
    128 		} else if (!matches(*argv, "ikey")) {
    129 			unsigned uval;
    130 
    131 			NEXT_ARG();
    132 			if (strchr(*argv, '.'))
    133 				uval = get_addr32(*argv);
    134 			else {
    135 				if (get_unsigned(&uval, *argv, 0) < 0) {
    136 					fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv);
    137 					exit(-1);
    138 				}
    139 				uval = htonl(uval);
    140 			}
    141 			ikey = uval;
    142 		} else if (!matches(*argv, "okey")) {
    143 			unsigned uval;
    144 
    145 			NEXT_ARG();
    146 			if (strchr(*argv, '.'))
    147 				uval = get_addr32(*argv);
    148 			else {
    149 				if (get_unsigned(&uval, *argv, 0) < 0) {
    150 					fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv);
    151 					exit(-1);
    152 				}
    153 				uval = htonl(uval);
    154 			}
    155 			okey = uval;
    156 		} else if (!matches(*argv, "remote")) {
    157 			NEXT_ARG();
    158 			if (!strcmp(*argv, "any")) {
    159 				fprintf(stderr, "invalid value for \"remote\": \"%s\"\n", *argv);
    160 				exit(-1);
    161 			} else {
    162 				inet_prefix addr;
    163 				get_prefix(&addr, *argv, AF_INET6);
    164 				memcpy(&daddr, addr.data, addr.bytelen);
    165 			}
    166 		} else if (!matches(*argv, "local")) {
    167 			NEXT_ARG();
    168 			if (!strcmp(*argv, "any")) {
    169 				fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv);
    170 				exit(-1);
    171 			} else {
    172 				inet_prefix addr;
    173 				get_prefix(&addr, *argv, AF_INET6);
    174 				memcpy(&saddr, addr.data, addr.bytelen);
    175 			}
    176 		} else if (!matches(*argv, "dev")) {
    177 			NEXT_ARG();
    178 			link = if_nametoindex(*argv);
    179 			if (link == 0)
    180 				exit(-1);
    181 		} else
    182 			usage();
    183 		argc--; argv++;
    184 	}
    185 
    186 	addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
    187 	addattr32(n, 1024, IFLA_VTI_OKEY, okey);
    188 	addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr));
    189 	addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr));
    190 	if (link)
    191 		addattr32(n, 1024, IFLA_VTI_LINK, link);
    192 
    193 	return 0;
    194 }
    195 
    196 static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
    197 {
    198 	char s1[1024];
    199 	char s2[64];
    200 	const char *local = "any";
    201 	const char *remote = "any";
    202 	struct in6_addr saddr;
    203 	struct in6_addr daddr;
    204 
    205 	if (!tb)
    206 		return;
    207 
    208 	if (tb[IFLA_VTI_REMOTE]) {
    209 		memcpy(&daddr, RTA_DATA(tb[IFLA_VTI_REMOTE]), sizeof(daddr));
    210 
    211 		remote = format_host(AF_INET6, 16, &daddr, s1, sizeof(s1));
    212 	}
    213 
    214 	fprintf(f, "remote %s ", remote);
    215 
    216 	if (tb[IFLA_VTI_LOCAL]) {
    217 		memcpy(&saddr, RTA_DATA(tb[IFLA_VTI_LOCAL]), sizeof(saddr));
    218 
    219 		local = format_host(AF_INET6, 16, &saddr, s1, sizeof(s1));
    220 	}
    221 
    222 	fprintf(f, "local %s ", local);
    223 
    224 	if (tb[IFLA_VTI_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK])) {
    225 		unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK]);
    226 		const char *n = if_indextoname(link, s2);
    227 
    228 		if (n)
    229 			fprintf(f, "dev %s ", n);
    230 		else
    231 			fprintf(f, "dev %u ", link);
    232 	}
    233 
    234 	if (tb[IFLA_VTI_IKEY]) {
    235 		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2));
    236 		fprintf(f, "ikey %s ", s2);
    237 	}
    238 
    239 	if (tb[IFLA_VTI_OKEY]) {
    240 		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2));
    241 		fprintf(f, "okey %s ", s2);
    242 	}
    243 }
    244 
    245 struct link_util vti6_link_util = {
    246 	.id = "vti6",
    247 	.maxattr = IFLA_VTI_MAX,
    248 	.parse_opt = vti6_parse_opt,
    249 	.print_opt = vti6_print_opt,
    250 };
    251