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