libnl  3.7.0
ipvti.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2014 Susant Sahani <susant@redhat.com>
4  */
5 
6 /**
7  * @ingroup link
8  * @defgroup ipvti IPVTI
9  * ipvti link module
10  *
11  * @details
12  * \b Link Type Name: "ipvti"
13  *
14  * @route_doc{link_ipvti, IPVTI Documentation}
15  *
16  * @{
17  */
18 
19 #include <netlink-private/netlink.h>
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/ipvti.h>
26 #include <netlink-private/route/link/api.h>
27 #include <linux/if_tunnel.h>
28 
29 #define IPVTI_ATTR_LINK (1 << 0)
30 #define IPVTI_ATTR_IKEY (1 << 1)
31 #define IPVTI_ATTR_OKEY (1 << 2)
32 #define IPVTI_ATTR_LOCAL (1 << 3)
33 #define IPVTI_ATTR_REMOTE (1 << 4)
34 #define IPVTI_ATTR_FWMARK (1 << 5)
35 
36 struct ipvti_info
37 {
38  uint32_t link;
39  uint32_t ikey;
40  uint32_t okey;
41  uint32_t local;
42  uint32_t remote;
43  uint32_t fwmark;
44  uint32_t ipvti_mask;
45 };
46 
47 static struct nla_policy ipvti_policy[IFLA_VTI_MAX + 1] = {
48  [IFLA_VTI_LINK] = { .type = NLA_U32 },
49  [IFLA_VTI_IKEY] = { .type = NLA_U32 },
50  [IFLA_VTI_OKEY] = { .type = NLA_U32 },
51  [IFLA_VTI_LOCAL] = { .type = NLA_U32 },
52  [IFLA_VTI_REMOTE] = { .type = NLA_U32 },
53  [IFLA_VTI_FWMARK] = { .type = NLA_U32 },
54 };
55 
56 static int ipvti_alloc(struct rtnl_link *link)
57 {
58  struct ipvti_info *ipvti;
59 
60  if (link->l_info)
61  memset(link->l_info, 0, sizeof(*ipvti));
62  else {
63  ipvti = calloc(1, sizeof(*ipvti));
64  if (!ipvti)
65  return -NLE_NOMEM;
66 
67  link->l_info = ipvti;
68  }
69 
70  return 0;
71 }
72 
73 static int ipvti_parse(struct rtnl_link *link, struct nlattr *data,
74  struct nlattr *xstats)
75 {
76  struct nlattr *tb[IFLA_VTI_MAX + 1];
77  struct ipvti_info *ipvti;
78  int err;
79 
80  NL_DBG(3, "Parsing IPVTI link info\n");
81 
82  err = nla_parse_nested(tb, IFLA_VTI_MAX, data, ipvti_policy);
83  if (err < 0)
84  goto errout;
85 
86  err = ipvti_alloc(link);
87  if (err < 0)
88  goto errout;
89 
90  ipvti = link->l_info;
91 
92  if (tb[IFLA_VTI_LINK]) {
93  ipvti->link = nla_get_u32(tb[IFLA_VTI_LINK]);
94  ipvti->ipvti_mask |= IPVTI_ATTR_LINK;
95  }
96 
97  if (tb[IFLA_VTI_IKEY]) {
98  ipvti->ikey = nla_get_u32(tb[IFLA_VTI_IKEY]);
99  ipvti->ipvti_mask |= IPVTI_ATTR_IKEY;
100  }
101 
102  if (tb[IFLA_VTI_OKEY]) {
103  ipvti->okey = nla_get_u32(tb[IFLA_VTI_OKEY]);
104  ipvti->ipvti_mask |= IPVTI_ATTR_OKEY;
105  }
106 
107  if (tb[IFLA_VTI_LOCAL]) {
108  ipvti->local = nla_get_u32(tb[IFLA_VTI_LOCAL]);
109  ipvti->ipvti_mask |= IPVTI_ATTR_LOCAL;
110  }
111 
112  if (tb[IFLA_VTI_REMOTE]) {
113  ipvti->remote = nla_get_u32(tb[IFLA_VTI_REMOTE]);
114  ipvti->ipvti_mask |= IPVTI_ATTR_REMOTE;
115  }
116 
117  if (tb[IFLA_VTI_FWMARK]) {
118  ipvti->fwmark = nla_get_u32(tb[IFLA_VTI_FWMARK]);
119  ipvti->ipvti_mask |= IPVTI_ATTR_FWMARK;
120  }
121 
122  err = 0;
123 
124 errout:
125  return err;
126 }
127 
128 static int ipvti_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
129 {
130  struct ipvti_info *ipvti = link->l_info;
131  struct nlattr *data;
132 
133  data = nla_nest_start(msg, IFLA_INFO_DATA);
134  if (!data)
135  return -NLE_MSGSIZE;
136 
137  if (ipvti->ipvti_mask & IPVTI_ATTR_LINK)
138  NLA_PUT_U32(msg, IFLA_VTI_LINK, ipvti->link);
139 
140  if (ipvti->ipvti_mask & IPVTI_ATTR_IKEY)
141  NLA_PUT_U32(msg, IFLA_VTI_IKEY, ipvti->ikey);
142 
143  if (ipvti->ipvti_mask & IFLA_VTI_IKEY)
144  NLA_PUT_U32(msg, IFLA_VTI_OKEY, ipvti->okey);
145 
146  if (ipvti->ipvti_mask & IPVTI_ATTR_LOCAL)
147  NLA_PUT_U32(msg, IFLA_VTI_LOCAL, ipvti->local);
148 
149  if (ipvti->ipvti_mask & IPVTI_ATTR_REMOTE)
150  NLA_PUT_U32(msg, IFLA_VTI_REMOTE, ipvti->remote);
151 
152  if (ipvti->ipvti_mask & IPVTI_ATTR_FWMARK)
153  NLA_PUT_U32(msg, IFLA_VTI_FWMARK, ipvti->fwmark);
154 
155  nla_nest_end(msg, data);
156 
157 nla_put_failure:
158 
159  return 0;
160 }
161 
162 static void ipvti_free(struct rtnl_link *link)
163 {
164  struct ipvti_info *ipvti = link->l_info;
165 
166  free(ipvti);
167  link->l_info = NULL;
168 }
169 
170 static void ipvti_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
171 {
172  nl_dump(p, "ipvti : %s", link->l_name);
173 }
174 
175 static void ipvti_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
176 {
177  struct ipvti_info *ipvti = link->l_info;
178  char *name, addr[INET_ADDRSTRLEN];
179  struct rtnl_link *parent;
180 
181  if (ipvti->ipvti_mask & IPVTI_ATTR_LINK) {
182  nl_dump(p, " link ");
183 
184  name = NULL;
185  parent = link_lookup(link->ce_cache, ipvti->link);
186  if (parent)
187  name = rtnl_link_get_name(parent);
188 
189  if (name)
190  nl_dump_line(p, "%s\n", name);
191  else
192  nl_dump_line(p, "%u\n", ipvti->link);
193  }
194 
195  if (ipvti->ipvti_mask & IPVTI_ATTR_IKEY) {
196  nl_dump(p, " ikey ");
197  nl_dump_line(p, "%x\n",ipvti->ikey);
198  }
199 
200  if (ipvti->ipvti_mask & IPVTI_ATTR_OKEY) {
201  nl_dump(p, " okey ");
202  nl_dump_line(p, "%x\n", ipvti->okey);
203  }
204 
205  if (ipvti->ipvti_mask & IPVTI_ATTR_LOCAL) {
206  nl_dump(p, " local ");
207  if(inet_ntop(AF_INET, &ipvti->local, addr, sizeof(addr)))
208  nl_dump_line(p, "%s\n", addr);
209  else
210  nl_dump_line(p, "%#x\n", ntohs(ipvti->local));
211  }
212 
213  if (ipvti->ipvti_mask & IPVTI_ATTR_REMOTE) {
214  nl_dump(p, " remote ");
215  if(inet_ntop(AF_INET, &ipvti->remote, addr, sizeof(addr)))
216  nl_dump_line(p, "%s\n", addr);
217  else
218  nl_dump_line(p, "%#x\n", ntohs(ipvti->remote));
219  }
220 
221  if (ipvti->ipvti_mask & IPVTI_ATTR_FWMARK) {
222  nl_dump(p, " fwmark ");
223  nl_dump_line(p, "%x\n", ipvti->fwmark);
224  }
225 }
226 
227 static int ipvti_clone(struct rtnl_link *dst, struct rtnl_link *src)
228 {
229  struct ipvti_info *ipvti_dst, *ipvti_src = src->l_info;
230  int err;
231 
232  dst->l_info = NULL;
233 
234  err = rtnl_link_set_type(dst, "vti");
235  if (err < 0)
236  return err;
237 
238  ipvti_dst = dst->l_info;
239 
240  if (!ipvti_dst || !ipvti_src)
241  BUG();
242 
243  memcpy(ipvti_dst, ipvti_src, sizeof(struct ipvti_info));
244 
245  return 0;
246 }
247 
248 static struct rtnl_link_info_ops ipvti_info_ops = {
249  .io_name = "vti",
250  .io_alloc = ipvti_alloc,
251  .io_parse = ipvti_parse,
252  .io_dump = {
253  [NL_DUMP_LINE] = ipvti_dump_line,
254  [NL_DUMP_DETAILS] = ipvti_dump_details,
255  },
256  .io_clone = ipvti_clone,
257  .io_put_attrs = ipvti_put_attrs,
258  .io_free = ipvti_free,
259 };
260 
261 #define IS_IPVTI_LINK_ASSERT(link) \
262  if ((link)->l_info_ops != &ipvti_info_ops) { \
263  APPBUG("Link is not a ipvti link. set type \vti\" first."); \
264  return -NLE_OPNOTSUPP; \
265  }
266 
267 struct rtnl_link *rtnl_link_ipvti_alloc(void)
268 {
269  struct rtnl_link *link;
270  int err;
271 
272  link = rtnl_link_alloc();
273  if (!link)
274  return NULL;
275 
276  err = rtnl_link_set_type(link, "vti");
277  if (err < 0) {
278  rtnl_link_put(link);
279  return NULL;
280  }
281 
282  return link;
283 }
284 
285 /**
286  * Check if link is a IPVTI link
287  * @arg link Link object
288  *
289  * @return True if link is a IPVTI link, otherwise 0 is returned.
290  */
291 int rtnl_link_is_ipvti(struct rtnl_link *link)
292 {
293  return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vti");
294 }
295 /**
296  * Create a new ipvti tunnel device
297  * @arg sock netlink socket
298  * @arg name name of the tunnel deviceL
299  *
300  * Creates a new ipvti tunnel device in the kernel
301  * @return 0 on success or a negative error code
302  */
303 int rtnl_link_ipvti_add(struct nl_sock *sk, const char *name)
304 {
305  struct rtnl_link *link;
306  int err;
307 
308  link = rtnl_link_ipvti_alloc();
309  if (!link)
310  return -NLE_NOMEM;
311 
312  if(name)
313  rtnl_link_set_name(link, name);
314 
315  err = rtnl_link_add(sk, link, NLM_F_CREATE);
316  rtnl_link_put(link);
317 
318  return err;
319 }
320 /**
321  * Set IPVTI tunnel interface index
322  * @arg link Link object
323  * @arg index interface index
324  *
325  * @return 0 on success or a negative error code
326  */
327 int rtnl_link_ipvti_set_link(struct rtnl_link *link, uint32_t index)
328 {
329  struct ipvti_info *ipvti = link->l_info;
330 
331  IS_IPVTI_LINK_ASSERT(link);
332 
333  ipvti->link = index;
334  ipvti->ipvti_mask |= IPVTI_ATTR_LINK;
335 
336  return 0;
337 }
338 
339 /**
340  * Get IPVTI tunnel interface index
341  * @arg link Link object
342  *
343  * @return interface index
344  */
345 uint32_t rtnl_link_ipvti_get_link(struct rtnl_link *link)
346 {
347  struct ipvti_info *ipvti = link->l_info;
348 
349  IS_IPVTI_LINK_ASSERT(link);
350 
351  return ipvti->link;
352 }
353 
354 /**
355  * Set IPVTI 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_ipvti_set_ikey(struct rtnl_link *link, uint32_t ikey)
362 {
363  struct ipvti_info *ipvti = link->l_info;
364 
365  IS_IPVTI_LINK_ASSERT(link);
366 
367  ipvti->ikey = ikey;
368  ipvti->ipvti_mask |= IPVTI_ATTR_IKEY;
369 
370  return 0;
371 }
372 
373 /**
374  * Get IPVTI tunnel ikey
375  * @arg link Link object
376  *
377  * @return ikey
378  */
379 uint32_t rtnl_link_ipvti_get_ikey(struct rtnl_link *link)
380 {
381  struct ipvti_info *ipvti = link->l_info;
382 
383  IS_IPVTI_LINK_ASSERT(link);
384 
385  return ipvti->ikey;
386 }
387 
388 /**
389  * Set IPVTI tunnel set okey
390  * @arg link Link object
391  * @arg okey gre okey
392  *
393  * @return 0 on success or a negative error code
394  */
395 int rtnl_link_ipvti_set_okey(struct rtnl_link *link, uint32_t okey)
396 {
397  struct ipvti_info *ipvti = link->l_info;
398 
399  IS_IPVTI_LINK_ASSERT(link);
400 
401  ipvti->okey = okey;
402  ipvti->ipvti_mask |= IPVTI_ATTR_OKEY;
403 
404  return 0;
405 }
406 
407 /**
408  * Get IPVTI tunnel okey
409  * @arg link Link object
410  *
411  * @return okey value
412  */
413 uint32_t rtnl_link_ipvti_get_okey(struct rtnl_link *link)
414 {
415  struct ipvti_info *ipvti = link->l_info;
416 
417  IS_IPVTI_LINK_ASSERT(link);
418 
419  return ipvti->okey;
420 }
421 
422 /**
423  * Set IPVTI tunnel local address
424  * @arg link Link object
425  * @arg addr local address
426  *
427  * @return 0 on success or a negative error code
428  */
429 int rtnl_link_ipvti_set_local(struct rtnl_link *link, uint32_t addr)
430 {
431  struct ipvti_info *ipvti = link->l_info;
432 
433  IS_IPVTI_LINK_ASSERT(link);
434 
435  ipvti->local = addr;
436  ipvti->ipvti_mask |= IPVTI_ATTR_LOCAL;
437 
438  return 0;
439 }
440 
441 /**
442  * Get IPVTI tunnel local address
443  * @arg link Link object
444  *
445  * @return local address
446  */
447 uint32_t rtnl_link_ipvti_get_local(struct rtnl_link *link)
448 {
449  struct ipvti_info *ipvti = link->l_info;
450 
451  IS_IPVTI_LINK_ASSERT(link);
452 
453  return ipvti->local;
454 }
455 
456 /**
457  * Set IPVTI tunnel remote address
458  * @arg link Link object
459  * @arg remote remote address
460  *
461  * @return 0 on success or a negative error code
462  */
463 int rtnl_link_ipvti_set_remote(struct rtnl_link *link, uint32_t remote)
464 {
465  struct ipvti_info *ipvti = link->l_info;
466 
467  IS_IPVTI_LINK_ASSERT(link);
468 
469  ipvti->remote = remote;
470  ipvti->ipvti_mask |= IPVTI_ATTR_REMOTE;
471 
472  return 0;
473 }
474 
475 /**
476  * Get IPVTI tunnel remote address
477  * @arg link Link object
478  *
479  * @return remote address on success or a negative error code
480  */
481 uint32_t rtnl_link_ipvti_get_remote(struct rtnl_link *link)
482 {
483  struct ipvti_info *ipvti = link->l_info;
484 
485  IS_IPVTI_LINK_ASSERT(link);
486 
487  return ipvti->remote;
488 }
489 
490 /**
491  * Set IPVTI tunnel fwmark
492  * @arg link Link object
493  * @arg fwmark fwmark
494  *
495  * @return 0 on success or a negative error code
496  */
497 int rtnl_link_ipvti_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
498 {
499  struct ipvti_info *ipvti = link->l_info;
500 
501  IS_IPVTI_LINK_ASSERT(link);
502 
503  ipvti->fwmark = fwmark;
504  ipvti->ipvti_mask |= IPVTI_ATTR_FWMARK;
505 
506  return 0;
507 }
508 
509 /**
510  * Get IPVTI tunnel fwmark
511  * @arg link Link object
512  * @arg fwmark addr to fill in with the fwmark
513  *
514  * @return 0 on success or a negative error code
515  */
516 int rtnl_link_ipvti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
517 {
518  struct ipvti_info *ipvti = link->l_info;
519 
520  IS_IPVTI_LINK_ASSERT(link);
521 
522  if (!(ipvti->ipvti_mask & IPVTI_ATTR_FWMARK))
523  return -NLE_NOATTR;
524 
525  *fwmark = ipvti->fwmark;
526 
527  return 0;
528 }
529 
530 static void __init ipvti_init(void)
531 {
532  rtnl_link_register_info(&ipvti_info_ops);
533 }
534 
535 static void __exit ipvti_exit(void)
536 {
537  rtnl_link_unregister_info(&ipvti_info_ops);
538 }
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition: attr.c:699
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition: attr.h:230
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_ipvti_set_ikey(struct rtnl_link *link, uint32_t ikey)
Set IPVTI tunnel set ikey.
Definition: ipvti.c:361
uint32_t rtnl_link_ipvti_get_ikey(struct rtnl_link *link)
Get IPVTI tunnel ikey.
Definition: ipvti.c:379
int rtnl_link_ipvti_set_local(struct rtnl_link *link, uint32_t addr)
Set IPVTI tunnel local address.
Definition: ipvti.c:429
int rtnl_link_ipvti_set_remote(struct rtnl_link *link, uint32_t remote)
Set IPVTI tunnel remote address.
Definition: ipvti.c:463
int rtnl_link_ipvti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
Get IPVTI tunnel fwmark.
Definition: ipvti.c:516
uint32_t rtnl_link_ipvti_get_local(struct rtnl_link *link)
Get IPVTI tunnel local address.
Definition: ipvti.c:447
int rtnl_link_ipvti_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
Set IPVTI tunnel fwmark.
Definition: ipvti.c:497
int rtnl_link_ipvti_set_okey(struct rtnl_link *link, uint32_t okey)
Set IPVTI tunnel set okey.
Definition: ipvti.c:395
int rtnl_link_is_ipvti(struct rtnl_link *link)
Check if link is a IPVTI link.
Definition: ipvti.c:291
uint32_t rtnl_link_ipvti_get_link(struct rtnl_link *link)
Get IPVTI tunnel interface index.
Definition: ipvti.c:345
uint32_t rtnl_link_ipvti_get_remote(struct rtnl_link *link)
Get IPVTI tunnel remote address.
Definition: ipvti.c:481
int rtnl_link_ipvti_set_link(struct rtnl_link *link, uint32_t index)
Set IPVTI tunnel interface index.
Definition: ipvti.c:327
uint32_t rtnl_link_ipvti_get_okey(struct rtnl_link *link)
Get IPVTI tunnel okey.
Definition: ipvti.c:413
int rtnl_link_ipvti_add(struct nl_sock *sk, const char *name)
Create a new ipvti tunnel device.
Definition: ipvti.c:303
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