• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@gondor.apana.org.au>
10  *          Saurabh Mohan <saurabh.mohan@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 
print_usage(FILE * f)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));
usage(void)43 static void usage(void)
44 {
45 	print_usage(stderr);
46 	exit(-1);
47 }
48 
vti_parse_opt(struct link_util * lu,int argc,char ** argv,struct nlmsghdr * n)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 
vti_print_opt(struct link_util * lu,FILE * f,struct rtattr * tb[])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 
vti_print_help(struct link_util * lu,int argc,char ** argv,FILE * f)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