Home | History | Annotate | Download | only in ip
      1 /*
      2  * link_vti.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  */
     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 
     27 static void print_usage(FILE *f)
     28 {
     29 	fprintf(f, "Usage: ip link { add | set | change | replace | del } NAME\n");
     30 	fprintf(f, "          type { vti } [ remote ADDR ] [ local ADDR ]\n");
     31 	fprintf(f, "          [ [i|o]key KEY ]\n");
     32 	fprintf(f, "          [ dev PHYS_DEV ]\n");
     33 	fprintf(f, "\n");
     34 	fprintf(f, "Where: NAME := STRING\n");
     35 	fprintf(f, "       ADDR := { IP_ADDRESS }\n");
     36 	fprintf(f, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
     37 }
     38 
     39 static void usage(void) __attribute__((noreturn));
     40 static void usage(void)
     41 {
     42 	print_usage(stderr);
     43 	exit(-1);
     44 }
     45 
     46 static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
     47 			 struct nlmsghdr *n)
     48 {
     49 	struct {
     50 		struct nlmsghdr n;
     51 		struct ifinfomsg i;
     52 		char buf[1024];
     53 	} req;
     54 	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
     55 	struct rtattr *tb[IFLA_MAX + 1];
     56 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
     57 	struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
     58 	unsigned ikey = 0;
     59 	unsigned okey = 0;
     60 	unsigned saddr = 0;
     61 	unsigned daddr = 0;
     62 	unsigned link = 0;
     63 	int len;
     64 
     65 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
     66 		memset(&req, 0, sizeof(req));
     67 
     68 		req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
     69 		req.n.nlmsg_flags = NLM_F_REQUEST;
     70 		req.n.nlmsg_type = RTM_GETLINK;
     71 		req.i.ifi_family = preferred_family;
     72 		req.i.ifi_index = ifi->ifi_index;
     73 
     74 		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
     75 get_failed:
     76 			fprintf(stderr,
     77 				"Failed to get existing tunnel info.\n");
     78 			return -1;
     79 		}
     80 
     81 		len = req.n.nlmsg_len;
     82 		len -= NLMSG_LENGTH(sizeof(*ifi));
     83 		if (len < 0)
     84 			goto get_failed;
     85 
     86 		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
     87 
     88 		if (!tb[IFLA_LINKINFO])
     89 			goto get_failed;
     90 
     91 		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
     92 
     93 		if (!linkinfo[IFLA_INFO_DATA])
     94 			goto get_failed;
     95 
     96 		parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
     97 				    linkinfo[IFLA_INFO_DATA]);
     98 
     99 		if (vtiinfo[IFLA_VTI_IKEY])
    100 			ikey = *(__u32 *)RTA_DATA(vtiinfo[IFLA_VTI_IKEY]);
    101 
    102 		if (vtiinfo[IFLA_VTI_OKEY])
    103 			okey = *(__u32 *)RTA_DATA(vtiinfo[IFLA_VTI_OKEY]);
    104 
    105 		if (vtiinfo[IFLA_VTI_LOCAL])
    106 			saddr = *(__u32 *)RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]);
    107 
    108 		if (vtiinfo[IFLA_VTI_REMOTE])
    109 			daddr = *(__u32 *)RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]);
    110 
    111 		if (vtiinfo[IFLA_VTI_LINK])
    112 			link = *(__u8 *)RTA_DATA(vtiinfo[IFLA_VTI_LINK]);
    113 	}
    114 
    115 	while (argc > 0) {
    116 		if (!matches(*argv, "key")) {
    117 			unsigned 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 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 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 				daddr = get_addr32(*argv);
    167 			}
    168 		} else if (!matches(*argv, "local")) {
    169 			NEXT_ARG();
    170 			if (!strcmp(*argv, "any")) {
    171 				fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv);
    172 				exit(-1);
    173 			} else {
    174 				saddr = get_addr32(*argv);
    175 			}
    176 		} else if (!matches(*argv, "dev")) {
    177 			NEXT_ARG();
    178 			link = if_nametoindex(*argv);
    179 			if (link == 0) {
    180 				fprintf(stderr, "Cannot find device \"%s\"\n",
    181 					*argv);
    182 				exit(-1);
    183 			}
    184 		} else
    185 			usage();
    186 		argc--; argv++;
    187 	}
    188 
    189 	addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
    190 	addattr32(n, 1024, IFLA_VTI_OKEY, okey);
    191 	addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, 4);
    192 	addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, 4);
    193 	if (link)
    194 		addattr32(n, 1024, IFLA_VTI_LINK, link);
    195 
    196 	return 0;
    197 }
    198 
    199 static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
    200 {
    201 	char s1[1024];
    202 	char s2[64];
    203 	const char *local = "any";
    204 	const char *remote = "any";
    205 
    206 	if (!tb)
    207 		return;
    208 
    209 	if (tb[IFLA_VTI_REMOTE]) {
    210 		unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_VTI_REMOTE]);
    211 
    212 		if (addr)
    213 			remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
    214 	}
    215 
    216 	fprintf(f, "remote %s ", remote);
    217 
    218 	if (tb[IFLA_VTI_LOCAL]) {
    219 		unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LOCAL]);
    220 
    221 		if (addr)
    222 			local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
    223 	}
    224 
    225 	fprintf(f, "local %s ", local);
    226 
    227 	if (tb[IFLA_VTI_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK])) {
    228 		unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK]);
    229 		const char *n = if_indextoname(link, s2);
    230 
    231 		if (n)
    232 			fprintf(f, "dev %s ", n);
    233 		else
    234 			fprintf(f, "dev %u ", link);
    235 	}
    236 
    237 	if (tb[IFLA_VTI_IKEY]) {
    238 		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2));
    239 		fprintf(f, "ikey %s ", s2);
    240 	}
    241 
    242 	if (tb[IFLA_VTI_OKEY]) {
    243 		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2));
    244 		fprintf(f, "okey %s ", s2);
    245 	}
    246 }
    247 
    248 static void vti_print_help(struct link_util *lu, int argc, char **argv,
    249 	FILE *f)
    250 {
    251 	print_usage(f);
    252 }
    253 
    254 struct link_util vti_link_util = {
    255 	.id = "vti",
    256 	.maxattr = IFLA_VTI_MAX,
    257 	.parse_opt = vti_parse_opt,
    258 	.print_opt = vti_print_opt,
    259 	.print_help = vti_print_help,
    260 };
    261