xref: /aosp_15_r20/external/libnl/lib/route/link/macvlan.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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