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