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