• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/route/link/ipvti.c	 IPVTI Link Info
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2014 Susant Sahani <susant@redhat.com>
10  */
11 
12 /**
13  * @ingroup link
14  * @defgroup ipvti IPVTI
15  * ipvti link module
16  *
17  * @details
18  * \b Link Type Name: "ipvti"
19  *
20  * @route_doc{link_ipvti, IPVTI Documentation}
21  *
22  * @{
23  */
24 
25 #include <netlink-private/netlink.h>
26 #include <netlink/netlink.h>
27 #include <netlink/attr.h>
28 #include <netlink/utils.h>
29 #include <netlink/object.h>
30 #include <netlink/route/rtnl.h>
31 #include <netlink/route/link/ipvti.h>
32 #include <netlink-private/route/link/api.h>
33 #include <linux/if_tunnel.h>
34 
35 #define IPVTI_ATTR_LINK		 (1 << 0)
36 #define IPVTI_ATTR_IKEY		 (1 << 1)
37 #define IPVTI_ATTR_OKEY		 (1 << 2)
38 #define IPVTI_ATTR_LOCAL	 (1 << 3)
39 #define IPVTI_ATTR_REMOTE	 (1 << 4)
40 
41 struct ipvti_info
42 {
43 	uint32_t   link;
44 	uint32_t   ikey;
45 	uint32_t   okey;
46 	uint32_t   local;
47 	uint32_t   remote;
48 	uint32_t   ipvti_mask;
49 };
50 
51 static	struct nla_policy ipvti_policy[IFLA_VTI_MAX + 1] = {
52 	[IFLA_VTI_LINK]     = { .type = NLA_U32 },
53 	[IFLA_VTI_IKEY]     = { .type = NLA_U32 },
54 	[IFLA_VTI_OKEY]     = { .type = NLA_U32 },
55 	[IFLA_VTI_LOCAL]    = { .type = NLA_U32 },
56 	[IFLA_VTI_REMOTE]   = { .type = NLA_U32 },
57 };
58 
ipvti_alloc(struct rtnl_link * link)59 static int ipvti_alloc(struct rtnl_link *link)
60 {
61 	struct ipvti_info *ipvti;
62 
63 	if (link->l_info)
64 		memset(link->l_info, 0, sizeof(*ipvti));
65 	else {
66 		ipvti = calloc(1, sizeof(*ipvti));
67 		if (!ipvti)
68 			return -NLE_NOMEM;
69 
70 		link->l_info = ipvti;
71 	}
72 
73 	return 0;
74 }
75 
ipvti_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)76 static int ipvti_parse(struct rtnl_link *link, struct nlattr *data,
77 		       struct nlattr *xstats)
78 {
79 	struct nlattr *tb[IFLA_VTI_MAX + 1];
80 	struct ipvti_info *ipvti;
81 	int err;
82 
83 	NL_DBG(3, "Parsing IPVTI link info\n");
84 
85 	err = nla_parse_nested(tb, IFLA_VTI_MAX, data, ipvti_policy);
86 	if (err < 0)
87 		goto errout;
88 
89 	err = ipvti_alloc(link);
90 	if (err < 0)
91 		goto errout;
92 
93 	ipvti = link->l_info;
94 
95 	if (tb[IFLA_VTI_LINK]) {
96 		ipvti->link = nla_get_u32(tb[IFLA_VTI_LINK]);
97 		ipvti->ipvti_mask |= IPVTI_ATTR_LINK;
98 	}
99 
100 	if (tb[IFLA_VTI_IKEY]) {
101 		ipvti->ikey = nla_get_u32(tb[IFLA_VTI_IKEY]);
102 		ipvti->ipvti_mask |= IPVTI_ATTR_IKEY;
103 	}
104 
105 	if (tb[IFLA_VTI_OKEY]) {
106 		ipvti->okey = nla_get_u32(tb[IFLA_VTI_OKEY]);
107 		ipvti->ipvti_mask |= IPVTI_ATTR_OKEY;
108 	}
109 
110 	if (tb[IFLA_VTI_LOCAL]) {
111 		ipvti->local = nla_get_u32(tb[IFLA_VTI_LOCAL]);
112 		ipvti->ipvti_mask |= IPVTI_ATTR_LOCAL;
113 	}
114 
115 	if (tb[IFLA_VTI_REMOTE]) {
116 		ipvti->remote = nla_get_u32(tb[IFLA_VTI_REMOTE]);
117 		ipvti->ipvti_mask |= IPVTI_ATTR_REMOTE;
118 	}
119 
120 	err = 0;
121 
122 errout:
123 	return err;
124 }
125 
ipvti_put_attrs(struct nl_msg * msg,struct rtnl_link * link)126 static int ipvti_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
127 {
128 	struct ipvti_info *ipvti = link->l_info;
129 	struct nlattr *data;
130 
131 	data = nla_nest_start(msg, IFLA_INFO_DATA);
132 	if (!data)
133 		return -NLE_MSGSIZE;
134 
135 	if (ipvti->ipvti_mask & IPVTI_ATTR_LINK)
136 		NLA_PUT_U32(msg, IFLA_VTI_LINK, ipvti->link);
137 
138 	if (ipvti->ipvti_mask & IPVTI_ATTR_IKEY)
139 		NLA_PUT_U32(msg, IFLA_VTI_IKEY, ipvti->ikey);
140 
141 	if (ipvti->ipvti_mask & IFLA_VTI_IKEY)
142 		NLA_PUT_U32(msg, IFLA_VTI_OKEY, ipvti->okey);
143 
144 	if (ipvti->ipvti_mask & IPVTI_ATTR_LOCAL)
145 		NLA_PUT_U32(msg, IFLA_VTI_LOCAL, ipvti->local);
146 
147 	if (ipvti->ipvti_mask & IPVTI_ATTR_REMOTE)
148 		NLA_PUT_U32(msg, IFLA_VTI_REMOTE, ipvti->remote);
149 
150 	nla_nest_end(msg, data);
151 
152 nla_put_failure:
153 
154 	return 0;
155 }
156 
ipvti_free(struct rtnl_link * link)157 static void ipvti_free(struct rtnl_link *link)
158 {
159 	struct ipvti_info *ipvti = link->l_info;
160 
161 	free(ipvti);
162 	link->l_info = NULL;
163 }
164 
ipvti_dump_line(struct rtnl_link * link,struct nl_dump_params * p)165 static void ipvti_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
166 {
167 	nl_dump(p, "ipvti : %s", link->l_name);
168 }
169 
ipvti_dump_details(struct rtnl_link * link,struct nl_dump_params * p)170 static void ipvti_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
171 {
172 	struct ipvti_info *ipvti = link->l_info;
173 	char *name, addr[INET_ADDRSTRLEN];
174 	struct rtnl_link *parent;
175 
176 	if (ipvti->ipvti_mask & IPVTI_ATTR_LINK) {
177 		nl_dump(p, "      link ");
178 
179 		name = NULL;
180 		parent = link_lookup(link->ce_cache, ipvti->link);
181 		if (parent)
182 			name = rtnl_link_get_name(parent);
183 
184 		if (name)
185 			nl_dump_line(p, "%s\n", name);
186 		else
187 			nl_dump_line(p, "%u\n", ipvti->link);
188 	}
189 
190 	if (ipvti->ipvti_mask & IPVTI_ATTR_IKEY) {
191 		nl_dump(p, "      ikey   ");
192 		nl_dump_line(p, "%x\n",ipvti->ikey);
193 	}
194 
195 	if (ipvti->ipvti_mask & IPVTI_ATTR_OKEY) {
196 		nl_dump(p, "      okey ");
197 		nl_dump_line(p, "%x\n", ipvti->okey);
198 	}
199 
200 	if (ipvti->ipvti_mask & IPVTI_ATTR_LOCAL) {
201 		nl_dump(p, "      local ");
202 		if(inet_ntop(AF_INET, &ipvti->local, addr, sizeof(addr)))
203 			nl_dump_line(p, "%s\n", addr);
204 		else
205 			nl_dump_line(p, "%#x\n", ntohs(ipvti->local));
206 	}
207 
208 	if (ipvti->ipvti_mask & IPVTI_ATTR_REMOTE) {
209 		nl_dump(p, "      remote ");
210 		if(inet_ntop(AF_INET, &ipvti->remote, addr, sizeof(addr)))
211 			nl_dump_line(p, "%s\n", addr);
212 		else
213 			nl_dump_line(p, "%#x\n", ntohs(ipvti->remote));
214 	}
215 }
216 
ipvti_clone(struct rtnl_link * dst,struct rtnl_link * src)217 static int ipvti_clone(struct rtnl_link *dst, struct rtnl_link *src)
218 {
219 	struct ipvti_info *ipvti_dst, *ipvti_src = src->l_info;
220 	int err;
221 
222 	dst->l_info = NULL;
223 
224 	err = rtnl_link_set_type(dst, "vti");
225 	if (err < 0)
226 		return err;
227 
228 	ipvti_dst = dst->l_info;
229 
230 	if (!ipvti_dst || !ipvti_src)
231 		BUG();
232 
233 	memcpy(ipvti_dst, ipvti_src, sizeof(struct ipvti_info));
234 
235 	return 0;
236 }
237 
238 static struct rtnl_link_info_ops ipvti_info_ops = {
239 	.io_name                = "vti",
240 	.io_alloc               = ipvti_alloc,
241 	.io_parse               = ipvti_parse,
242 	.io_dump = {
243 		[NL_DUMP_LINE]  = ipvti_dump_line,
244 		[NL_DUMP_DETAILS] = ipvti_dump_details,
245 	},
246 	.io_clone               = ipvti_clone,
247 	.io_put_attrs           = ipvti_put_attrs,
248 	.io_free                = ipvti_free,
249 };
250 
251 #define IS_IPVTI_LINK_ASSERT(link)                                          \
252         if ((link)->l_info_ops != &ipvti_info_ops) {                        \
253                 APPBUG("Link is not a ipvti link. set type \vti\" first."); \
254                 return -NLE_OPNOTSUPP;                                      \
255         }
256 
rtnl_link_ipvti_alloc(void)257 struct rtnl_link *rtnl_link_ipvti_alloc(void)
258 {
259 	struct rtnl_link *link;
260 	int err;
261 
262 	link = rtnl_link_alloc();
263 	if (!link)
264 		return NULL;
265 
266 	err = rtnl_link_set_type(link, "vti");
267 	if (err < 0) {
268 		rtnl_link_put(link);
269 		return NULL;
270 	}
271 
272 	return link;
273 }
274 
275 /**
276  * Check if link is a IPVTI link
277  * @arg link            Link object
278  *
279  * @return True if link is a IPVTI link, otherwise 0 is returned.
280  */
rtnl_link_is_ipvti(struct rtnl_link * link)281 int rtnl_link_is_ipvti(struct rtnl_link *link)
282 {
283 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vti");
284 }
285 /**
286  * Create a new ipvti tunnel device
287  * @arg sock            netlink socket
288  * @arg name            name of the tunnel deviceL
289  *
290  * Creates a new ipvti tunnel device in the kernel
291  * @return 0 on success or a negative error code
292  */
rtnl_link_ipvti_add(struct nl_sock * sk,const char * name)293 int rtnl_link_ipvti_add(struct nl_sock *sk, const char *name)
294 {
295 	struct rtnl_link *link;
296 	int err;
297 
298 	link = rtnl_link_ipvti_alloc();
299 	if (!link)
300 		return -NLE_NOMEM;
301 
302 	if(name)
303 		rtnl_link_set_name(link, name);
304 
305 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
306 	rtnl_link_put(link);
307 
308 	return err;
309 }
310 /**
311  * Set IPVTI tunnel interface index
312  * @arg link            Link object
313  * @arg index           interface index
314  *
315  * @return 0 on success or a negative error code
316  */
rtnl_link_ipvti_set_link(struct rtnl_link * link,uint32_t index)317 int rtnl_link_ipvti_set_link(struct rtnl_link *link, uint32_t index)
318 {
319 	struct ipvti_info *ipvti = link->l_info;
320 
321 	IS_IPVTI_LINK_ASSERT(link);
322 
323 	ipvti->link = index;
324 	ipvti->ipvti_mask |= IPVTI_ATTR_LINK;
325 
326 	return 0;
327 }
328 
329 /**
330  * Get IPVTI tunnel interface index
331  * @arg link            Link object
332  *
333  * @return interface index
334  */
rtnl_link_ipvti_get_link(struct rtnl_link * link)335 uint32_t rtnl_link_ipvti_get_link(struct rtnl_link *link)
336 {
337 	struct ipvti_info *ipvti = link->l_info;
338 
339 	IS_IPVTI_LINK_ASSERT(link);
340 
341 	return ipvti->link;
342 }
343 
344 /**
345  * Set IPVTI tunnel set ikey
346  * @arg link            Link object
347  * @arg ikey            gre ikey
348  *
349  * @return 0 on success or a negative error code
350  */
rtnl_link_ipvti_set_ikey(struct rtnl_link * link,uint32_t ikey)351 int rtnl_link_ipvti_set_ikey(struct rtnl_link *link, uint32_t ikey)
352 {
353 	struct ipvti_info *ipvti = link->l_info;
354 
355 	IS_IPVTI_LINK_ASSERT(link);
356 
357 	ipvti->ikey = ikey;
358 	ipvti->ipvti_mask |= IPVTI_ATTR_IKEY;
359 
360 	return 0;
361 }
362 
363 /**
364  * Get IPVTI tunnel ikey
365  * @arg link            Link object
366  *
367  * @return ikey
368  */
rtnl_link_ipvti_get_ikey(struct rtnl_link * link)369 uint32_t rtnl_link_ipvti_get_ikey(struct rtnl_link *link)
370 {
371 	struct ipvti_info *ipvti = link->l_info;
372 
373 	IS_IPVTI_LINK_ASSERT(link);
374 
375 	return ipvti->ikey;
376 }
377 
378 /**
379  * Set IPVTI tunnel set okey
380  * @arg link            Link object
381  * @arg okey            gre okey
382  *
383  * @return 0 on success or a negative error code
384  */
rtnl_link_ipvti_set_okey(struct rtnl_link * link,uint32_t okey)385 int rtnl_link_ipvti_set_okey(struct rtnl_link *link, uint32_t okey)
386 {
387 	struct ipvti_info *ipvti = link->l_info;
388 
389 	IS_IPVTI_LINK_ASSERT(link);
390 
391 	ipvti->okey = okey;
392 	ipvti->ipvti_mask |= IPVTI_ATTR_OKEY;
393 
394 	return 0;
395 }
396 
397 /**
398  * Get IPVTI tunnel okey
399  * @arg link            Link object
400  *
401  * @return okey value
402  */
rtnl_link_ipvti_get_okey(struct rtnl_link * link)403 uint32_t rtnl_link_ipvti_get_okey(struct rtnl_link *link)
404 {
405 	struct ipvti_info *ipvti = link->l_info;
406 
407 	IS_IPVTI_LINK_ASSERT(link);
408 
409 	return ipvti->okey;
410 }
411 
412 /**
413  * Set IPVTI tunnel local address
414  * @arg link            Link object
415  * @arg addr            local address
416  *
417  * @return 0 on success or a negative error code
418  */
rtnl_link_ipvti_set_local(struct rtnl_link * link,uint32_t addr)419 int rtnl_link_ipvti_set_local(struct rtnl_link *link, uint32_t addr)
420 {
421 	struct ipvti_info *ipvti = link->l_info;
422 
423 	IS_IPVTI_LINK_ASSERT(link);
424 
425 	ipvti->local = addr;
426 	ipvti->ipvti_mask |= IPVTI_ATTR_LOCAL;
427 
428 	return 0;
429 }
430 
431 /**
432  * Get IPVTI tunnel local address
433  * @arg link            Link object
434  *
435  * @return local address
436  */
rtnl_link_ipvti_get_local(struct rtnl_link * link)437 uint32_t rtnl_link_ipvti_get_local(struct rtnl_link *link)
438 {
439 	struct ipvti_info *ipvti = link->l_info;
440 
441 	IS_IPVTI_LINK_ASSERT(link);
442 
443 	return ipvti->local;
444 }
445 
446 /**
447  * Set IPVTI tunnel remote address
448  * @arg link            Link object
449  * @arg remote          remote address
450  *
451  * @return 0 on success or a negative error code
452  */
rtnl_link_ipvti_set_remote(struct rtnl_link * link,uint32_t remote)453 int rtnl_link_ipvti_set_remote(struct rtnl_link *link, uint32_t remote)
454 {
455 	struct ipvti_info *ipvti = link->l_info;
456 
457 	IS_IPVTI_LINK_ASSERT(link);
458 
459 	ipvti->remote = remote;
460 	ipvti->ipvti_mask |= IPVTI_ATTR_REMOTE;
461 
462 	return 0;
463 }
464 
465 /**
466  * Get IPVTI tunnel remote address
467  * @arg link            Link object
468  *
469  * @return remote address  on success or a negative error code
470  */
rtnl_link_ipvti_get_remote(struct rtnl_link * link)471 uint32_t rtnl_link_ipvti_get_remote(struct rtnl_link *link)
472 {
473 	struct ipvti_info *ipvti = link->l_info;
474 
475 	IS_IPVTI_LINK_ASSERT(link);
476 
477 	return ipvti->remote;
478 }
479 
ipvti_init(void)480 static void __init ipvti_init(void)
481 {
482 	rtnl_link_register_info(&ipvti_info_ops);
483 }
484 
ipvti_exit(void)485 static void __exit ipvti_exit(void)
486 {
487 	rtnl_link_unregister_info(&ipvti_info_ops);
488 }
489