• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2013 Michael Braun <michael-dev@fami-braun.de>
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 <netlink-private/netlink.h>
21 #include <netlink/netlink.h>
22 #include <netlink/attr.h>
23 #include <netlink/utils.h>
24 #include <netlink/object.h>
25 #include <netlink/route/rtnl.h>
26 #include <netlink-private/route/link/api.h>
27 #include <netlink/route/link/macvlan.h>
28 #include <netlink/route/link/macvtap.h>
29 
30 #include <linux/if_link.h>
31 
32 /** @cond SKIP */
33 #define MACVLAN_HAS_MODE        (1<<0)
34 #define MACVLAN_HAS_FLAGS       (1<<1)
35 #define MACVLAN_HAS_MACADDR     (1<<2)
36 
37 struct macvlan_info
38 {
39 	uint32_t                mvi_mode;
40 	uint16_t                mvi_flags; // there currently is only one flag and kernel has no flags_mask yet
41 	uint32_t                mvi_mask;
42 	uint32_t                mvi_maccount;
43 	uint32_t                mvi_macmode;
44 	struct nl_addr          **mvi_macaddr;
45 };
46 
47 /** @endcond */
48 
49 static struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX+1] = {
50 	[IFLA_MACVLAN_MODE]             = { .type = NLA_U32 },
51 	[IFLA_MACVLAN_FLAGS]            = { .type = NLA_U16 },
52 	[IFLA_MACVLAN_MACADDR_MODE]     = { .type = NLA_U32 },
53 	[IFLA_MACVLAN_MACADDR]          = { .type = NLA_UNSPEC },
54 	[IFLA_MACVLAN_MACADDR_DATA]     = { .type = NLA_NESTED },
55 	[IFLA_MACVLAN_MACADDR_COUNT]    = { .type = NLA_U32 },
56 };
57 
macvlan_alloc(struct rtnl_link * link)58 static int macvlan_alloc(struct rtnl_link *link)
59 {
60 	struct macvlan_info *mvi;
61 	uint32_t i;
62 
63 	if (link->l_info) {
64 		mvi = link->l_info;
65 		for (i = 0; i < mvi->mvi_maccount; i++)
66 			nl_addr_put(mvi->mvi_macaddr[i]);
67 		free(mvi->mvi_macaddr);
68 		memset(mvi, 0, sizeof(*mvi));
69 	} else {
70 		if ((mvi = calloc(1, sizeof(*mvi))) == NULL)
71 			return -NLE_NOMEM;
72 
73 		link->l_info = mvi;
74 	}
75 	mvi->mvi_macmode = MACVLAN_MACADDR_SET;
76 
77 	return 0;
78 }
79 
macvlan_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)80 static int macvlan_parse(struct rtnl_link *link, struct nlattr *data,
81                          struct nlattr *xstats)
82 {
83 	struct nlattr *tb[IFLA_MACVLAN_MAX+1];
84 	struct macvlan_info *mvi;
85 	struct nlattr *nla;
86 	int len;
87 	int err;
88 
89 	NL_DBG(3, "Parsing %s link info", link->l_info_ops->io_name);
90 
91 	if ((err = nla_parse_nested(tb, IFLA_MACVLAN_MAX, data, macvlan_policy)) < 0)
92 		goto errout;
93 
94 	if ((err = macvlan_alloc(link)) < 0)
95 		goto errout;
96 
97 	mvi = link->l_info;
98 
99 	if (tb[IFLA_MACVLAN_MODE]) {
100 		mvi->mvi_mode = nla_get_u32(tb[IFLA_MACVLAN_MODE]);
101 		mvi->mvi_mask |= MACVLAN_HAS_MODE;
102 	}
103 
104 	if (tb[IFLA_MACVLAN_FLAGS]) {
105 		mvi->mvi_flags = nla_get_u16(tb[IFLA_MACVLAN_FLAGS]);
106 		mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
107 	}
108 
109 	if (   tb[IFLA_MACVLAN_MACADDR_COUNT]
110 	    && tb[IFLA_MACVLAN_MACADDR_DATA]) {
111 		mvi->mvi_maccount = nla_get_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]);
112 		if (mvi->mvi_maccount > 0) {
113 			uint32_t i;
114 
115 			nla = nla_data(tb[IFLA_MACVLAN_MACADDR_DATA]);
116 			len = nla_len(tb[IFLA_MACVLAN_MACADDR_DATA]);
117 
118 			mvi->mvi_macaddr = calloc(mvi->mvi_maccount,
119 			                          sizeof(*(mvi->mvi_macaddr)));
120 			if (mvi->mvi_macaddr == NULL) {
121 				err = -NLE_NOMEM;
122 				goto errout;
123 			}
124 
125 			i = 0;
126 			for (; nla_ok(nla, len); nla = nla_next(nla, &len)) {
127 				if (i >= mvi->mvi_maccount)
128 					break;
129 				if (nla_type(nla) != IFLA_MACVLAN_MACADDR ||
130 				    nla_len(nla) < ETH_ALEN)
131 					continue;
132 				mvi->mvi_macaddr[i] = nl_addr_alloc_attr(nla, AF_LLC);
133 				i++;
134 			}
135 		}
136 		mvi->mvi_mask |= MACVLAN_HAS_MACADDR;
137 	}
138 
139 	err = 0;
140 errout:
141 	return err;
142 }
143 
macvlan_free(struct rtnl_link * link)144 static void macvlan_free(struct rtnl_link *link)
145 {
146 	struct macvlan_info *mvi;
147 	uint32_t i;
148 
149 	mvi = link->l_info;
150 	if (!mvi)
151 		return;
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 
311 	if (!(link = rtnl_link_alloc()))
312 		return NULL;
313 
314 	if (rtnl_link_set_type(link, "macvlan") < 0) {
315 		rtnl_link_put(link);
316 		return NULL;
317 	}
318 
319 	return link;
320 }
321 
322 /**
323  * Check if link is a MACVLAN link
324  * @arg link            Link object
325  *
326  * @return True if link is a MACVLAN link, otherwise false is returned.
327  */
rtnl_link_is_macvlan(struct rtnl_link * link)328 int rtnl_link_is_macvlan(struct rtnl_link *link)
329 {
330 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "macvlan");
331 }
332 
333 /**
334  * Set MACVLAN MODE
335  * @arg link            Link object
336  * @arg mode            MACVLAN mode
337  *
338  * @return 0 on success or a negative error code
339  */
rtnl_link_macvlan_set_mode(struct rtnl_link * link,uint32_t mode)340 int rtnl_link_macvlan_set_mode(struct rtnl_link *link, uint32_t mode)
341 {
342 	struct macvlan_info *mvi = link->l_info;
343 	int i;
344 
345 	IS_MACVLAN_LINK_ASSERT(link);
346 
347 	mvi->mvi_mode = mode;
348 	mvi->mvi_mask |= MACVLAN_HAS_MODE;
349 
350 	if (mode != MACVLAN_MODE_SOURCE) {
351 		for (i = 0; i < mvi->mvi_maccount; i++)
352 			nl_addr_put(mvi->mvi_macaddr[i]);
353 		free(mvi->mvi_macaddr);
354 		mvi->mvi_maccount = 0;
355 		mvi->mvi_macaddr = NULL;
356 		mvi->mvi_macmode = MACVLAN_MACADDR_SET;
357 		mvi->mvi_mask &= ~MACVLAN_HAS_MACADDR;
358 	}
359 
360 	return 0;
361 }
362 
363 /**
364  * Get MACVLAN Mode
365  * @arg link            Link object
366  *
367  * @return MACVLAN mode, 0 if not set or a negative error code.
368  */
rtnl_link_macvlan_get_mode(struct rtnl_link * link)369 uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *link)
370 {
371 	struct macvlan_info *mvi = link->l_info;
372 
373 	IS_MACVLAN_LINK_ASSERT(link);
374 
375 	if (mvi->mvi_mask & MACVLAN_HAS_MODE)
376 		return mvi->mvi_mode;
377 	else
378 		return 0;
379 }
380 
381 /**
382  * Set MACVLAN MACMODE
383  * @arg link            Link object
384  * @arg mode            MACVLAN mac list modification mode
385  *
386  * Only for macvlan SOURCE mode.
387  *
388  * @return 0 on success or a negative error code
389  */
rtnl_link_macvlan_set_macmode(struct rtnl_link * link,uint32_t macmode)390 int rtnl_link_macvlan_set_macmode(struct rtnl_link *link, uint32_t macmode)
391 {
392 	struct macvlan_info *mvi = link->l_info;
393 
394 	IS_MACVLAN_LINK_ASSERT(link);
395 
396 	if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
397 	    (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
398 		return -NLE_INVAL;
399 
400 	mvi->mvi_macmode = macmode;
401 	mvi->mvi_mask |= MACVLAN_HAS_MACADDR;
402 
403 	return 0;
404 }
405 
406 /**
407  * Get MACVLAN MACMODE
408  * @arg link            Link object
409  * @arg out_macmode     mac list modification mode
410  *
411  * Only for SOURCE mode.
412  *
413  * @return 0 on success or a negative error code.
414  */
rtnl_link_macvlan_get_macmode(struct rtnl_link * link,uint32_t * out_macmode)415 int rtnl_link_macvlan_get_macmode(struct rtnl_link *link, uint32_t *out_macmode)
416 {
417 	struct macvlan_info *mvi = link->l_info;
418 
419 	IS_MACVLAN_LINK_ASSERT(link);
420 
421 	if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
422 	    (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
423 		return -NLE_INVAL;
424 
425 	if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
426 		return -NLE_INVAL;
427 
428 	*out_macmode = mvi->mvi_macmode;
429 
430 	return 0;
431 }
432 
433 /**
434  * Set MACVLAN flags
435  * @arg link            Link object
436  * @arg flags           MACVLAN flags
437  *
438  * @return 0 on success or a negative error code.
439  */
rtnl_link_macvlan_set_flags(struct rtnl_link * link,uint16_t flags)440 int rtnl_link_macvlan_set_flags(struct rtnl_link *link, uint16_t flags)
441 {
442 	struct macvlan_info *mvi = link->l_info;
443 
444 	IS_MACVLAN_LINK_ASSERT(link);
445 
446 	mvi->mvi_flags |= flags;
447 	mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
448 
449 	return 0;
450 }
451 
452 /**
453  * Unset MACVLAN flags
454  * @arg link            Link object
455  * @arg flags           MACVLAN flags
456  *
457  * Note: kernel currently only has a single flag and lacks flags_mask to
458  * indicate which flags shall be changed (it always all).
459  *
460  * @return 0 on success or a negative error code.
461  */
rtnl_link_macvlan_unset_flags(struct rtnl_link * link,uint16_t flags)462 int rtnl_link_macvlan_unset_flags(struct rtnl_link *link, uint16_t flags)
463 {
464 	struct macvlan_info *mvi = link->l_info;
465 
466 	IS_MACVLAN_LINK_ASSERT(link);
467 
468 	mvi->mvi_flags &= ~flags;
469 	mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
470 
471 	return 0;
472 }
473 
474 /**
475  * Get MACVLAN flags
476  * @arg link            Link object
477  *
478  * @return MACVLAN flags, 0 if none set, or a negative error code.
479  */
rtnl_link_macvlan_get_flags(struct rtnl_link * link)480 uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *link)
481 {
482 	struct macvlan_info *mvi = link->l_info;
483 
484 	IS_MACVLAN_LINK_ASSERT(link);
485 
486 	return mvi->mvi_flags;
487 }
488 
489 /**
490  * Get number of MAC-Addr for MACVLAN device in source mode
491  * @arg link            Link object
492  * @arg out_count       number of mac addresses
493  *
494  * @return 0 on success or a negative error code.
495  */
rtnl_link_macvlan_count_macaddr(struct rtnl_link * link,uint32_t * out_count)496 int rtnl_link_macvlan_count_macaddr(struct rtnl_link *link, uint32_t *out_count)
497 {
498 	struct macvlan_info *mvi = link->l_info;
499 
500 	IS_MACVLAN_LINK_ASSERT(link);
501 
502 	if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
503 	    (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
504 		return -NLE_INVAL;
505 
506 	if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
507 		return -NLE_INVAL;
508 
509 	*out_count = mvi->mvi_maccount;
510 
511 	return 0;
512 }
513 
514 /**
515  * Get configured remote MAC-Addr from MACVLAN device in source mode
516  * @arg link            Link object
517  * @arg out_addr        address object
518  *
519  * The returned nl_addr struct needs NOT to be released using nl_addr_put.
520  * It is only valid until the address is not removed from this link object
521  * or its mode is changed to non-source.
522  *
523  * @return 0 on success or negative error code
524  */
rtnl_link_macvlan_get_macaddr(struct rtnl_link * link,uint32_t idx,const struct nl_addr ** out_addr)525 int rtnl_link_macvlan_get_macaddr(struct rtnl_link *link, uint32_t idx,
526                                   const struct nl_addr **out_addr)
527 {
528 	struct macvlan_info *mvi = link->l_info;
529 
530 	IS_MACVLAN_LINK_ASSERT(link);
531 
532 	if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
533 	    (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
534 		return -NLE_INVAL;
535 
536 	if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
537 		return -NLE_INVAL;
538 
539 	if (idx >= mvi->mvi_maccount)
540 		return -NLE_INVAL;
541 
542 	*out_addr = mvi->mvi_macaddr[idx];
543 	return 0;
544 }
545 
546 /**
547  * Add MAC-Addr to MACVLAN device in source mode
548  * @arg link            Link object
549  * @arg addr            MAC-Addr
550  *
551  * addr is not release but cloned by this method.
552  *
553  * @return 0 on success or a negative error code.
554  */
rtnl_link_macvlan_add_macaddr(struct rtnl_link * link,struct nl_addr * addr)555 int rtnl_link_macvlan_add_macaddr(struct rtnl_link *link, struct nl_addr *addr)
556 {
557 	struct macvlan_info *mvi = link->l_info;
558 	struct nl_addr **mvi_macaddr;
559 	size_t newsize;
560 
561 	IS_MACVLAN_LINK_ASSERT(link);
562 
563 	if (nl_addr_get_family(addr) != AF_LLC)
564 		return -NLE_INVAL;
565 
566 	if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
567 	    (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
568 		return -NLE_INVAL;
569 
570 	if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
571 		return -NLE_INVAL;
572 
573 	if (mvi->mvi_maccount >= UINT32_MAX)
574 		return -NLE_INVAL;
575 
576 	newsize = (mvi->mvi_maccount + 1) * sizeof(*(mvi->mvi_macaddr));
577 	mvi_macaddr = realloc(mvi->mvi_macaddr, newsize);
578 	if (!mvi_macaddr)
579 		return -NLE_NOMEM;
580 
581 	mvi->mvi_macaddr = mvi_macaddr;
582 	mvi->mvi_macaddr[mvi->mvi_maccount] = nl_addr_clone(addr);
583 	mvi->mvi_maccount++;
584 
585 	mvi->mvi_mask |= MACVLAN_HAS_MACADDR;
586 
587 	return 0;
588 }
589 
590 /**
591  * Remove MAC-Addr from MACVLAN device in source mode
592  * @arg link            Link object
593  * @arg addr            MAC-Addr
594  *
595  * addr is not release by this method.
596  *
597  * @return a negative error code on failure, or the number
598  *   of deleted addresses on success.
599  */
rtnl_link_macvlan_del_macaddr(struct rtnl_link * link,struct nl_addr * addr)600 int rtnl_link_macvlan_del_macaddr(struct rtnl_link *link, struct nl_addr *addr)
601 {
602 	struct macvlan_info *mvi = link->l_info;
603 	uint32_t found, i;
604 
605 	IS_MACVLAN_LINK_ASSERT(link);
606 
607 	if (nl_addr_get_family(addr) != AF_LLC)
608 		return -NLE_INVAL;
609 
610 	if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
611 	    (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
612 		return -NLE_INVAL;
613 
614 	if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
615 		return -NLE_INVAL;
616 
617 	nl_addr_get(addr);
618 
619 	found = 0; i = 0;
620 	while (i + found < mvi->mvi_maccount) {
621 		mvi->mvi_macaddr[i] = mvi->mvi_macaddr[i + found];
622 		if (found > 0)
623 			mvi->mvi_macaddr[i + found] = NULL;
624 		if (nl_addr_cmp(addr, mvi->mvi_macaddr[i]) == 0) {
625 			nl_addr_put(mvi->mvi_macaddr[i]);
626 			mvi->mvi_macaddr[i] = NULL;
627 			found++;
628 		} else
629 			i++;
630 	}
631 
632 	nl_addr_put(addr);
633 
634 	mvi->mvi_maccount -= found;
635 
636 	return found > INT_MAX ? INT_MAX : (int) found;
637 }
638 
639 /** @} */
640 
641 
642 /**
643  * @name MACVTAP Object
644  * @{
645  */
646 
647 /**
648  * Allocate link object of type MACVTAP
649  *
650  * @return Allocated link object or NULL.
651  */
rtnl_link_macvtap_alloc(void)652 struct rtnl_link *rtnl_link_macvtap_alloc(void)
653 {
654 	struct rtnl_link *link;
655 
656 	if (!(link = rtnl_link_alloc()))
657 		return NULL;
658 
659 	if (rtnl_link_set_type(link, "macvtap") < 0) {
660 		rtnl_link_put(link);
661 		return NULL;
662 	}
663 
664 	return link;
665 }
666 
667 /**
668  * Check if link is a MACVTAP link
669  * @arg link            Link object
670  *
671  * @return True if link is a MACVTAP link, otherwise false is returned.
672  */
rtnl_link_is_macvtap(struct rtnl_link * link)673 int rtnl_link_is_macvtap(struct rtnl_link *link)
674 {
675 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "macvtap");
676 }
677 
678 /**
679  * Set MACVTAP MODE
680  * @arg link            Link object
681  * @arg mode            MACVTAP mode
682  *
683  * @return 0 on success or a negative error code
684  */
rtnl_link_macvtap_set_mode(struct rtnl_link * link,uint32_t mode)685 int rtnl_link_macvtap_set_mode(struct rtnl_link *link, uint32_t mode)
686 {
687 	struct macvlan_info *mvi = link->l_info;
688 
689 	IS_MACVTAP_LINK_ASSERT(link);
690 
691 	mvi->mvi_mode = mode;
692 	mvi->mvi_mask |= MACVLAN_HAS_MODE;
693 
694 	return 0;
695 }
696 
697 /**
698  * Get MACVTAP Mode
699  * @arg link            Link object
700  *
701  * @return MACVTAP mode, 0 if not set or a negative error code.
702  */
rtnl_link_macvtap_get_mode(struct rtnl_link * link)703 uint32_t rtnl_link_macvtap_get_mode(struct rtnl_link *link)
704 {
705 	struct macvlan_info *mvi = link->l_info;
706 
707 	IS_MACVTAP_LINK_ASSERT(link);
708 
709 	if (mvi->mvi_mask & MACVLAN_HAS_MODE)
710 		return mvi->mvi_mode;
711 	else
712 		return 0;
713 }
714 
715 /**
716  * Set MACVTAP flags
717  * @arg link            Link object
718  * @arg flags           MACVTAP flags
719  *
720  * @return 0 on success or a negative error code.
721  */
rtnl_link_macvtap_set_flags(struct rtnl_link * link,uint16_t flags)722 int rtnl_link_macvtap_set_flags(struct rtnl_link *link, uint16_t flags)
723 {
724 	struct macvlan_info *mvi = link->l_info;
725 
726 	IS_MACVTAP_LINK_ASSERT(link);
727 
728 	mvi->mvi_flags |= flags;
729 	mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
730 
731 	return 0;
732 }
733 
734 /**
735  * Unset MACVTAP flags
736  * @arg link            Link object
737  * @arg flags           MACVTAP flags
738  *
739  * Note: kernel currently only has a single flag and lacks flags_mask to
740  * indicate which flags shall be changed (it always all).
741  *
742  * @return 0 on success or a negative error code.
743  */
rtnl_link_macvtap_unset_flags(struct rtnl_link * link,uint16_t flags)744 int rtnl_link_macvtap_unset_flags(struct rtnl_link *link, uint16_t flags)
745 {
746 	struct macvlan_info *mvi = link->l_info;
747 
748 	IS_MACVTAP_LINK_ASSERT(link);
749 
750 	mvi->mvi_flags &= ~flags;
751 	mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
752 
753 	return 0;
754 }
755 
756 /**
757  * Get MACVTAP flags
758  * @arg link            Link object
759  *
760  * @return MACVTAP flags, 0 if none set, or a negative error code.
761  */
rtnl_link_macvtap_get_flags(struct rtnl_link * link)762 uint16_t rtnl_link_macvtap_get_flags(struct rtnl_link *link)
763 {
764 	struct macvlan_info *mvi = link->l_info;
765 
766 	IS_MACVTAP_LINK_ASSERT(link);
767 
768 	return mvi->mvi_flags;
769 }
770 
771 /** @} */
772 
773 
774 static const struct trans_tbl macvlan_flags[] = {
775 	__ADD(MACVLAN_FLAG_NOPROMISC, nopromisc),
776 };
777 
778 static const struct trans_tbl macvlan_modes[] = {
779 	__ADD(MACVLAN_MODE_PRIVATE, private),
780 	__ADD(MACVLAN_MODE_VEPA, vepa),
781 	__ADD(MACVLAN_MODE_BRIDGE, bridge),
782 	__ADD(MACVLAN_MODE_PASSTHRU, passthru),
783 	__ADD(MACVLAN_MODE_SOURCE, source),
784 };
785 
786 static const struct trans_tbl macvlan_macmodes[] = {
787 	__ADD(MACVLAN_MACADDR_ADD, "add"),
788 	__ADD(MACVLAN_MACADDR_DEL, "del"),
789 	__ADD(MACVLAN_MACADDR_SET, "set"),
790 	__ADD(MACVLAN_MACADDR_FLUSH, "flush"),
791 };
792 
793 /**
794  * @name Flag Translation
795  * @{
796  */
797 
rtnl_link_macvlan_flags2str(int flags,char * buf,size_t len)798 char *rtnl_link_macvlan_flags2str(int flags, char *buf, size_t len)
799 {
800 	return __flags2str(flags, buf, len, macvlan_flags, ARRAY_SIZE(macvlan_flags));
801 }
802 
rtnl_link_macvlan_str2flags(const char * name)803 int rtnl_link_macvlan_str2flags(const char *name)
804 {
805 	return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
806 }
807 
rtnl_link_macvtap_flags2str(int flags,char * buf,size_t len)808 char *rtnl_link_macvtap_flags2str(int flags, char *buf, size_t len)
809 {
810 	return __flags2str(flags, buf, len, macvlan_flags, ARRAY_SIZE(macvlan_flags));
811 }
812 
rtnl_link_macvtap_str2flags(const char * name)813 int rtnl_link_macvtap_str2flags(const char *name)
814 {
815 	return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
816 }
817 
818 /** @} */
819 
820 /**
821  * @name Mode Translation
822  * @{
823  */
824 
rtnl_link_macvlan_mode2str(int mode,char * buf,size_t len)825 char *rtnl_link_macvlan_mode2str(int mode, char *buf, size_t len)
826 {
827 	return __type2str(mode, buf, len, macvlan_modes, ARRAY_SIZE(macvlan_modes));
828 }
829 
rtnl_link_macvlan_str2mode(const char * name)830 int rtnl_link_macvlan_str2mode(const char *name)
831 {
832 	return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
833 }
834 
rtnl_link_macvlan_macmode2str(int mode,char * buf,size_t len)835 char *rtnl_link_macvlan_macmode2str(int mode, char *buf, size_t len)
836 {
837 	return __type2str(mode, buf, len, macvlan_macmodes,
838 	                  ARRAY_SIZE(macvlan_macmodes));
839 }
840 
rtnl_link_macvlan_str2macmode(const char * name)841 int rtnl_link_macvlan_str2macmode(const char *name)
842 {
843 	return __str2type(name, macvlan_macmodes, ARRAY_SIZE(macvlan_macmodes));
844 }
845 
rtnl_link_macvtap_mode2str(int mode,char * buf,size_t len)846 char *rtnl_link_macvtap_mode2str(int mode, char *buf, size_t len)
847 {
848 	return __type2str(mode, buf, len, macvlan_modes, ARRAY_SIZE(macvlan_modes));
849 }
850 
rtnl_link_macvtap_str2mode(const char * name)851 int rtnl_link_macvtap_str2mode(const char *name)
852 {
853 	return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
854 }
855 
856 /** @} */
857 
macvlan_init(void)858 static void __init macvlan_init(void)
859 {
860 	rtnl_link_register_info(&macvlan_info_ops);
861 	rtnl_link_register_info(&macvtap_info_ops);
862 }
863 
macvlan_exit(void)864 static void __exit macvlan_exit(void)
865 {
866 	rtnl_link_unregister_info(&macvlan_info_ops);
867 	rtnl_link_unregister_info(&macvtap_info_ops);
868 }
869 
870 /** @} */
871