• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@gondor.apana.org.au>
10  *		Saurabh Mohan <saurabh.mohan@vyatta.com> Modified link_gre.c for VTI
11  *		Steffen Klassert <steffen.klassert@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));
usage(void)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 
vti6_parse_opt(struct link_util * lu,int argc,char ** argv,struct nlmsghdr * n)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 
vti6_print_opt(struct link_util * lu,FILE * f,struct rtattr * tb[])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