1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2013 Michael Braun <[email protected]>
4 */
5
6 /**
7 * @ingroup link
8 * @defgroup macvlan MACVLAN/MACVTAP
9 * MAC-based Virtual LAN link module
10 *
11 * @details
12 * \b Link Type Name: "macvlan"
13 *
14 * @route_doc{link_macvlan, MACVLAN Documentation}
15 * @route_doc{link_macvtap, MACVTAP Documentation}
16 *
17 * @{
18 */
19
20 #include "nl-default.h"
21
22 #include <linux/if_link.h>
23
24 #include <linux/ethtool.h>
25
26 #include <netlink/netlink.h>
27 #include <netlink/attr.h>
28 #include <netlink/utils.h>
29 #include <netlink/object.h>
30 #include <netlink/route/rtnl.h>
31 #include <netlink/route/link/macvlan.h>
32 #include <netlink/route/link/macvtap.h>
33
34 #include "nl-route.h"
35 #include "link-api.h"
36
37 /** @cond SKIP */
38 #define MACVLAN_HAS_MODE (1<<0)
39 #define MACVLAN_HAS_FLAGS (1<<1)
40 #define MACVLAN_HAS_MACADDR (1<<2)
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 uint32_t mvi_maccount;
48 uint32_t mvi_macmode;
49 struct nl_addr **mvi_macaddr;
50 };
51
52 /** @endcond */
53
54 static struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX+1] = {
55 [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
56 [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
57 [IFLA_MACVLAN_MACADDR_MODE] = { .type = NLA_U32 },
58 [IFLA_MACVLAN_MACADDR] = { .type = NLA_UNSPEC },
59 [IFLA_MACVLAN_MACADDR_DATA] = { .type = NLA_NESTED },
60 [IFLA_MACVLAN_MACADDR_COUNT] = { .type = NLA_U32 },
61 };
62
macvlan_alloc(struct rtnl_link * link)63 static int macvlan_alloc(struct rtnl_link *link)
64 {
65 struct macvlan_info *mvi;
66 uint32_t i;
67
68 if (link->l_info) {
69 mvi = link->l_info;
70 for (i = 0; i < mvi->mvi_maccount; i++)
71 nl_addr_put(mvi->mvi_macaddr[i]);
72 free(mvi->mvi_macaddr);
73 memset(mvi, 0, sizeof(*mvi));
74 } else {
75 if ((mvi = calloc(1, sizeof(*mvi))) == NULL)
76 return -NLE_NOMEM;
77
78 link->l_info = mvi;
79 }
80 mvi->mvi_macmode = MACVLAN_MACADDR_SET;
81
82 return 0;
83 }
84
macvlan_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)85 static int macvlan_parse(struct rtnl_link *link, struct nlattr *data,
86 struct nlattr *xstats)
87 {
88 struct nlattr *tb[IFLA_MACVLAN_MAX+1];
89 struct macvlan_info *mvi;
90 struct nlattr *nla;
91 int len;
92 int err;
93
94 NL_DBG(3, "Parsing %s link info", link->l_info_ops->io_name);
95
96 if ((err = nla_parse_nested(tb, IFLA_MACVLAN_MAX, data, macvlan_policy)) < 0)
97 goto errout;
98
99 if ((err = macvlan_alloc(link)) < 0)
100 goto errout;
101
102 mvi = link->l_info;
103
104 if (tb[IFLA_MACVLAN_MODE]) {
105 mvi->mvi_mode = nla_get_u32(tb[IFLA_MACVLAN_MODE]);
106 mvi->mvi_mask |= MACVLAN_HAS_MODE;
107 }
108
109 if (tb[IFLA_MACVLAN_FLAGS]) {
110 mvi->mvi_flags = nla_get_u16(tb[IFLA_MACVLAN_FLAGS]);
111 mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
112 }
113
114 if ( tb[IFLA_MACVLAN_MACADDR_COUNT]
115 && tb[IFLA_MACVLAN_MACADDR_DATA]) {
116 mvi->mvi_maccount = nla_get_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]);
117 if (mvi->mvi_maccount > 0) {
118 uint32_t i;
119
120 nla = nla_data(tb[IFLA_MACVLAN_MACADDR_DATA]);
121 len = nla_len(tb[IFLA_MACVLAN_MACADDR_DATA]);
122
123 mvi->mvi_macaddr = calloc(mvi->mvi_maccount,
124 sizeof(*(mvi->mvi_macaddr)));
125 if (mvi->mvi_macaddr == NULL) {
126 err = -NLE_NOMEM;
127 goto errout;
128 }
129
130 i = 0;
131 for (; nla_ok(nla, len); nla = nla_next(nla, &len)) {
132 if (i >= mvi->mvi_maccount)
133 break;
134 if (nla_type(nla) != IFLA_MACVLAN_MACADDR ||
135 nla_len(nla) < ETH_ALEN)
136 continue;
137 mvi->mvi_macaddr[i] = nl_addr_alloc_attr(nla, AF_LLC);
138 i++;
139 }
140 }
141 mvi->mvi_mask |= MACVLAN_HAS_MACADDR;
142 }
143
144 err = 0;
145 errout:
146 return err;
147 }
148
macvlan_free(struct rtnl_link * link)149 static void macvlan_free(struct rtnl_link *link)
150 {
151 struct macvlan_info *mvi;
152 uint32_t i;
153
154 mvi = link->l_info;
155 if (!mvi)
156 return;
157
158 for (i = 0; i < mvi->mvi_maccount; i++)
159 nl_addr_put(mvi->mvi_macaddr[i]);
160 free(mvi->mvi_macaddr);
161 free(mvi);
162
163 link->l_info = NULL;
164 }
165
macvlan_dump_details(struct rtnl_link * link,struct nl_dump_params * p)166 static void macvlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
167 {
168 char buf[64];
169 uint32_t i;
170 struct macvlan_info *mvi = link->l_info;
171
172 if (mvi->mvi_mask & MACVLAN_HAS_MODE) {
173 rtnl_link_macvlan_mode2str(mvi->mvi_mode, buf, sizeof(buf));
174 nl_dump(p, " %s-mode %s", link->l_info_ops->io_name, buf);
175 }
176
177 if (mvi->mvi_mask & MACVLAN_HAS_FLAGS) {
178 rtnl_link_macvlan_flags2str(mvi->mvi_flags, buf, sizeof(buf));
179 nl_dump(p, " %s-flags %s", link->l_info_ops->io_name, buf);
180 }
181
182 if (mvi->mvi_mask & MACVLAN_HAS_MACADDR) {
183 nl_dump(p, " macvlan-count %u", (unsigned) mvi->mvi_maccount);
184
185 if (mvi->mvi_maccount)
186 nl_dump(p, " macvlan-sourcemac");
187
188 for (i = 0; i < mvi->mvi_maccount; i++) {
189 nl_dump(p, " %s", nl_addr2str(mvi->mvi_macaddr[i], buf,
190 sizeof(buf)));
191 }
192 }
193 nl_dump(p, "\n");
194 }
195
macvlan_clone(struct rtnl_link * dst,struct rtnl_link * src)196 static int macvlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
197 {
198 struct macvlan_info *vdst, *vsrc = src->l_info;
199 int err;
200 uint32_t i;
201
202 dst->l_info = NULL;
203 if ((err = rtnl_link_set_type(dst, "macvlan")) < 0)
204 return err;
205 vdst = dst->l_info;
206
207 if (!vdst || !vsrc)
208 return -NLE_NOMEM;
209
210 memcpy(vdst, vsrc, sizeof(struct macvlan_info));
211
212 if ( vsrc->mvi_mask & MACVLAN_HAS_MACADDR
213 && vsrc->mvi_maccount > 0) {
214 vdst->mvi_macaddr = calloc(vdst->mvi_maccount,
215 sizeof(*(vdst->mvi_macaddr)));
216 for (i = 0; i < vdst->mvi_maccount; i++)
217 vdst->mvi_macaddr[i] = nl_addr_clone(vsrc->mvi_macaddr[i]);
218 } else
219 vdst->mvi_macaddr = NULL;
220
221 return 0;
222 }
223
macvlan_put_attrs(struct nl_msg * msg,struct rtnl_link * link)224 static int macvlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
225 {
226 struct macvlan_info *mvi = link->l_info;
227 struct nlattr *data, *datamac = NULL;
228 int ret;
229
230 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
231 return -NLE_MSGSIZE;
232
233 ret = -NLE_NOMEM;
234
235 if (mvi->mvi_mask & MACVLAN_HAS_MODE)
236 NLA_PUT_U32(msg, IFLA_MACVLAN_MODE, mvi->mvi_mode);
237
238 if (mvi->mvi_mask & MACVLAN_HAS_FLAGS)
239 NLA_PUT_U16(msg, IFLA_MACVLAN_FLAGS, mvi->mvi_flags);
240
241 if (mvi->mvi_mask & MACVLAN_HAS_MACADDR) {
242 uint32_t i;
243
244 NLA_PUT_U32(msg, IFLA_MACVLAN_MACADDR_MODE, mvi->mvi_macmode);
245 datamac = nla_nest_start(msg, IFLA_MACVLAN_MACADDR_DATA);
246 if (!datamac)
247 goto nla_put_failure;
248
249 for (i = 0; i < mvi->mvi_maccount; i++) {
250 NLA_PUT_ADDR(msg, IFLA_MACVLAN_MACADDR,
251 mvi->mvi_macaddr[i]);
252 }
253 }
254
255 ret = 0;
256
257 nla_put_failure:
258 if (datamac)
259 nla_nest_end(msg, datamac);
260
261 nla_nest_end(msg, data);
262
263 return ret;
264 }
265
266 static struct rtnl_link_info_ops macvlan_info_ops = {
267 .io_name = "macvlan",
268 .io_alloc = macvlan_alloc,
269 .io_parse = macvlan_parse,
270 .io_dump = {
271 [NL_DUMP_DETAILS] = macvlan_dump_details,
272 },
273 .io_clone = macvlan_clone,
274 .io_put_attrs = macvlan_put_attrs,
275 .io_free = macvlan_free,
276 };
277
278 static struct rtnl_link_info_ops macvtap_info_ops = {
279 .io_name = "macvtap",
280 .io_alloc = macvlan_alloc,
281 .io_parse = macvlan_parse,
282 .io_dump = {
283 [NL_DUMP_DETAILS] = macvlan_dump_details,
284 },
285 .io_clone = macvlan_clone,
286 .io_put_attrs = macvlan_put_attrs,
287 .io_free = macvlan_free,
288 };
289
290 /** @cond SKIP */
291 #define IS_MACVLAN_LINK_ASSERT(link) \
292 if ((link)->l_info_ops != &macvlan_info_ops) { \
293 APPBUG("Link is not a macvlan link. set type \"macvlan\" first."); \
294 return -NLE_OPNOTSUPP; \
295 }
296
297 #define IS_MACVTAP_LINK_ASSERT(link) \
298 if ((link)->l_info_ops != &macvtap_info_ops) { \
299 APPBUG("Link is not a macvtap link. set type \"macvtap\" first."); \
300 return -NLE_OPNOTSUPP; \
301 }
302 /** @endcond */
303
304 /**
305 * @name MACVLAN Object
306 * @{
307 */
308
309 /**
310 * Allocate link object of type MACVLAN
311 *
312 * @return Allocated link object or NULL.
313 */
rtnl_link_macvlan_alloc(void)314 struct rtnl_link *rtnl_link_macvlan_alloc(void)
315 {
316 struct rtnl_link *link;
317
318 if (!(link = rtnl_link_alloc()))
319 return NULL;
320
321 if (rtnl_link_set_type(link, "macvlan") < 0) {
322 rtnl_link_put(link);
323 return NULL;
324 }
325
326 return link;
327 }
328
329 /**
330 * Check if link is a MACVLAN link
331 * @arg link Link object
332 *
333 * @return True if link is a MACVLAN link, otherwise false is returned.
334 */
rtnl_link_is_macvlan(struct rtnl_link * link)335 int rtnl_link_is_macvlan(struct rtnl_link *link)
336 {
337 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "macvlan");
338 }
339
340 /**
341 * Set MACVLAN MODE
342 * @arg link Link object
343 * @arg mode MACVLAN mode
344 *
345 * @return 0 on success or a negative error code
346 */
rtnl_link_macvlan_set_mode(struct rtnl_link * link,uint32_t mode)347 int rtnl_link_macvlan_set_mode(struct rtnl_link *link, uint32_t mode)
348 {
349 struct macvlan_info *mvi = link->l_info;
350
351 IS_MACVLAN_LINK_ASSERT(link);
352
353 mvi->mvi_mode = mode;
354 mvi->mvi_mask |= MACVLAN_HAS_MODE;
355
356 if (mode != MACVLAN_MODE_SOURCE) {
357 uint32_t i;
358
359 for (i = 0; i < mvi->mvi_maccount; i++)
360 nl_addr_put(mvi->mvi_macaddr[i]);
361 free(mvi->mvi_macaddr);
362 mvi->mvi_maccount = 0;
363 mvi->mvi_macaddr = NULL;
364 mvi->mvi_macmode = MACVLAN_MACADDR_SET;
365 mvi->mvi_mask &= ~MACVLAN_HAS_MACADDR;
366 }
367
368 return 0;
369 }
370
371 /**
372 * Get MACVLAN Mode
373 * @arg link Link object
374 *
375 * @return MACVLAN mode, 0 if not set or a negative error code.
376 */
rtnl_link_macvlan_get_mode(struct rtnl_link * link)377 uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *link)
378 {
379 struct macvlan_info *mvi = link->l_info;
380
381 IS_MACVLAN_LINK_ASSERT(link);
382
383 if (mvi->mvi_mask & MACVLAN_HAS_MODE)
384 return mvi->mvi_mode;
385 else
386 return 0;
387 }
388
389 /**
390 * Set MACVLAN MACMODE
391 * @arg link Link object
392 * @arg mode MACVLAN mac list modification mode
393 *
394 * Only for macvlan SOURCE mode.
395 *
396 * @return 0 on success or a negative error code
397 */
rtnl_link_macvlan_set_macmode(struct rtnl_link * link,uint32_t macmode)398 int rtnl_link_macvlan_set_macmode(struct rtnl_link *link, uint32_t macmode)
399 {
400 struct macvlan_info *mvi = link->l_info;
401
402 IS_MACVLAN_LINK_ASSERT(link);
403
404 if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
405 (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
406 return -NLE_INVAL;
407
408 mvi->mvi_macmode = macmode;
409 mvi->mvi_mask |= MACVLAN_HAS_MACADDR;
410
411 return 0;
412 }
413
414 /**
415 * Get MACVLAN MACMODE
416 * @arg link Link object
417 * @arg out_macmode mac list modification mode
418 *
419 * Only for SOURCE mode.
420 *
421 * @return 0 on success or a negative error code.
422 */
rtnl_link_macvlan_get_macmode(struct rtnl_link * link,uint32_t * out_macmode)423 int rtnl_link_macvlan_get_macmode(struct rtnl_link *link, uint32_t *out_macmode)
424 {
425 struct macvlan_info *mvi = link->l_info;
426
427 IS_MACVLAN_LINK_ASSERT(link);
428
429 if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
430 (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
431 return -NLE_INVAL;
432
433 if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
434 return -NLE_INVAL;
435
436 *out_macmode = mvi->mvi_macmode;
437
438 return 0;
439 }
440
441 /**
442 * Set MACVLAN flags
443 * @arg link Link object
444 * @arg flags MACVLAN flags
445 *
446 * @return 0 on success or a negative error code.
447 */
rtnl_link_macvlan_set_flags(struct rtnl_link * link,uint16_t flags)448 int rtnl_link_macvlan_set_flags(struct rtnl_link *link, uint16_t flags)
449 {
450 struct macvlan_info *mvi = link->l_info;
451
452 IS_MACVLAN_LINK_ASSERT(link);
453
454 mvi->mvi_flags |= flags;
455 mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
456
457 return 0;
458 }
459
460 /**
461 * Unset MACVLAN flags
462 * @arg link Link object
463 * @arg flags MACVLAN flags
464 *
465 * Note: kernel currently only has a single flag and lacks flags_mask to
466 * indicate which flags shall be changed (it always all).
467 *
468 * @return 0 on success or a negative error code.
469 */
rtnl_link_macvlan_unset_flags(struct rtnl_link * link,uint16_t flags)470 int rtnl_link_macvlan_unset_flags(struct rtnl_link *link, uint16_t flags)
471 {
472 struct macvlan_info *mvi = link->l_info;
473
474 IS_MACVLAN_LINK_ASSERT(link);
475
476 mvi->mvi_flags &= ~flags;
477 mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
478
479 return 0;
480 }
481
482 /**
483 * Get MACVLAN flags
484 * @arg link Link object
485 *
486 * @return MACVLAN flags, 0 if none set, or a negative error code.
487 */
rtnl_link_macvlan_get_flags(struct rtnl_link * link)488 uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *link)
489 {
490 struct macvlan_info *mvi = link->l_info;
491
492 IS_MACVLAN_LINK_ASSERT(link);
493
494 return mvi->mvi_flags;
495 }
496
497 /**
498 * Get number of MAC-Addr for MACVLAN device in source mode
499 * @arg link Link object
500 * @arg out_count number of mac addresses
501 *
502 * @return 0 on success or a negative error code.
503 */
rtnl_link_macvlan_count_macaddr(struct rtnl_link * link,uint32_t * out_count)504 int rtnl_link_macvlan_count_macaddr(struct rtnl_link *link, uint32_t *out_count)
505 {
506 struct macvlan_info *mvi = link->l_info;
507
508 IS_MACVLAN_LINK_ASSERT(link);
509
510 if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
511 (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
512 return -NLE_INVAL;
513
514 if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
515 return -NLE_INVAL;
516
517 *out_count = mvi->mvi_maccount;
518
519 return 0;
520 }
521
522 /**
523 * Get configured remote MAC-Addr from MACVLAN device in source mode
524 * @arg link Link object
525 * @arg out_addr address object
526 *
527 * The returned nl_addr struct needs NOT to be released using nl_addr_put.
528 * It is only valid until the address is not removed from this link object
529 * or its mode is changed to non-source.
530 *
531 * @return 0 on success or negative error code
532 */
rtnl_link_macvlan_get_macaddr(struct rtnl_link * link,uint32_t idx,const struct nl_addr ** out_addr)533 int rtnl_link_macvlan_get_macaddr(struct rtnl_link *link, uint32_t idx,
534 const struct nl_addr **out_addr)
535 {
536 struct macvlan_info *mvi = link->l_info;
537
538 IS_MACVLAN_LINK_ASSERT(link);
539
540 if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
541 (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
542 return -NLE_INVAL;
543
544 if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
545 return -NLE_INVAL;
546
547 if (idx >= mvi->mvi_maccount)
548 return -NLE_INVAL;
549
550 *out_addr = mvi->mvi_macaddr[idx];
551 return 0;
552 }
553
554 /**
555 * Add MAC-Addr to MACVLAN device in source mode
556 * @arg link Link object
557 * @arg addr MAC-Addr
558 *
559 * addr is not release but cloned by this method.
560 *
561 * @return 0 on success or a negative error code.
562 */
rtnl_link_macvlan_add_macaddr(struct rtnl_link * link,struct nl_addr * addr)563 int rtnl_link_macvlan_add_macaddr(struct rtnl_link *link, struct nl_addr *addr)
564 {
565 struct macvlan_info *mvi = link->l_info;
566 struct nl_addr **mvi_macaddr;
567 size_t newsize;
568
569 IS_MACVLAN_LINK_ASSERT(link);
570
571 if (nl_addr_get_family(addr) != AF_LLC)
572 return -NLE_INVAL;
573
574 if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
575 (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
576 return -NLE_INVAL;
577
578 if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
579 return -NLE_INVAL;
580
581 if (mvi->mvi_maccount >= UINT32_MAX)
582 return -NLE_INVAL;
583
584 newsize = (mvi->mvi_maccount + 1) * sizeof(*(mvi->mvi_macaddr));
585 mvi_macaddr = realloc(mvi->mvi_macaddr, newsize);
586 if (!mvi_macaddr)
587 return -NLE_NOMEM;
588
589 mvi->mvi_macaddr = mvi_macaddr;
590 mvi->mvi_macaddr[mvi->mvi_maccount] = nl_addr_clone(addr);
591 mvi->mvi_maccount++;
592
593 mvi->mvi_mask |= MACVLAN_HAS_MACADDR;
594
595 return 0;
596 }
597
598 /**
599 * Remove MAC-Addr from MACVLAN device in source mode
600 * @arg link Link object
601 * @arg addr MAC-Addr
602 *
603 * addr is not release by this method.
604 *
605 * @return a negative error code on failure, or the number
606 * of deleted addresses on success.
607 */
rtnl_link_macvlan_del_macaddr(struct rtnl_link * link,struct nl_addr * addr)608 int rtnl_link_macvlan_del_macaddr(struct rtnl_link *link, struct nl_addr *addr)
609 {
610 struct macvlan_info *mvi = link->l_info;
611 uint32_t found, i;
612
613 IS_MACVLAN_LINK_ASSERT(link);
614
615 if (nl_addr_get_family(addr) != AF_LLC)
616 return -NLE_INVAL;
617
618 if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
619 (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
620 return -NLE_INVAL;
621
622 if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
623 return -NLE_INVAL;
624
625 nl_addr_get(addr);
626
627 found = 0; i = 0;
628 while (i + found < mvi->mvi_maccount) {
629 mvi->mvi_macaddr[i] = mvi->mvi_macaddr[i + found];
630 if (found > 0)
631 mvi->mvi_macaddr[i + found] = NULL;
632 if (nl_addr_cmp(addr, mvi->mvi_macaddr[i]) == 0) {
633 nl_addr_put(mvi->mvi_macaddr[i]);
634 mvi->mvi_macaddr[i] = NULL;
635 found++;
636 } else
637 i++;
638 }
639
640 nl_addr_put(addr);
641
642 mvi->mvi_maccount -= found;
643
644 return found > INT_MAX ? INT_MAX : (int) found;
645 }
646
647 /** @} */
648
649
650 /**
651 * @name MACVTAP Object
652 * @{
653 */
654
655 /**
656 * Allocate link object of type MACVTAP
657 *
658 * @return Allocated link object or NULL.
659 */
rtnl_link_macvtap_alloc(void)660 struct rtnl_link *rtnl_link_macvtap_alloc(void)
661 {
662 struct rtnl_link *link;
663
664 if (!(link = rtnl_link_alloc()))
665 return NULL;
666
667 if (rtnl_link_set_type(link, "macvtap") < 0) {
668 rtnl_link_put(link);
669 return NULL;
670 }
671
672 return link;
673 }
674
675 /**
676 * Check if link is a MACVTAP link
677 * @arg link Link object
678 *
679 * @return True if link is a MACVTAP link, otherwise false is returned.
680 */
rtnl_link_is_macvtap(struct rtnl_link * link)681 int rtnl_link_is_macvtap(struct rtnl_link *link)
682 {
683 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "macvtap");
684 }
685
686 /**
687 * Set MACVTAP MODE
688 * @arg link Link object
689 * @arg mode MACVTAP mode
690 *
691 * @return 0 on success or a negative error code
692 */
rtnl_link_macvtap_set_mode(struct rtnl_link * link,uint32_t mode)693 int rtnl_link_macvtap_set_mode(struct rtnl_link *link, uint32_t mode)
694 {
695 struct macvlan_info *mvi = link->l_info;
696
697 IS_MACVTAP_LINK_ASSERT(link);
698
699 mvi->mvi_mode = mode;
700 mvi->mvi_mask |= MACVLAN_HAS_MODE;
701
702 return 0;
703 }
704
705 /**
706 * Get MACVTAP Mode
707 * @arg link Link object
708 *
709 * @return MACVTAP mode, 0 if not set or a negative error code.
710 */
rtnl_link_macvtap_get_mode(struct rtnl_link * link)711 uint32_t rtnl_link_macvtap_get_mode(struct rtnl_link *link)
712 {
713 struct macvlan_info *mvi = link->l_info;
714
715 IS_MACVTAP_LINK_ASSERT(link);
716
717 if (mvi->mvi_mask & MACVLAN_HAS_MODE)
718 return mvi->mvi_mode;
719 else
720 return 0;
721 }
722
723 /**
724 * Set MACVTAP flags
725 * @arg link Link object
726 * @arg flags MACVTAP flags
727 *
728 * @return 0 on success or a negative error code.
729 */
rtnl_link_macvtap_set_flags(struct rtnl_link * link,uint16_t flags)730 int rtnl_link_macvtap_set_flags(struct rtnl_link *link, uint16_t flags)
731 {
732 struct macvlan_info *mvi = link->l_info;
733
734 IS_MACVTAP_LINK_ASSERT(link);
735
736 mvi->mvi_flags |= flags;
737 mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
738
739 return 0;
740 }
741
742 /**
743 * Unset MACVTAP flags
744 * @arg link Link object
745 * @arg flags MACVTAP flags
746 *
747 * Note: kernel currently only has a single flag and lacks flags_mask to
748 * indicate which flags shall be changed (it always all).
749 *
750 * @return 0 on success or a negative error code.
751 */
rtnl_link_macvtap_unset_flags(struct rtnl_link * link,uint16_t flags)752 int rtnl_link_macvtap_unset_flags(struct rtnl_link *link, uint16_t flags)
753 {
754 struct macvlan_info *mvi = link->l_info;
755
756 IS_MACVTAP_LINK_ASSERT(link);
757
758 mvi->mvi_flags &= ~flags;
759 mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
760
761 return 0;
762 }
763
764 /**
765 * Get MACVTAP flags
766 * @arg link Link object
767 *
768 * @return MACVTAP flags, 0 if none set, or a negative error code.
769 */
rtnl_link_macvtap_get_flags(struct rtnl_link * link)770 uint16_t rtnl_link_macvtap_get_flags(struct rtnl_link *link)
771 {
772 struct macvlan_info *mvi = link->l_info;
773
774 IS_MACVTAP_LINK_ASSERT(link);
775
776 return mvi->mvi_flags;
777 }
778
779 /** @} */
780
781
782 static const struct trans_tbl macvlan_flags[] = {
783 __ADD(MACVLAN_FLAG_NOPROMISC, nopromisc),
784 };
785
786 static const struct trans_tbl macvlan_modes[] = {
787 __ADD(MACVLAN_MODE_PRIVATE, private),
788 __ADD(MACVLAN_MODE_VEPA, vepa),
789 __ADD(MACVLAN_MODE_BRIDGE, bridge),
790 __ADD(MACVLAN_MODE_PASSTHRU, passthru),
791 __ADD(MACVLAN_MODE_SOURCE, source),
792 };
793
794 static const struct trans_tbl macvlan_macmodes[] = {
795 __ADD(MACVLAN_MACADDR_ADD, "add"),
796 __ADD(MACVLAN_MACADDR_DEL, "del"),
797 __ADD(MACVLAN_MACADDR_SET, "set"),
798 __ADD(MACVLAN_MACADDR_FLUSH, "flush"),
799 };
800
801 /**
802 * @name Flag Translation
803 * @{
804 */
805
rtnl_link_macvlan_flags2str(int flags,char * buf,size_t len)806 char *rtnl_link_macvlan_flags2str(int flags, char *buf, size_t len)
807 {
808 return __flags2str(flags, buf, len, macvlan_flags, ARRAY_SIZE(macvlan_flags));
809 }
810
rtnl_link_macvlan_str2flags(const char * name)811 int rtnl_link_macvlan_str2flags(const char *name)
812 {
813 return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
814 }
815
rtnl_link_macvtap_flags2str(int flags,char * buf,size_t len)816 char *rtnl_link_macvtap_flags2str(int flags, char *buf, size_t len)
817 {
818 return __flags2str(flags, buf, len, macvlan_flags, ARRAY_SIZE(macvlan_flags));
819 }
820
rtnl_link_macvtap_str2flags(const char * name)821 int rtnl_link_macvtap_str2flags(const char *name)
822 {
823 return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
824 }
825
826 /** @} */
827
828 /**
829 * @name Mode Translation
830 * @{
831 */
832
rtnl_link_macvlan_mode2str(int mode,char * buf,size_t len)833 char *rtnl_link_macvlan_mode2str(int mode, char *buf, size_t len)
834 {
835 return __type2str(mode, buf, len, macvlan_modes, ARRAY_SIZE(macvlan_modes));
836 }
837
rtnl_link_macvlan_str2mode(const char * name)838 int rtnl_link_macvlan_str2mode(const char *name)
839 {
840 return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
841 }
842
rtnl_link_macvlan_macmode2str(int mode,char * buf,size_t len)843 char *rtnl_link_macvlan_macmode2str(int mode, char *buf, size_t len)
844 {
845 return __type2str(mode, buf, len, macvlan_macmodes,
846 ARRAY_SIZE(macvlan_macmodes));
847 }
848
rtnl_link_macvlan_str2macmode(const char * name)849 int rtnl_link_macvlan_str2macmode(const char *name)
850 {
851 return __str2type(name, macvlan_macmodes, ARRAY_SIZE(macvlan_macmodes));
852 }
853
rtnl_link_macvtap_mode2str(int mode,char * buf,size_t len)854 char *rtnl_link_macvtap_mode2str(int mode, char *buf, size_t len)
855 {
856 return __type2str(mode, buf, len, macvlan_modes, ARRAY_SIZE(macvlan_modes));
857 }
858
rtnl_link_macvtap_str2mode(const char * name)859 int rtnl_link_macvtap_str2mode(const char *name)
860 {
861 return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
862 }
863
864 /** @} */
865
macvlan_init(void)866 static void _nl_init macvlan_init(void)
867 {
868 rtnl_link_register_info(&macvlan_info_ops);
869 rtnl_link_register_info(&macvtap_info_ops);
870 }
871
macvlan_exit(void)872 static void _nl_exit macvlan_exit(void)
873 {
874 rtnl_link_unregister_info(&macvlan_info_ops);
875 rtnl_link_unregister_info(&macvtap_info_ops);
876 }
877
878 /** @} */
879