libnl 3.12.0
ip6vti.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2
3/**
4 * @ingroup link
5 * @defgroup ip6vti IP6VTI
6 * ip6vti link module
7 *
8 * @details
9 * \b Link Type Name: "vti6"
10 *
11 * @route_doc{link_ip6vti, IP6VTI Documentation}
12 *
13 * @{
14 */
15
16#include "nl-default.h"
17
18#include <linux/if_tunnel.h>
19
20#include <netlink/netlink.h>
21#include <netlink/attr.h>
22#include <netlink/utils.h>
23#include <netlink/object.h>
24#include <netlink/route/rtnl.h>
25#include <netlink/route/link/ip6vti.h>
26
27#include "nl-route.h"
28#include "link-api.h"
29#include "nl-aux-route/nl-route.h"
30
31#define IP6VTI_ATTR_LINK (1 << 0)
32#define IP6VTI_ATTR_IKEY (1 << 1)
33#define IP6VTI_ATTR_OKEY (1 << 2)
34#define IP6VTI_ATTR_LOCAL (1 << 3)
35#define IP6VTI_ATTR_REMOTE (1 << 4)
36#define IP6VTI_ATTR_FWMARK (1 << 5)
37
39{
40 uint32_t link;
41 uint32_t ikey;
42 uint32_t okey;
43 struct in6_addr local;
44 struct in6_addr remote;
45 uint32_t fwmark;
46 uint32_t ip6vti_mask;
47};
48
49static struct nla_policy ip6vti_policy[IFLA_VTI_MAX + 1] = {
50 [IFLA_VTI_LINK] = { .type = NLA_U32 },
51 [IFLA_VTI_IKEY] = { .type = NLA_U32 },
52 [IFLA_VTI_OKEY] = { .type = NLA_U32 },
53 [IFLA_VTI_LOCAL] = { .minlen = sizeof(struct in6_addr) },
54 [IFLA_VTI_REMOTE] = { .minlen = sizeof(struct in6_addr) },
55 [IFLA_VTI_FWMARK] = { .type = NLA_U32 },
56};
57
58static int ip6vti_alloc(struct rtnl_link *link)
59{
60 struct ip6vti_info *ip6vti;
61
62 if (link->l_info)
63 memset(link->l_info, 0, sizeof(*ip6vti));
64 else {
65 ip6vti = calloc(1, sizeof(*ip6vti));
66 if (!ip6vti)
67 return -NLE_NOMEM;
68
69 link->l_info = ip6vti;
70 }
71
72 return 0;
73}
74
75static int ip6vti_parse(struct rtnl_link *link, struct nlattr *data,
76 struct nlattr *xstats)
77{
78 struct nlattr *tb[IFLA_VTI_MAX + 1];
79 struct ip6vti_info *ip6vti;
80 int err;
81
82 NL_DBG(3, "Parsing IP6VTI link info\n");
83
84 err = nla_parse_nested(tb, IFLA_VTI_MAX, data, ip6vti_policy);
85 if (err < 0)
86 goto errout;
87
88 err = ip6vti_alloc(link);
89 if (err < 0)
90 goto errout;
91
92 ip6vti = link->l_info;
93
94 if (tb[IFLA_VTI_LINK]) {
95 ip6vti->link = nla_get_u32(tb[IFLA_VTI_LINK]);
96 ip6vti->ip6vti_mask |= IP6VTI_ATTR_LINK;
97 }
98
99 if (tb[IFLA_VTI_IKEY]) {
100 ip6vti->ikey = nla_get_u32(tb[IFLA_VTI_IKEY]);
101 ip6vti->ip6vti_mask |= IP6VTI_ATTR_IKEY;
102 }
103
104 if (tb[IFLA_VTI_OKEY]) {
105 ip6vti->okey = nla_get_u32(tb[IFLA_VTI_OKEY]);
106 ip6vti->ip6vti_mask |= IP6VTI_ATTR_OKEY;
107 }
108
109 if (tb[IFLA_VTI_LOCAL]) {
110 nla_memcpy(&ip6vti->local, tb[IFLA_VTI_LOCAL], sizeof(struct in6_addr));
111 ip6vti->ip6vti_mask |= IP6VTI_ATTR_LOCAL;
112 }
113
114 if (tb[IFLA_VTI_REMOTE]) {
115 nla_memcpy(&ip6vti->remote, tb[IFLA_VTI_REMOTE], sizeof(struct in6_addr));
116 ip6vti->ip6vti_mask |= IP6VTI_ATTR_REMOTE;
117 }
118
119 if (tb[IFLA_VTI_FWMARK]) {
120 ip6vti->fwmark = nla_get_u32(tb[IFLA_VTI_FWMARK]);
121 ip6vti->ip6vti_mask |= IP6VTI_ATTR_FWMARK;
122 }
123
124 err = 0;
125
126 errout:
127 return err;
128}
129
130static int ip6vti_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
131{
132 struct ip6vti_info *ip6vti = link->l_info;
133 struct nlattr *data;
134
135 data = nla_nest_start(msg, IFLA_INFO_DATA);
136 if (!data)
137 return -NLE_MSGSIZE;
138
139 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LINK)
140 NLA_PUT_U32(msg, IFLA_VTI_LINK, ip6vti->link);
141
142 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_IKEY)
143 NLA_PUT_U32(msg, IFLA_VTI_IKEY, ip6vti->ikey);
144
145 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_OKEY)
146 NLA_PUT_U32(msg, IFLA_VTI_OKEY, ip6vti->okey);
147
148 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LOCAL)
149 NLA_PUT(msg, IFLA_VTI_LOCAL, sizeof(struct in6_addr), &ip6vti->local);
150
151 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_REMOTE)
152 NLA_PUT(msg, IFLA_VTI_REMOTE, sizeof(struct in6_addr), &ip6vti->remote);
153
154 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_FWMARK)
155 NLA_PUT_U32(msg, IFLA_VTI_FWMARK, ip6vti->fwmark);
156
157 nla_nest_end(msg, data);
158
159nla_put_failure:
160
161 return 0;
162}
163
164static void ip6vti_free(struct rtnl_link *link)
165{
166 struct ip6vti_info *ip6vti = link->l_info;
167
168 free(ip6vti);
169 link->l_info = NULL;
170}
171
172static void ip6vti_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
173{
174 nl_dump(p, "ip6vti : %s", link->l_name);
175}
176
177static void ip6vti_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
178{
179 struct ip6vti_info *ip6vti = link->l_info;
180 char addr[INET6_ADDRSTRLEN];
181
182 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LINK) {
183 _nl_auto_rtnl_link struct rtnl_link *parent = NULL;
184 char *name;
185
186 nl_dump(p, " link ");
187
188 name = NULL;
189 parent = link_lookup(link->ce_cache, ip6vti->link);
190 if (parent)
191 name = rtnl_link_get_name(parent);
192
193 if (name)
194 nl_dump_line(p, "%s\n", name);
195 else
196 nl_dump_line(p, "%u\n", ip6vti->link);
197 }
198
199 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_IKEY) {
200 nl_dump(p, " ikey ");
201 nl_dump_line(p, "%x\n",ip6vti->ikey);
202 }
203
204 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_OKEY) {
205 nl_dump(p, " okey ");
206 nl_dump_line(p, "%x\n", ip6vti->okey);
207 }
208
209 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LOCAL) {
210 nl_dump(p, " local ");
211 nl_dump_line(p, "%s\n",
212 _nl_inet_ntop(AF_INET6, &ip6vti->local, addr));
213 }
214
215 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_REMOTE) {
216 nl_dump(p, " remote ");
217 nl_dump_line(p, "%s\n",
218 _nl_inet_ntop(AF_INET6, &ip6vti->remote, addr));
219 }
220
221 if (ip6vti->ip6vti_mask & IP6VTI_ATTR_FWMARK) {
222 nl_dump(p, " fwmark ");
223 nl_dump_line(p, "%x\n", ip6vti->fwmark);
224 }
225}
226
227static int ip6vti_clone(struct rtnl_link *dst, struct rtnl_link *src)
228{
229 struct ip6vti_info *ip6vti_dst, *ip6vti_src = src->l_info;
230 int err;
231
232 dst->l_info = NULL;
233
234 err = rtnl_link_set_type(dst, "vti6");
235 if (err < 0)
236 return err;
237
238 ip6vti_dst = dst->l_info;
239
240 if (!ip6vti_dst || !ip6vti_src)
241 BUG();
242
243 memcpy(ip6vti_dst, ip6vti_src, sizeof(struct ip6vti_info));
244
245 return 0;
246}
247
248static struct rtnl_link_info_ops ip6vti_info_ops = {
249 .io_name = "vti6",
250 .io_alloc = ip6vti_alloc,
251 .io_parse = ip6vti_parse,
252 .io_dump = {
253 [NL_DUMP_LINE] = ip6vti_dump_line,
254 [NL_DUMP_DETAILS] = ip6vti_dump_details,
255 },
256 .io_clone = ip6vti_clone,
257 .io_put_attrs = ip6vti_put_attrs,
258 .io_free = ip6vti_free,
259};
260
261#define IS_IP6VTI_LINK_ASSERT(link) \
262 if ((link)->l_info_ops != &ip6vti_info_ops) { \
263 APPBUG("Link is not a ip6vti link. set type \"vti6\" first."); \
264 return -NLE_OPNOTSUPP; \
265 }
266
267#define HAS_IP6VTI_ATTR_ASSERT(ip6vti,attr) \
268 if (!((ip6vti)->ip6vti_mask & (attr))) \
269 return -NLE_NOATTR;
270
271struct rtnl_link *rtnl_link_ip6vti_alloc(void)
272{
273 struct rtnl_link *link;
274 int err;
275
276 link = rtnl_link_alloc();
277 if (!link)
278 return NULL;
279
280 err = rtnl_link_set_type(link, "vti6");
281 if (err < 0) {
282 rtnl_link_put(link);
283 return NULL;
284 }
285
286 return link;
287}
288
289/**
290 * Check if link is a IP6VTI link
291 * @arg link Link object
292 *
293 * @return True if link is a IP6VTI link, otherwise 0 is returned.
294 */
296{
297 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vti6");
298}
299/**
300 * Create a new vti6 tunnel device
301 * @arg sock netlink socket
302 * @arg name name of the tunnel deviceL
303 *
304 * Creates a new vti6 tunnel device in the kernel
305 * @return 0 on success or a negative error code
306 */
307int rtnl_link_ip6vti_add(struct nl_sock *sk, const char *name)
308{
309 struct rtnl_link *link;
310 int err;
311
312 link = rtnl_link_ip6vti_alloc();
313 if (!link)
314 return -NLE_NOMEM;
315
316 if(name)
317 rtnl_link_set_name(link, name);
318
319 err = rtnl_link_add(sk, link, NLM_F_CREATE);
320 rtnl_link_put(link);
321
322 return err;
323}
324/**
325 * Set IP6VTI tunnel interface index
326 * @arg link Link object
327 * @arg index interface index
328 *
329 * @return 0 on success or a negative error code
330 */
331int rtnl_link_ip6vti_set_link(struct rtnl_link *link, uint32_t index)
332{
333 struct ip6vti_info *ip6vti = link->l_info;
334
335 IS_IP6VTI_LINK_ASSERT(link);
336
337 ip6vti->link = index;
338 ip6vti->ip6vti_mask |= IP6VTI_ATTR_LINK;
339
340 return 0;
341}
342
343/**
344 * Get IP6VTI tunnel interface index
345 * @arg link Link object
346 * @arg index addr to fill in with the interface index
347 *
348 * @return 0 on success or a negative error code
349 */
350int rtnl_link_ip6vti_get_link(struct rtnl_link *link, uint32_t *index)
351{
352 struct ip6vti_info *ip6vti = link->l_info;
353
354 IS_IP6VTI_LINK_ASSERT(link);
355
356 HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_LINK);
357
358 *index = ip6vti->link;
359
360 return 0;
361}
362
363/**
364 * Set IP6VTI tunnel set ikey
365 * @arg link Link object
366 * @arg ikey gre ikey
367 *
368 * @return 0 on success or a negative error code
369 */
370int rtnl_link_ip6vti_set_ikey(struct rtnl_link *link, uint32_t ikey)
371{
372 struct ip6vti_info *ip6vti = link->l_info;
373
374 IS_IP6VTI_LINK_ASSERT(link);
375
376 ip6vti->ikey = ikey;
377 ip6vti->ip6vti_mask |= IP6VTI_ATTR_IKEY;
378
379 return 0;
380}
381
382/**
383 * Get IP6VTI tunnel ikey
384 * @arg link Link object
385 * @arg ikey addr to fill in with the ikey
386 *
387 * @return 0 on success or a negative error code
388 */
389int rtnl_link_ip6vti_get_ikey(struct rtnl_link *link, uint32_t *ikey)
390{
391 struct ip6vti_info *ip6vti = link->l_info;
392
393 IS_IP6VTI_LINK_ASSERT(link);
394
395 HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_IKEY);
396
397 *ikey = ip6vti->ikey;
398
399 return 0;
400}
401
402/**
403 * Set IP6VTI tunnel set okey
404 * @arg link Link object
405 * @arg okey gre okey
406 *
407 * @return 0 on success or a negative error code
408 */
409int rtnl_link_ip6vti_set_okey(struct rtnl_link *link, uint32_t okey)
410{
411 struct ip6vti_info *ip6vti = link->l_info;
412
413 IS_IP6VTI_LINK_ASSERT(link);
414
415 ip6vti->okey = okey;
416 ip6vti->ip6vti_mask |= IP6VTI_ATTR_OKEY;
417
418 return 0;
419}
420
421/**
422 * Get IP6VTI tunnel okey
423 * @arg link Link object
424 * @arg okey addr to fill in with the okey
425 *
426 * @return 0 on success or a negative error code
427 */
428int rtnl_link_ip6vti_get_okey(struct rtnl_link *link, uint32_t *okey)
429{
430 struct ip6vti_info *ip6vti = link->l_info;
431
432 IS_IP6VTI_LINK_ASSERT(link);
433
434 HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_OKEY);
435
436 *okey = ip6vti->okey;
437
438 return 0;
439}
440
441/**
442 * Set IP6VTI tunnel local address
443 * @arg link Link object
444 * @arg local local address
445 *
446 * @return 0 on success or a negative error code
447 */
448int rtnl_link_ip6vti_set_local(struct rtnl_link *link, struct in6_addr *local)
449{
450 struct ip6vti_info *ip6vti = link->l_info;
451
452 IS_IP6VTI_LINK_ASSERT(link);
453
454 memcpy(&ip6vti->local, local, sizeof(struct in6_addr));
455 ip6vti->ip6vti_mask |= IP6VTI_ATTR_LOCAL;
456
457 return 0;
458}
459
460/**
461 * Get IP6VTI tunnel local address
462 * @arg link Link object
463 * @arg local addr to fill in with remote address
464 *
465 * @return 0 on success or a negative error code
466 */
467int rtnl_link_ip6vti_get_local(struct rtnl_link *link, struct in6_addr *local)
468{
469 struct ip6vti_info *ip6vti = link->l_info;
470
471 IS_IP6VTI_LINK_ASSERT(link);
472
473 HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_LOCAL);
474
475 memcpy(local, &ip6vti->local, sizeof(struct in6_addr));
476
477 return 0;
478}
479
480/**
481 * Set IP6VTI tunnel remote address
482 * @arg link Link object
483 * @arg remote remote address
484 *
485 * @return 0 on success or a negative error code
486 */
487int rtnl_link_ip6vti_set_remote(struct rtnl_link *link, struct in6_addr *remote)
488{
489 struct ip6vti_info *ip6vti = link->l_info;
490
491 IS_IP6VTI_LINK_ASSERT(link);
492
493 memcpy(&ip6vti->remote, remote, sizeof(struct in6_addr));
494 ip6vti->ip6vti_mask |= IP6VTI_ATTR_REMOTE;
495
496 return 0;
497}
498
499/**
500 * Get IP6VTI tunnel remote address
501 * @arg link Link object
502 * @arg remote addr to fill in with remote address
503 *
504 * @return 0 on success or a negative error code
505 */
506int rtnl_link_ip6vti_get_remote(struct rtnl_link *link, struct in6_addr *remote)
507{
508 struct ip6vti_info *ip6vti = link->l_info;
509
510 IS_IP6VTI_LINK_ASSERT(link);
511
512 HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_REMOTE);
513
514 memcpy(remote, &ip6vti->remote, sizeof(struct in6_addr));
515
516 return 0;
517}
518
519/**
520 * Set IP6VTI tunnel fwmark
521 * @arg link Link object
522 * @arg fwmark fwmark
523 *
524 * @return 0 on success or a negative error code
525 */
526int rtnl_link_ip6vti_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
527{
528 struct ip6vti_info *ip6vti = link->l_info;
529
530 IS_IP6VTI_LINK_ASSERT(link);
531
532 ip6vti->fwmark = fwmark;
533 ip6vti->ip6vti_mask |= IP6VTI_ATTR_FWMARK;
534
535 return 0;
536}
537
538/**
539 * Get IP6VTI tunnel fwmark
540 * @arg link Link object
541 * @arg fwmark addr to fill in with the fwmark
542 *
543 * @return 0 on success or a negative error code
544 */
545int rtnl_link_ip6vti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
546{
547 struct ip6vti_info *ip6vti = link->l_info;
548
549 IS_IP6VTI_LINK_ASSERT(link);
550
551 HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_FWMARK);
552
553 *fwmark = ip6vti->fwmark;
554
555 return 0;
556}
557
558static void _nl_init ip6vti_init(void)
559{
560 rtnl_link_register_info(&ip6vti_info_ops);
561}
562
563static void _nl_exit ip6vti_exit(void)
564{
565 rtnl_link_unregister_info(&ip6vti_info_ops);
566}
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition attr.c:714
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
Definition attr.h:166
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition attr.h:237
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
Definition attr.c:355
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition attr.c:974
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition attr.c:1101
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition attr.c:1037
@ NLA_U32
32 bit integer
Definition attr.h:37
int rtnl_link_ip6vti_add(struct nl_sock *sk, const char *name)
Create a new vti6 tunnel device.
Definition ip6vti.c:307
int rtnl_link_ip6vti_get_link(struct rtnl_link *link, uint32_t *index)
Get IP6VTI tunnel interface index.
Definition ip6vti.c:350
int rtnl_link_ip6vti_get_local(struct rtnl_link *link, struct in6_addr *local)
Get IP6VTI tunnel local address.
Definition ip6vti.c:467
int rtnl_link_ip6vti_set_link(struct rtnl_link *link, uint32_t index)
Set IP6VTI tunnel interface index.
Definition ip6vti.c:331
int rtnl_link_ip6vti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
Get IP6VTI tunnel fwmark.
Definition ip6vti.c:545
int rtnl_link_ip6vti_set_remote(struct rtnl_link *link, struct in6_addr *remote)
Set IP6VTI tunnel remote address.
Definition ip6vti.c:487
int rtnl_link_ip6vti_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
Set IP6VTI tunnel fwmark.
Definition ip6vti.c:526
int rtnl_link_is_ip6vti(struct rtnl_link *link)
Check if link is a IP6VTI link.
Definition ip6vti.c:295
int rtnl_link_ip6vti_set_local(struct rtnl_link *link, struct in6_addr *local)
Set IP6VTI tunnel local address.
Definition ip6vti.c:448
int rtnl_link_ip6vti_set_okey(struct rtnl_link *link, uint32_t okey)
Set IP6VTI tunnel set okey.
Definition ip6vti.c:409
int rtnl_link_ip6vti_get_remote(struct rtnl_link *link, struct in6_addr *remote)
Get IP6VTI tunnel remote address.
Definition ip6vti.c:506
int rtnl_link_ip6vti_get_okey(struct rtnl_link *link, uint32_t *okey)
Get IP6VTI tunnel okey.
Definition ip6vti.c:428
int rtnl_link_ip6vti_set_ikey(struct rtnl_link *link, uint32_t ikey)
Set IP6VTI tunnel set ikey.
Definition ip6vti.c:370
int rtnl_link_ip6vti_get_ikey(struct rtnl_link *link, uint32_t *ikey)
Get IP6VTI tunnel ikey.
Definition ip6vti.c:389
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition utils.c:1015
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition types.h:20
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition types.h:21
Dumping parameters.
Definition types.h:32
Attribute validation policy.
Definition attr.h:66