• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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