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