libnl  3.6.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 
44 static 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 
53 static 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 
70 static 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 
125 static 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 
154 nla_put_failure:
155 
156  return 0;
157 }
158 
159 static 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 
167 static 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 
172 static 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, addr[INET6_ADDRSTRLEN];
176 
177  if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LINK) {
178  nl_dump(p, " link ");
179  name = rtnl_link_get_name(link);
180  if (name)
181  nl_dump_line(p, "%s\n", name);
182  else
183  nl_dump_line(p, "%u\n", ip6vti->link);
184  }
185 
186  if (ip6vti->ip6vti_mask & IP6VTI_ATTR_IKEY) {
187  nl_dump(p, " ikey ");
188  nl_dump_line(p, "%x\n",ip6vti->ikey);
189  }
190 
191  if (ip6vti->ip6vti_mask & IP6VTI_ATTR_OKEY) {
192  nl_dump(p, " okey ");
193  nl_dump_line(p, "%x\n", ip6vti->okey);
194  }
195 
196  if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LOCAL) {
197  nl_dump(p, " local ");
198  if(inet_ntop(AF_INET6, &ip6vti->local, addr, sizeof(addr)))
199  nl_dump_line(p, "%s\n", addr);
200  else
201  nl_dump_line(p, "%#x\n", ip6vti->local);
202  }
203 
204  if (ip6vti->ip6vti_mask & IP6VTI_ATTR_REMOTE) {
205  nl_dump(p, " remote ");
206  if(inet_ntop(AF_INET6, &ip6vti->remote, addr, sizeof(addr)))
207  nl_dump_line(p, "%s\n", addr);
208  else
209  nl_dump_line(p, "%#x\n", ip6vti->remote);
210  }
211 
212  if (ip6vti->ip6vti_mask & IP6VTI_ATTR_FWMARK) {
213  nl_dump(p, " fwmark ");
214  nl_dump_line(p, "%x\n", ip6vti->fwmark);
215  }
216 }
217 
218 static int ip6vti_clone(struct rtnl_link *dst, struct rtnl_link *src)
219 {
220  struct ip6vti_info *ip6vti_dst, *ip6vti_src = src->l_info;
221  int err;
222 
223  dst->l_info = NULL;
224 
225  err = rtnl_link_set_type(dst, "vti6");
226  if (err < 0)
227  return err;
228 
229  ip6vti_dst = dst->l_info;
230 
231  if (!ip6vti_dst || !ip6vti_src)
232  BUG();
233 
234  memcpy(ip6vti_dst, ip6vti_src, sizeof(struct ip6vti_info));
235 
236  return 0;
237 }
238 
239 static struct rtnl_link_info_ops ip6vti_info_ops = {
240  .io_name = "vti6",
241  .io_alloc = ip6vti_alloc,
242  .io_parse = ip6vti_parse,
243  .io_dump = {
244  [NL_DUMP_LINE] = ip6vti_dump_line,
245  [NL_DUMP_DETAILS] = ip6vti_dump_details,
246  },
247  .io_clone = ip6vti_clone,
248  .io_put_attrs = ip6vti_put_attrs,
249  .io_free = ip6vti_free,
250 };
251 
252 #define IS_IP6VTI_LINK_ASSERT(link) \
253  if ((link)->l_info_ops != &ip6vti_info_ops) { \
254  APPBUG("Link is not a ip6vti link. set type \"vti6\" first."); \
255  return -NLE_OPNOTSUPP; \
256  }
257 
258 #define HAS_IP6VTI_ATTR_ASSERT(ip6vti,attr) \
259  if (!((ip6vti)->ip6vti_mask & (attr))) \
260  return -NLE_NOATTR;
261 
262 struct rtnl_link *rtnl_link_ip6vti_alloc(void)
263 {
264  struct rtnl_link *link;
265  int err;
266 
267  link = rtnl_link_alloc();
268  if (!link)
269  return NULL;
270 
271  err = rtnl_link_set_type(link, "vti6");
272  if (err < 0) {
273  rtnl_link_put(link);
274  return NULL;
275  }
276 
277  return link;
278 }
279 
280 /**
281  * Check if link is a IP6VTI link
282  * @arg link Link object
283  *
284  * @return True if link is a IP6VTI link, otherwise 0 is returned.
285  */
287 {
288  return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vti6");
289 }
290 /**
291  * Create a new vti6 tunnel device
292  * @arg sock netlink socket
293  * @arg name name of the tunnel deviceL
294  *
295  * Creates a new vti6 tunnel device in the kernel
296  * @return 0 on success or a negative error code
297  */
298 int rtnl_link_ip6vti_add(struct nl_sock *sk, const char *name)
299 {
300  struct rtnl_link *link;
301  int err;
302 
303  link = rtnl_link_ip6vti_alloc();
304  if (!link)
305  return -NLE_NOMEM;
306 
307  if(name)
308  rtnl_link_set_name(link, name);
309 
310  err = rtnl_link_add(sk, link, NLM_F_CREATE);
311  rtnl_link_put(link);
312 
313  return err;
314 }
315 /**
316  * Set IP6VTI tunnel interface index
317  * @arg link Link object
318  * @arg index interface index
319  *
320  * @return 0 on success or a negative error code
321  */
322 int rtnl_link_ip6vti_set_link(struct rtnl_link *link, uint32_t index)
323 {
324  struct ip6vti_info *ip6vti = link->l_info;
325 
326  IS_IP6VTI_LINK_ASSERT(link);
327 
328  ip6vti->link = index;
329  ip6vti->ip6vti_mask |= IP6VTI_ATTR_LINK;
330 
331  return 0;
332 }
333 
334 /**
335  * Get IP6VTI tunnel interface index
336  * @arg link Link object
337  * @arg index addr to fill in with the interface index
338  *
339  * @return 0 on success or a negative error code
340  */
341 int rtnl_link_ip6vti_get_link(struct rtnl_link *link, uint32_t *index)
342 {
343  struct ip6vti_info *ip6vti = link->l_info;
344 
345  IS_IP6VTI_LINK_ASSERT(link);
346 
347  HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_LINK);
348 
349  *index = ip6vti->link;
350 
351  return 0;
352 }
353 
354 /**
355  * Set IP6VTI tunnel set ikey
356  * @arg link Link object
357  * @arg ikey gre ikey
358  *
359  * @return 0 on success or a negative error code
360  */
361 int rtnl_link_ip6vti_set_ikey(struct rtnl_link *link, uint32_t ikey)
362 {
363  struct ip6vti_info *ip6vti = link->l_info;
364 
365  IS_IP6VTI_LINK_ASSERT(link);
366 
367  ip6vti->ikey = ikey;
368  ip6vti->ip6vti_mask |= IP6VTI_ATTR_IKEY;
369 
370  return 0;
371 }
372 
373 /**
374  * Get IP6VTI tunnel ikey
375  * @arg link Link object
376  * @arg ikey addr to fill in with the ikey
377  *
378  * @return 0 on success or a negative error code
379  */
380 int rtnl_link_ip6vti_get_ikey(struct rtnl_link *link, uint32_t *ikey)
381 {
382  struct ip6vti_info *ip6vti = link->l_info;
383 
384  IS_IP6VTI_LINK_ASSERT(link);
385 
386  HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_IKEY);
387 
388  *ikey = ip6vti->ikey;
389 
390  return 0;
391 }
392 
393 /**
394  * Set IP6VTI tunnel set okey
395  * @arg link Link object
396  * @arg okey gre okey
397  *
398  * @return 0 on success or a negative error code
399  */
400 int rtnl_link_ip6vti_set_okey(struct rtnl_link *link, uint32_t okey)
401 {
402  struct ip6vti_info *ip6vti = link->l_info;
403 
404  IS_IP6VTI_LINK_ASSERT(link);
405 
406  ip6vti->okey = okey;
407  ip6vti->ip6vti_mask |= IP6VTI_ATTR_OKEY;
408 
409  return 0;
410 }
411 
412 /**
413  * Get IP6VTI tunnel okey
414  * @arg link Link object
415  * @arg okey addr to fill in with the okey
416  *
417  * @return 0 on success or a negative error code
418  */
419 int rtnl_link_ip6vti_get_okey(struct rtnl_link *link, uint32_t *okey)
420 {
421  struct ip6vti_info *ip6vti = link->l_info;
422 
423  IS_IP6VTI_LINK_ASSERT(link);
424 
425  HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_OKEY);
426 
427  *okey = ip6vti->okey;
428 
429  return 0;
430 }
431 
432 /**
433  * Set IP6VTI tunnel local address
434  * @arg link Link object
435  * @arg local local address
436  *
437  * @return 0 on success or a negative error code
438  */
439 int rtnl_link_ip6vti_set_local(struct rtnl_link *link, struct in6_addr *local)
440 {
441  struct ip6vti_info *ip6vti = link->l_info;
442 
443  IS_IP6VTI_LINK_ASSERT(link);
444 
445  memcpy(&ip6vti->local, local, sizeof(struct in6_addr));
446  ip6vti->ip6vti_mask |= IP6VTI_ATTR_LOCAL;
447 
448  return 0;
449 }
450 
451 /**
452  * Get IP6VTI tunnel local address
453  * @arg link Link object
454  * @arg local addr to fill in with remote address
455  *
456  * @return 0 on success or a negative error code
457  */
458 int rtnl_link_ip6vti_get_local(struct rtnl_link *link, struct in6_addr *local)
459 {
460  struct ip6vti_info *ip6vti = link->l_info;
461 
462  IS_IP6VTI_LINK_ASSERT(link);
463 
464  HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_LOCAL);
465 
466  memcpy(local, &ip6vti->local, sizeof(struct in6_addr));
467 
468  return 0;
469 }
470 
471 /**
472  * Set IP6VTI tunnel remote address
473  * @arg link Link object
474  * @arg remote remote address
475  *
476  * @return 0 on success or a negative error code
477  */
478 int rtnl_link_ip6vti_set_remote(struct rtnl_link *link, struct in6_addr *remote)
479 {
480  struct ip6vti_info *ip6vti = link->l_info;
481 
482  IS_IP6VTI_LINK_ASSERT(link);
483 
484  memcpy(&ip6vti->remote, remote, sizeof(struct in6_addr));
485  ip6vti->ip6vti_mask |= IP6VTI_ATTR_REMOTE;
486 
487  return 0;
488 }
489 
490 /**
491  * Get IP6VTI tunnel remote address
492  * @arg link Link object
493  * @arg remote addr to fill in with remote address
494  *
495  * @return 0 on success or a negative error code
496  */
497 int rtnl_link_ip6vti_get_remote(struct rtnl_link *link, struct in6_addr *remote)
498 {
499  struct ip6vti_info *ip6vti = link->l_info;
500 
501  IS_IP6VTI_LINK_ASSERT(link);
502 
503  HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_REMOTE);
504 
505  memcpy(remote, &ip6vti->remote, sizeof(struct in6_addr));
506 
507  return 0;
508 }
509 
510 /**
511  * Set IP6VTI tunnel fwmark
512  * @arg link Link object
513  * @arg fwmark fwmark
514  *
515  * @return 0 on success or a negative error code
516  */
517 int rtnl_link_ip6vti_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
518 {
519  struct ip6vti_info *ip6vti = link->l_info;
520 
521  IS_IP6VTI_LINK_ASSERT(link);
522 
523  ip6vti->fwmark = fwmark;
524  ip6vti->ip6vti_mask |= IP6VTI_ATTR_FWMARK;
525 
526  return 0;
527 }
528 
529 /**
530  * Get IP6VTI tunnel fwmark
531  * @arg link Link object
532  * @arg fwmark addr to fill in with the fwmark
533  *
534  * @return 0 on success or a negative error code
535  */
536 int rtnl_link_ip6vti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
537 {
538  struct ip6vti_info *ip6vti = link->l_info;
539 
540  IS_IP6VTI_LINK_ASSERT(link);
541 
542  HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_FWMARK);
543 
544  *fwmark = ip6vti->fwmark;
545 
546  return 0;
547 }
548 
549 static void __init ip6vti_init(void)
550 {
551  rtnl_link_register_info(&ip6vti_info_ops);
552 }
553 
554 static void __exit ip6vti_exit(void)
555 {
556  rtnl_link_unregister_info(&ip6vti_info_ops);
557 }
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition: attr.c:699
#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:895
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:1013
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:958
@ 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:298
int rtnl_link_ip6vti_get_link(struct rtnl_link *link, uint32_t *index)
Get IP6VTI tunnel interface index.
Definition: ip6vti.c:341
int rtnl_link_ip6vti_get_local(struct rtnl_link *link, struct in6_addr *local)
Get IP6VTI tunnel local address.
Definition: ip6vti.c:458
int rtnl_link_ip6vti_set_link(struct rtnl_link *link, uint32_t index)
Set IP6VTI tunnel interface index.
Definition: ip6vti.c:322
int rtnl_link_ip6vti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
Get IP6VTI tunnel fwmark.
Definition: ip6vti.c:536
int rtnl_link_ip6vti_set_remote(struct rtnl_link *link, struct in6_addr *remote)
Set IP6VTI tunnel remote address.
Definition: ip6vti.c:478
int rtnl_link_ip6vti_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
Set IP6VTI tunnel fwmark.
Definition: ip6vti.c:517
int rtnl_link_is_ip6vti(struct rtnl_link *link)
Check if link is a IP6VTI link.
Definition: ip6vti.c:286
int rtnl_link_ip6vti_set_local(struct rtnl_link *link, struct in6_addr *local)
Set IP6VTI tunnel local address.
Definition: ip6vti.c:439
int rtnl_link_ip6vti_set_okey(struct rtnl_link *link, uint32_t okey)
Set IP6VTI tunnel set okey.
Definition: ip6vti.c:400
int rtnl_link_ip6vti_get_remote(struct rtnl_link *link, struct in6_addr *remote)
Get IP6VTI tunnel remote address.
Definition: ip6vti.c:497
int rtnl_link_ip6vti_get_okey(struct rtnl_link *link, uint32_t *okey)
Get IP6VTI tunnel okey.
Definition: ip6vti.c:419
int rtnl_link_ip6vti_set_ikey(struct rtnl_link *link, uint32_t ikey)
Set IP6VTI tunnel set ikey.
Definition: ip6vti.c:361
int rtnl_link_ip6vti_get_ikey(struct rtnl_link *link, uint32_t *ikey)
Get IP6VTI tunnel ikey.
Definition: ip6vti.c:380
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