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 
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;
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 
215 static 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 
236 static 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 
259 struct 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  */
295 int 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  */
319 int 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  */
338 int 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  */
358 int 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  */
377 int 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  */
397 int 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  */
416 int 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  */
436 int 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  */
455 int 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  */
475 int 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  */
494 int 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  */
514 int 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  */
533 int 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 
546 static void __init ip6vti_init(void)
547 {
548  rtnl_link_register_info(&ip6vti_info_ops);
549 }
550 
551 static 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: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: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