libnl  3.2.28
macvlan.c
1 /*
2  * lib/route/link/macvlan.c MACVLAN Link Info
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2013 Michael Braun <michael-dev@fami-braun.de>
10  */
11 
12 /**
13  * @ingroup link
14  * @defgroup macvlan MACVLAN/MACVTAP
15  * MAC-based Virtual LAN link module
16  *
17  * @details
18  * \b Link Type Name: "macvlan"
19  *
20  * @route_doc{link_macvlan, MACVLAN Documentation}
21  * @route_doc{link_macvtap, MACVTAP Documentation}
22  *
23  * @{
24  */
25 
26 #include <netlink-private/netlink.h>
27 #include <netlink/netlink.h>
28 #include <netlink/attr.h>
29 #include <netlink/utils.h>
30 #include <netlink/object.h>
31 #include <netlink/route/rtnl.h>
32 #include <netlink-private/route/link/api.h>
33 #include <netlink/route/link/macvlan.h>
34 #include <netlink/route/link/macvtap.h>
35 
36 #include <linux/if_link.h>
37 
38 /** @cond SKIP */
39 #define MACVLAN_HAS_MODE (1<<0)
40 #define MACVLAN_HAS_FLAGS (1<<1)
41 
42 struct macvlan_info
43 {
44  uint32_t mvi_mode;
45  uint16_t mvi_flags; // there currently is only one flag and kernel has no flags_mask yet
46  uint32_t mvi_mask;
47 };
48 
49 /** @endcond */
50 
51 static struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX+1] = {
52  [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
53  [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
54 };
55 
56 static int macvlan_alloc(struct rtnl_link *link)
57 {
58  struct macvlan_info *mvi;
59 
60  if (link->l_info)
61  memset(link->l_info, 0, sizeof(*mvi));
62  else {
63  if ((mvi = calloc(1, sizeof(*mvi))) == NULL)
64  return -NLE_NOMEM;
65 
66  link->l_info = mvi;
67  }
68 
69  return 0;
70 }
71 
72 static int macvlan_parse(struct rtnl_link *link, struct nlattr *data,
73  struct nlattr *xstats)
74 {
75  struct nlattr *tb[IFLA_MACVLAN_MAX+1];
76  struct macvlan_info *mvi;
77  int err;
78 
79  NL_DBG(3, "Parsing %s link info", link->l_info_ops->io_name);
80 
81  if ((err = nla_parse_nested(tb, IFLA_MACVLAN_MAX, data, macvlan_policy)) < 0)
82  goto errout;
83 
84  if ((err = macvlan_alloc(link)) < 0)
85  goto errout;
86 
87  mvi = link->l_info;
88 
89  if (tb[IFLA_MACVLAN_MODE]) {
90  mvi->mvi_mode = nla_get_u32(tb[IFLA_MACVLAN_MODE]);
91  mvi->mvi_mask |= MACVLAN_HAS_MODE;
92  }
93 
94  if (tb[IFLA_MACVLAN_FLAGS]) {
95  mvi->mvi_mode = nla_get_u16(tb[IFLA_MACVLAN_FLAGS]);
96  mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
97  }
98 
99  err = 0;
100 errout:
101  return err;
102 }
103 
104 static void macvlan_free(struct rtnl_link *link)
105 {
106  free(link->l_info);
107  link->l_info = NULL;
108 }
109 
110 static void macvlan_dump(struct rtnl_link *link, struct nl_dump_params *p)
111 {
112  char buf[64];
113  struct macvlan_info *mvi = link->l_info;
114 
115  if (mvi->mvi_mask & MACVLAN_HAS_MODE) {
116  rtnl_link_macvlan_mode2str(mvi->mvi_mode, buf, sizeof(buf));
117  nl_dump(p, "%s-mode %s", link->l_info_ops->io_name, buf);
118  }
119 
120  if (mvi->mvi_mask & MACVLAN_HAS_FLAGS) {
121  rtnl_link_macvlan_flags2str(mvi->mvi_flags, buf, sizeof(buf));
122  nl_dump(p, "%s-flags %s", link->l_info_ops->io_name, buf);
123  }
124 }
125 
126 static int macvlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
127 {
128  struct macvlan_info *vdst, *vsrc = src->l_info;
129  int err;
130 
131  dst->l_info = NULL;
132  if ((err = rtnl_link_set_type(dst, "macvlan")) < 0)
133  return err;
134  vdst = dst->l_info;
135 
136  if (!vdst || !vsrc)
137  return -NLE_NOMEM;
138 
139  memcpy(vdst, vsrc, sizeof(struct macvlan_info));
140 
141  return 0;
142 }
143 
144 static int macvlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
145 {
146  struct macvlan_info *mvi = link->l_info;
147  struct nlattr *data;
148 
149  if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
150  return -NLE_MSGSIZE;
151 
152  if (mvi->mvi_mask & MACVLAN_HAS_MODE)
153  NLA_PUT_U32(msg, IFLA_MACVLAN_MODE, mvi->mvi_mode);
154 
155  if (mvi->mvi_mask & MACVLAN_HAS_FLAGS)
156  NLA_PUT_U16(msg, IFLA_MACVLAN_FLAGS, mvi->mvi_flags);
157 
158  nla_nest_end(msg, data);
159 
160 nla_put_failure:
161 
162  return 0;
163 }
164 
165 static struct rtnl_link_info_ops macvlan_info_ops = {
166  .io_name = "macvlan",
167  .io_alloc = macvlan_alloc,
168  .io_parse = macvlan_parse,
169  .io_dump = {
170  [NL_DUMP_LINE] = macvlan_dump,
171  [NL_DUMP_DETAILS] = macvlan_dump,
172  },
173  .io_clone = macvlan_clone,
174  .io_put_attrs = macvlan_put_attrs,
175  .io_free = macvlan_free,
176 };
177 
178 static struct rtnl_link_info_ops macvtap_info_ops = {
179  .io_name = "macvtap",
180  .io_alloc = macvlan_alloc,
181  .io_parse = macvlan_parse,
182  .io_dump = {
183  [NL_DUMP_LINE] = macvlan_dump,
184  [NL_DUMP_DETAILS] = macvlan_dump,
185  },
186  .io_clone = macvlan_clone,
187  .io_put_attrs = macvlan_put_attrs,
188  .io_free = macvlan_free,
189 };
190 
191 /** @cond SKIP */
192 #define IS_MACVLAN_LINK_ASSERT(link) \
193  if ((link)->l_info_ops != &macvlan_info_ops) { \
194  APPBUG("Link is not a macvlan link. set type \"macvlan\" first."); \
195  return -NLE_OPNOTSUPP; \
196  }
197 
198 #define IS_MACVTAP_LINK_ASSERT(link) \
199  if ((link)->l_info_ops != &macvtap_info_ops) { \
200  APPBUG("Link is not a macvtap link. set type \"macvtap\" first."); \
201  return -NLE_OPNOTSUPP; \
202  }
203 /** @endcond */
204 
205 /**
206  * @name MACVLAN Object
207  * @{
208  */
209 
210 /**
211  * Allocate link object of type MACVLAN
212  *
213  * @return Allocated link object or NULL.
214  */
216 {
217  struct rtnl_link *link;
218  int err;
219 
220  if (!(link = rtnl_link_alloc()))
221  return NULL;
222 
223  if ((err = rtnl_link_set_type(link, "macvlan")) < 0) {
224  rtnl_link_put(link);
225  return NULL;
226  }
227 
228  return link;
229 }
230 
231 /**
232  * Check if link is a MACVLAN link
233  * @arg link Link object
234  *
235  * @return True if link is a MACVLAN link, otherwise false is returned.
236  */
238 {
239  return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "macvlan");
240 }
241 
242 /**
243  * Set MACVLAN MODE
244  * @arg link Link object
245  * @arg mode MACVLAN mode
246  *
247  * @return 0 on success or a negative error code
248  */
249 int rtnl_link_macvlan_set_mode(struct rtnl_link *link, uint32_t mode)
250 {
251  struct macvlan_info *mvi = link->l_info;
252 
253  IS_MACVLAN_LINK_ASSERT(link);
254 
255  mvi->mvi_mode = mode;
256  mvi->mvi_mask |= MACVLAN_HAS_MODE;
257 
258  return 0;
259 }
260 
261 /**
262  * Get MACVLAN Mode
263  * @arg link Link object
264  *
265  * @return MACVLAN mode, 0 if not set or a negative error code.
266  */
267 uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *link)
268 {
269  struct macvlan_info *mvi = link->l_info;
270 
271  IS_MACVLAN_LINK_ASSERT(link);
272 
273  if (mvi->mvi_mask & MACVLAN_HAS_MODE)
274  return mvi->mvi_mode;
275  else
276  return 0;
277 }
278 
279 /**
280  * Set MACVLAN flags
281  * @arg link Link object
282  * @arg flags MACVLAN flags
283  *
284  * @return 0 on success or a negative error code.
285  */
286 int rtnl_link_macvlan_set_flags(struct rtnl_link *link, uint16_t flags)
287 {
288  struct macvlan_info *mvi = link->l_info;
289 
290  IS_MACVLAN_LINK_ASSERT(link);
291 
292  mvi->mvi_flags |= flags;
293  mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
294 
295  return 0;
296 }
297 
298 /**
299  * Unset MACVLAN flags
300  * @arg link Link object
301  * @arg flags MACVLAN flags
302  *
303  * Note: kernel currently only has a single flag and lacks flags_mask to
304  * indicate which flags shall be changed (it always all).
305  *
306  * @return 0 on success or a negative error code.
307  */
308 int rtnl_link_macvlan_unset_flags(struct rtnl_link *link, uint16_t flags)
309 {
310  struct macvlan_info *mvi = link->l_info;
311 
312  IS_MACVLAN_LINK_ASSERT(link);
313 
314  mvi->mvi_flags &= ~flags;
315  mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
316 
317  return 0;
318 }
319 
320 /**
321  * Get MACVLAN flags
322  * @arg link Link object
323  *
324  * @return MACVLAN flags, 0 if none set, or a negative error code.
325  */
327 {
328  struct macvlan_info *mvi = link->l_info;
329 
330  IS_MACVLAN_LINK_ASSERT(link);
331 
332  return mvi->mvi_flags;
333 }
334 
335 /** @} */
336 
337 
338 /**
339  * @name MACVTAP Object
340  * @{
341  */
342 
343 /**
344  * Allocate link object of type MACVTAP
345  *
346  * @return Allocated link object or NULL.
347  */
349 {
350  struct rtnl_link *link;
351  int err;
352 
353  if (!(link = rtnl_link_alloc()))
354  return NULL;
355 
356  if ((err = rtnl_link_set_type(link, "macvtap")) < 0) {
357  rtnl_link_put(link);
358  return NULL;
359  }
360 
361  return link;
362 }
363 
364 /**
365  * Check if link is a MACVTAP link
366  * @arg link Link object
367  *
368  * @return True if link is a MACVTAP link, otherwise false is returned.
369  */
371 {
372  return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "macvtap");
373 }
374 
375 /**
376  * Set MACVTAP MODE
377  * @arg link Link object
378  * @arg mode MACVTAP mode
379  *
380  * @return 0 on success or a negative error code
381  */
382 int rtnl_link_macvtap_set_mode(struct rtnl_link *link, uint32_t mode)
383 {
384  struct macvlan_info *mvi = link->l_info;
385 
386  IS_MACVTAP_LINK_ASSERT(link);
387 
388  mvi->mvi_mode = mode;
389  mvi->mvi_mask |= MACVLAN_HAS_MODE;
390 
391  return 0;
392 }
393 
394 /**
395  * Get MACVTAP Mode
396  * @arg link Link object
397  *
398  * @return MACVTAP mode, 0 if not set or a negative error code.
399  */
400 uint32_t rtnl_link_macvtap_get_mode(struct rtnl_link *link)
401 {
402  struct macvlan_info *mvi = link->l_info;
403 
404  IS_MACVTAP_LINK_ASSERT(link);
405 
406  if (mvi->mvi_mask & MACVLAN_HAS_MODE)
407  return mvi->mvi_mode;
408  else
409  return 0;
410 }
411 
412 /**
413  * Set MACVTAP flags
414  * @arg link Link object
415  * @arg flags MACVTAP flags
416  *
417  * @return 0 on success or a negative error code.
418  */
419 int rtnl_link_macvtap_set_flags(struct rtnl_link *link, uint16_t flags)
420 {
421  struct macvlan_info *mvi = link->l_info;
422 
423  IS_MACVTAP_LINK_ASSERT(link);
424 
425  mvi->mvi_flags |= flags;
426  mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
427 
428  return 0;
429 }
430 
431 /**
432  * Unset MACVTAP flags
433  * @arg link Link object
434  * @arg flags MACVTAP flags
435  *
436  * Note: kernel currently only has a single flag and lacks flags_mask to
437  * indicate which flags shall be changed (it always all).
438  *
439  * @return 0 on success or a negative error code.
440  */
441 int rtnl_link_macvtap_unset_flags(struct rtnl_link *link, uint16_t flags)
442 {
443  struct macvlan_info *mvi = link->l_info;
444 
445  IS_MACVTAP_LINK_ASSERT(link);
446 
447  mvi->mvi_flags &= ~flags;
448  mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
449 
450  return 0;
451 }
452 
453 /**
454  * Get MACVTAP flags
455  * @arg link Link object
456  *
457  * @return MACVTAP flags, 0 if none set, or a negative error code.
458  */
460 {
461  struct macvlan_info *mvi = link->l_info;
462 
463  IS_MACVTAP_LINK_ASSERT(link);
464 
465  return mvi->mvi_flags;
466 }
467 
468 /** @} */
469 
470 
471 static const struct trans_tbl macvlan_flags[] = {
472  __ADD(MACVLAN_FLAG_NOPROMISC, nopromisc),
473 };
474 
475 static const struct trans_tbl macvlan_modes[] = {
476  __ADD(MACVLAN_MODE_PRIVATE, private),
477  __ADD(MACVLAN_MODE_VEPA, vepa),
478  __ADD(MACVLAN_MODE_BRIDGE, bridge),
479  __ADD(MACVLAN_MODE_PASSTHRU, passthru),
480 };
481 
482 /**
483  * @name Flag Translation
484  * @{
485  */
486 
487 char *rtnl_link_macvlan_flags2str(int flags, char *buf, size_t len)
488 {
489  return __flags2str(flags, buf, len, macvlan_flags, ARRAY_SIZE(macvlan_flags));
490 }
491 
492 int rtnl_link_macvlan_str2flags(const char *name)
493 {
494  return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
495 }
496 
497 char *rtnl_link_macvtap_flags2str(int flags, char *buf, size_t len)
498 {
499  return __flags2str(flags, buf, len, macvlan_flags, ARRAY_SIZE(macvlan_flags));
500 }
501 
502 int rtnl_link_macvtap_str2flags(const char *name)
503 {
504  return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
505 }
506 
507 /** @} */
508 
509 /**
510  * @name Mode Translation
511  * @{
512  */
513 
514 char *rtnl_link_macvlan_mode2str(int mode, char *buf, size_t len)
515 {
516  return __type2str(mode, buf, len, macvlan_modes, ARRAY_SIZE(macvlan_modes));
517 }
518 
519 int rtnl_link_macvlan_str2mode(const char *name)
520 {
521  return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
522 }
523 
524 char *rtnl_link_macvtap_mode2str(int mode, char *buf, size_t len)
525 {
526  return __type2str(mode, buf, len, macvlan_modes, ARRAY_SIZE(macvlan_modes));
527 }
528 
529 int rtnl_link_macvtap_str2mode(const char *name)
530 {
531  return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
532 }
533 
534 /** @} */
535 
536 static void __init macvlan_init(void)
537 {
538  rtnl_link_register_info(&macvlan_info_ops);
539  rtnl_link_register_info(&macvtap_info_ops);
540 }
541 
542 static void __exit macvlan_exit(void)
543 {
544  rtnl_link_unregister_info(&macvlan_info_ops);
545  rtnl_link_unregister_info(&macvtap_info_ops);
546 }
547 
548 /** @} */
Dump object briefly on one line.
Definition: types.h:22
int rtnl_link_is_macvlan(struct rtnl_link *link)
Check if link is a MACVLAN link.
Definition: macvlan.c:237
int rtnl_link_macvlan_unset_flags(struct rtnl_link *link, uint16_t flags)
Unset MACVLAN flags.
Definition: macvlan.c:308
uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *link)
Get MACVLAN flags.
Definition: macvlan.c:326
Attribute validation policy.
Definition: attr.h:67
uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *link)
Get MACVLAN Mode.
Definition: macvlan.c:267
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition: attr.c:699
int rtnl_link_macvtap_unset_flags(struct rtnl_link *link, uint16_t flags)
Unset MACVTAP flags.
Definition: macvlan.c:441
Dump all attributes but no statistics.
Definition: types.h:23
int rtnl_link_is_macvtap(struct rtnl_link *link)
Check if link is a MACVTAP link.
Definition: macvlan.c:370
struct rtnl_link * rtnl_link_macvtap_alloc(void)
Allocate link object of type MACVTAP.
Definition: macvlan.c:348
int rtnl_link_macvlan_set_flags(struct rtnl_link *link, uint16_t flags)
Set MACVLAN flags.
Definition: macvlan.c:286
int rtnl_link_macvlan_set_mode(struct rtnl_link *link, uint32_t mode)
Set MACVLAN MODE.
Definition: macvlan.c:249
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:917
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition: attr.c:992
16 bit integer
Definition: attr.h:40
uint16_t rtnl_link_macvtap_get_flags(struct rtnl_link *link)
Get MACVTAP flags.
Definition: macvlan.c:459
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition: attr.h:233
int rtnl_link_macvtap_set_flags(struct rtnl_link *link, uint16_t flags)
Set MACVTAP flags.
Definition: macvlan.c:419
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:69
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition: attr.c:649
32 bit integer
Definition: attr.h:41
Dumping parameters.
Definition: types.h:33
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
Definition: attr.h:215
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:914
uint32_t rtnl_link_macvtap_get_mode(struct rtnl_link *link)
Get MACVTAP Mode.
Definition: macvlan.c:400
int rtnl_link_macvtap_set_mode(struct rtnl_link *link, uint32_t mode)
Set MACVTAP MODE.
Definition: macvlan.c:382
struct rtnl_link * rtnl_link_macvlan_alloc(void)
Allocate link object of type MACVLAN.
Definition: macvlan.c:215
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:895