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,
     30 		"Usage: ... vti [ remote ADDR ]\n"
     31 		"               [ local ADDR ]\n"
     32 		"               [ [i|o]key KEY ]\n"
     33 		"               [ dev PHYS_DEV ]\n"
     34 		"               [ fwmark MARK ]\n"
     35 		"\n"
     36 		"Where: ADDR := { IP_ADDRESS }\n"
     37 		"       KEY  := { DOTTED_QUAD | NUMBER }\n"
     38 		"       MARK := { 0x0..0xffffffff }\n"
     39 	);
     40 }
     41 
     42 static void usage(void) __attribute__((noreturn));
     43 static void usage(void)
     44 {
     45 	print_usage(stderr);
     46 	exit(-1);
     47 }
     48 
     49 static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
     50 			 struct nlmsghdr *n)
     51 {
     52 	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
     53 	struct {
     54 		struct nlmsghdr n;
     55 		struct ifinfomsg i;
     56 		char buf[1024];
     57 	} req = {
     58 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
     59 		.n.nlmsg_flags = NLM_F_REQUEST,
     60 		.n.nlmsg_type = RTM_GETLINK,
     61 		.i.ifi_family = preferred_family,
     62 		.i.ifi_index = ifi->ifi_index,
     63 	};
     64 	struct rtattr *tb[IFLA_MAX + 1];
     65 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
     66 	struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
     67 	unsigned int ikey = 0;
     68 	unsigned int okey = 0;
     69 	unsigned int saddr = 0;
     70 	unsigned int daddr = 0;
     71 	unsigned int link = 0;
     72 	unsigned int fwmark = 0;
     73 	int len;
     74 
     75 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
     76 		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
     77 get_failed:
     78 			fprintf(stderr,
     79 				"Failed to get existing tunnel info.\n");
     80 			return -1;
     81 		}
     82 
     83 		len = req.n.nlmsg_len;
     84 		len -= NLMSG_LENGTH(sizeof(*ifi));
     85 		if (len < 0)
     86 			goto get_failed;
     87 
     88 		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
     89 
     90 		if (!tb[IFLA_LINKINFO])
     91 			goto get_failed;
     92 
     93 		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
     94 
     95 		if (!linkinfo[IFLA_INFO_DATA])
     96 			goto get_failed;
     97 
     98 		parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
     99 				    linkinfo[IFLA_INFO_DATA]);
    100 
    101 		if (vtiinfo[IFLA_VTI_IKEY])
    102 			ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
    103 
    104 		if (vtiinfo[IFLA_VTI_OKEY])
    105 			okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
    106 
    107 		if (vtiinfo[IFLA_VTI_LOCAL])
    108 			saddr = rta_getattr_u32(vtiinfo[IFLA_VTI_LOCAL]);
    109 
    110 		if (vtiinfo[IFLA_VTI_REMOTE])
    111 			daddr = rta_getattr_u32(vtiinfo[IFLA_VTI_REMOTE]);
    112 
    113 		if (vtiinfo[IFLA_VTI_LINK])
    114 			link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
    115 
    116 		if (vtiinfo[IFLA_VTI_FWMARK])
    117 			fwmark = rta_getattr_u32(vtiinfo[IFLA_VTI_FWMARK]);
    118 	}
    119 
    120 	while (argc > 0) {
    121 		if (!matches(*argv, "key")) {
    122 			unsigned int uval;
    123 
    124 			NEXT_ARG();
    125 			if (strchr(*argv, '.'))
    126 				uval = get_addr32(*argv);
    127 			else {
    128 				if (get_unsigned(&uval, *argv, 0) < 0) {
    129 					fprintf(stderr,
    130 						"Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv);
    131 					exit(-1);
    132 				}
    133 				uval = htonl(uval);
    134 			}
    135 
    136 			ikey = okey = uval;
    137 		} else if (!matches(*argv, "ikey")) {
    138 			unsigned int uval;
    139 
    140 			NEXT_ARG();
    141 			if (strchr(*argv, '.'))
    142 				uval = get_addr32(*argv);
    143 			else {
    144 				if (get_unsigned(&uval, *argv, 0) < 0) {
    145 					fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv);
    146 					exit(-1);
    147 				}
    148 				uval = htonl(uval);
    149 			}
    150 			ikey = uval;
    151 		} else if (!matches(*argv, "okey")) {
    152 			unsigned int uval;
    153 
    154 			NEXT_ARG();
    155 			if (strchr(*argv, '.'))
    156 				uval = get_addr32(*argv);
    157 			else {
    158 				if (get_unsigned(&uval, *argv, 0) < 0) {
    159 					fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv);
    160 					exit(-1);
    161 				}
    162 				uval = htonl(uval);
    163 			}
    164 			okey = uval;
    165 		} else if (!matches(*argv, "remote")) {
    166 			NEXT_ARG();
    167 			if (!strcmp(*argv, "any")) {
    168 				fprintf(stderr, "invalid value for \"remote\": \"%s\"\n", *argv);
    169 				exit(-1);
    170 			} else {
    171 				daddr = get_addr32(*argv);
    172 			}
    173 		} else if (!matches(*argv, "local")) {
    174 			NEXT_ARG();
    175 			if (!strcmp(*argv, "any")) {
    176 				fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv);
    177 				exit(-1);
    178 			} else {
    179 				saddr = get_addr32(*argv);
    180 			}
    181 		} else if (!matches(*argv, "dev")) {
    182 			NEXT_ARG();
    183 			link = if_nametoindex(*argv);
    184 			if (link == 0) {
    185 				fprintf(stderr, "Cannot find device \"%s\"\n",
    186 					*argv);
    187 				exit(-1);
    188 			}
    189 		} else if (strcmp(*argv, "fwmark") == 0) {
    190 			NEXT_ARG();
    191 			if (get_u32(&fwmark, *argv, 0))
    192 				invarg("invalid fwmark\n", *argv);
    193 		} else
    194 			usage();
    195 		argc--; argv++;
    196 	}
    197 
    198 	addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
    199 	addattr32(n, 1024, IFLA_VTI_OKEY, okey);
    200 	addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, 4);
    201 	addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, 4);
    202 	addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark);
    203 	if (link)
    204 		addattr32(n, 1024, IFLA_VTI_LINK, link);
    205 
    206 	return 0;
    207 }
    208 
    209 static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
    210 {
    211 	const char *local = "any";
    212 	const char *remote = "any";
    213 	__u32 key;
    214 	unsigned int link;
    215 	char s2[IFNAMSIZ];
    216 
    217 	if (!tb)
    218 		return;
    219 
    220 	if (tb[IFLA_VTI_REMOTE]) {
    221 		unsigned int addr = rta_getattr_u32(tb[IFLA_VTI_REMOTE]);
    222 
    223 		if (addr)
    224 			remote = format_host(AF_INET, 4, &addr);
    225 	}
    226 
    227 	print_string(PRINT_ANY, "remote", "remote %s ", remote);
    228 
    229 	if (tb[IFLA_VTI_LOCAL]) {
    230 		unsigned int addr = rta_getattr_u32(tb[IFLA_VTI_LOCAL]);
    231 
    232 		if (addr)
    233 			local = format_host(AF_INET, 4, &addr);
    234 	}
    235 
    236 	print_string(PRINT_ANY, "local", "local %s ", local);
    237 
    238 	if (tb[IFLA_VTI_LINK] &&
    239 	    (link = rta_getattr_u32(tb[IFLA_VTI_LINK]))) {
    240 		const char *n = if_indextoname(link, s2);
    241 
    242 		if (n)
    243 			print_string(PRINT_ANY, "link", "dev %s ", n);
    244 		else
    245 			print_uint(PRINT_ANY, "link_index", "dev %u ", link);
    246 	}
    247 
    248 	if (tb[IFLA_VTI_IKEY] &&
    249 	    (key = rta_getattr_u32(tb[IFLA_VTI_IKEY])))
    250 		print_0xhex(PRINT_ANY, "ikey", "ikey %#x ", ntohl(key));
    251 
    252 
    253 	if (tb[IFLA_VTI_OKEY] &&
    254 	    (key = rta_getattr_u32(tb[IFLA_VTI_OKEY])))
    255 		print_0xhex(PRINT_ANY, "okey", "okey %#x ", ntohl(key));
    256 
    257 	if (tb[IFLA_VTI_FWMARK]) {
    258 		__u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]);
    259 
    260 		if (fwmark) {
    261 			SPRINT_BUF(b1);
    262 
    263 			snprintf(b1, sizeof(b1), "0x%x", fwmark);
    264 			print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
    265 		}
    266 	}
    267 }
    268 
    269 static void vti_print_help(struct link_util *lu, int argc, char **argv,
    270 	FILE *f)
    271 {
    272 	print_usage(f);
    273 }
    274 
    275 struct link_util vti_link_util = {
    276 	.id = "vti",
    277 	.maxattr = IFLA_VTI_MAX,
    278 	.parse_opt = vti_parse_opt,
    279 	.print_opt = vti_print_opt,
    280 	.print_help = vti_print_help,
    281 };
    282