• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/route/link/vlan.c	VLAN 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) 2003-2013 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup link
14  * @defgroup vlan VLAN
15  * Virtual LAN link module
16  *
17  * @details
18  * \b Link Type Name: "vlan"
19  *
20  * @route_doc{link_vlan, VLAN Documentation}
21  *
22  * @{
23  */
24 
25 #include <netlink-private/netlink.h>
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-private/route/link/api.h>
32 #include <netlink/route/link/vlan.h>
33 
34 #include <linux/if_vlan.h>
35 
36 /** @cond SKIP */
37 #define VLAN_HAS_ID		(1<<0)
38 #define VLAN_HAS_FLAGS		(1<<1)
39 #define VLAN_HAS_INGRESS_QOS	(1<<2)
40 #define VLAN_HAS_EGRESS_QOS	(1<<3)
41 #define VLAN_HAS_PROTOCOL	(1<<4)
42 
43 struct vlan_info
44 {
45 	uint16_t		vi_vlan_id;
46 	uint16_t		vi_protocol;
47 	unsigned int            vi_ingress_qos_mask:(VLAN_PRIO_MAX+1);
48 	uint32_t		vi_flags;
49 	uint32_t		vi_flags_mask;
50 	uint32_t		vi_ingress_qos[VLAN_PRIO_MAX+1];
51 	uint32_t		vi_negress;
52 	uint32_t		vi_egress_size;
53 	struct vlan_map * 	vi_egress_qos;
54 	uint32_t		vi_mask;
55 };
56 
57 /** @endcond */
58 
59 static struct nla_policy vlan_policy[IFLA_VLAN_MAX+1] = {
60 	[IFLA_VLAN_ID]		= { .type = NLA_U16 },
61 	[IFLA_VLAN_FLAGS]	= { .minlen = sizeof(struct ifla_vlan_flags) },
62 	[IFLA_VLAN_INGRESS_QOS]	= { .type = NLA_NESTED },
63 	[IFLA_VLAN_EGRESS_QOS]	= { .type = NLA_NESTED },
64 	[IFLA_VLAN_PROTOCOL]	= { .type = NLA_U16 },
65 };
66 
vlan_alloc(struct rtnl_link * link)67 static int vlan_alloc(struct rtnl_link *link)
68 {
69 	struct vlan_info *vi;
70 
71 	if (link->l_info) {
72 		vi = link->l_info;
73 		free(vi->vi_egress_qos);
74 		memset(link->l_info, 0, sizeof(*vi));
75 	} else {
76 		if ((vi = calloc(1, sizeof(*vi))) == NULL)
77 			return -NLE_NOMEM;
78 
79 		link->l_info = vi;
80 	}
81 
82 	return 0;
83 }
84 
vlan_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)85 static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
86 		      struct nlattr *xstats)
87 {
88 	struct nlattr *tb[IFLA_VLAN_MAX+1];
89 	struct vlan_info *vi;
90 	int err;
91 
92 	NL_DBG(3, "Parsing VLAN link info\n");
93 
94 	if ((err = nla_parse_nested(tb, IFLA_VLAN_MAX, data, vlan_policy)) < 0)
95 		goto errout;
96 
97 	if ((err = vlan_alloc(link)) < 0)
98 		goto errout;
99 
100 	vi = link->l_info;
101 
102 	if (tb[IFLA_VLAN_ID]) {
103 		vi->vi_vlan_id = nla_get_u16(tb[IFLA_VLAN_ID]);
104 		vi->vi_mask |= VLAN_HAS_ID;
105 	}
106 
107 	if (tb[IFLA_VLAN_PROTOCOL]) {
108 		vi->vi_protocol = nla_get_u16(tb[IFLA_VLAN_PROTOCOL]);
109 		vi->vi_mask |= VLAN_HAS_PROTOCOL;
110 	}
111 
112 	if (tb[IFLA_VLAN_FLAGS]) {
113 		struct ifla_vlan_flags flags;
114 		nla_memcpy(&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags));
115 
116 		vi->vi_flags = flags.flags;
117 		vi->vi_mask |= VLAN_HAS_FLAGS;
118 	}
119 
120 	if (tb[IFLA_VLAN_INGRESS_QOS]) {
121 		struct ifla_vlan_qos_mapping *map;
122 		struct nlattr *nla;
123 		int remaining;
124 
125 		vi->vi_ingress_qos_mask = 0;
126 		memset(vi->vi_ingress_qos, 0, sizeof(vi->vi_ingress_qos));
127 
128 		nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) {
129 			if (nla_len(nla) < sizeof(*map))
130 				return -NLE_INVAL;
131 
132 			map = nla_data(nla);
133 			if (map->from > VLAN_PRIO_MAX) {
134 				return -NLE_INVAL;
135 			}
136 
137 			/* Kernel will not explicitly serialize mappings with "to" zero
138 			 * (although they are implicitly set).
139 			 *
140 			 * Thus we only mark those as "set" which are explicitly sent.
141 			 * That is similar to what we do with the egress map and it preserves
142 			 * previous behavior before NL_CAPABILITY_RTNL_LINK_VLAN_INGRESS_MAP_CLEAR.
143 			 *
144 			 * It matters only when a received object is send back to kernel to modify
145 			 * the link.
146 			 */
147 			vi->vi_ingress_qos_mask |= (1 << map->from);
148 			vi->vi_ingress_qos[map->from] = map->to;
149 		}
150 
151 		vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
152 	}
153 
154 	if (tb[IFLA_VLAN_EGRESS_QOS]) {
155 		struct ifla_vlan_qos_mapping *map;
156 		struct nlattr *nla;
157 		int remaining, i = 0;
158 
159 		nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
160 			if (nla_len(nla) < sizeof(*map))
161 				return -NLE_INVAL;
162 			i++;
163 		}
164 
165 		/* align to have a little reserve */
166 		vi->vi_egress_size = (i + 32) & ~31;
167 		vi->vi_egress_qos = calloc(vi->vi_egress_size, sizeof(*vi->vi_egress_qos));
168 		if (vi->vi_egress_qos == NULL)
169 			return -NLE_NOMEM;
170 
171 		i = 0;
172 		nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
173 			map = nla_data(nla);
174 			NL_DBG(4, "Assigning egress qos mapping %d\n", i);
175 			vi->vi_egress_qos[i].vm_from = map->from;
176 			vi->vi_egress_qos[i++].vm_to = map->to;
177 		}
178 
179 		vi->vi_negress = i;
180 		vi->vi_mask |= VLAN_HAS_EGRESS_QOS;
181 	}
182 
183 	err = 0;
184 errout:
185 	return err;
186 }
187 
vlan_free(struct rtnl_link * link)188 static void vlan_free(struct rtnl_link *link)
189 {
190 	struct vlan_info *vi = link->l_info;
191 
192 	if (vi) {
193 		free(vi->vi_egress_qos);
194 		vi->vi_egress_qos = NULL;
195 	}
196 
197 	free(vi);
198 	link->l_info = NULL;
199 }
200 
vlan_dump_line(struct rtnl_link * link,struct nl_dump_params * p)201 static void vlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
202 {
203 	struct vlan_info *vi = link->l_info;
204 
205 	nl_dump(p, "vlan-id %d", vi->vi_vlan_id);
206 }
207 
vlan_dump_details(struct rtnl_link * link,struct nl_dump_params * p)208 static void vlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
209 {
210 	struct vlan_info *vi = link->l_info;
211 	int printed;
212 	uint32_t i;
213 	char buf[64];
214 
215 	rtnl_link_vlan_flags2str(vi->vi_flags, buf, sizeof(buf));
216 	nl_dump_line(p, "    vlan-info id %d <%s>", vi->vi_vlan_id, buf);
217 
218 	if (vi->vi_mask & VLAN_HAS_PROTOCOL)
219 		nl_dump_line(p, "    vlan protocol <%d>", ntohs(vi->vi_protocol));
220 
221 	nl_dump(p, "\n");
222 
223 	if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
224 		nl_dump_line(p,
225 		"      ingress vlan prio -> qos/socket prio mapping:\n");
226 		for (i = 0, printed = 0; i <= VLAN_PRIO_MAX; i++) {
227 			if (vi->vi_ingress_qos_mask & (1 << i)) {
228 				if (printed == 0)
229 					nl_dump_line(p, "      ");
230 				nl_dump(p, "%x -> %#08x, ",
231 					i, vi->vi_ingress_qos[i]);
232 				if (printed++ == 3) {
233 					nl_dump(p, "\n");
234 					printed = 0;
235 				}
236 			}
237 		}
238 
239 		if (printed > 0 && printed != 4)
240 			nl_dump(p, "\n");
241 	}
242 
243 	if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
244 		nl_dump_line(p,
245 		"      egress qos/socket prio -> vlan prio mapping:\n");
246 		for (i = 0, printed = 0; i < vi->vi_negress; i++) {
247 			if (printed == 0)
248 				nl_dump_line(p, "      ");
249 			nl_dump(p, "%#08x -> %x, ",
250 				vi->vi_egress_qos[i].vm_from,
251 				vi->vi_egress_qos[i].vm_to);
252 			if (printed++ == 3) {
253 				nl_dump(p, "\n");
254 				printed = 0;
255 			}
256 		}
257 
258 		if (printed > 0 && printed != 4)
259 			nl_dump(p, "\n");
260 	}
261 }
262 
vlan_clone(struct rtnl_link * dst,struct rtnl_link * src)263 static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
264 {
265 	struct vlan_info *vdst, *vsrc = src->l_info;
266 	int err;
267 	struct vlan_map *p = NULL;
268 
269 	dst->l_info = NULL;
270 	if ((err = rtnl_link_set_type(dst, "vlan")) < 0)
271 		return err;
272 	vdst = dst->l_info;
273 
274 	if (vsrc->vi_negress) {
275 		p = calloc(vsrc->vi_negress,
276 		           sizeof(struct vlan_map));
277 		if (!p)
278 			return -NLE_NOMEM;
279 	}
280 
281 	*vdst = *vsrc;
282 
283 	if (vsrc->vi_negress) {
284 		vdst->vi_egress_size = vsrc->vi_negress;
285 		vdst->vi_egress_qos = p;
286 		memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos,
287 		       vsrc->vi_negress * sizeof(struct vlan_map));
288 	}
289 
290 	return 0;
291 }
292 
vlan_put_attrs(struct nl_msg * msg,struct rtnl_link * link)293 static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
294 {
295 	struct vlan_info *vi = link->l_info;
296 	struct nlattr *data;
297 
298 	if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
299 		return -NLE_MSGSIZE;
300 
301 	if (vi->vi_mask & VLAN_HAS_ID)
302 		NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id);
303 
304 	if (vi->vi_mask & VLAN_HAS_PROTOCOL)
305 		NLA_PUT_U16(msg, IFLA_VLAN_PROTOCOL, vi->vi_protocol);
306 
307 	if (vi->vi_mask & VLAN_HAS_FLAGS) {
308 		struct ifla_vlan_flags flags = {
309 			.flags = vi->vi_flags,
310 			.mask = vi->vi_flags_mask,
311 		};
312 
313 		NLA_PUT(msg, IFLA_VLAN_FLAGS, sizeof(flags), &flags);
314 	}
315 
316 	if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
317 		struct ifla_vlan_qos_mapping map;
318 		struct nlattr *qos;
319 		int i;
320 
321 		if (!(qos = nla_nest_start(msg, IFLA_VLAN_INGRESS_QOS)))
322 			goto nla_put_failure;
323 
324 		for (i = 0; i <= VLAN_PRIO_MAX; i++) {
325 			if (vi->vi_ingress_qos_mask & (1 << i)) {
326 				map.from = i;
327 				map.to = vi->vi_ingress_qos[i];
328 
329 				NLA_PUT(msg, i, sizeof(map), &map);
330 			}
331 		}
332 
333 		nla_nest_end(msg, qos);
334 	}
335 
336 	if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
337 		struct ifla_vlan_qos_mapping map;
338 		struct nlattr *qos;
339 		uint32_t i;
340 
341 		if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS)))
342 			goto nla_put_failure;
343 
344 		for (i = 0; i < vi->vi_negress; i++) {
345 			map.from = vi->vi_egress_qos[i].vm_from;
346 			map.to = vi->vi_egress_qos[i].vm_to;
347 
348 			NLA_PUT(msg, i, sizeof(map), &map);
349 		}
350 
351 		nla_nest_end(msg, qos);
352 	}
353 
354 	nla_nest_end(msg, data);
355 
356 nla_put_failure:
357 
358 	return 0;
359 }
360 
361 static struct rtnl_link_info_ops vlan_info_ops = {
362 	.io_name		= "vlan",
363 	.io_alloc		= vlan_alloc,
364 	.io_parse		= vlan_parse,
365 	.io_dump = {
366 	    [NL_DUMP_LINE]	= vlan_dump_line,
367 	    [NL_DUMP_DETAILS]	= vlan_dump_details,
368 	},
369 	.io_clone		= vlan_clone,
370 	.io_put_attrs		= vlan_put_attrs,
371 	.io_free		= vlan_free,
372 };
373 
374 /** @cond SKIP */
375 #define IS_VLAN_LINK_ASSERT(link) \
376 	if ((link)->l_info_ops != &vlan_info_ops) { \
377 		APPBUG("Link is not a vlan link. set type \"vlan\" first."); \
378 		return -NLE_OPNOTSUPP; \
379 	}
380 /** @endcond */
381 
382 /**
383  * @name VLAN Object
384  * @{
385  */
386 
387 /**
388  * Allocate link object of type VLAN
389  *
390  * @return Allocated link object or NULL.
391  */
rtnl_link_vlan_alloc(void)392 struct rtnl_link *rtnl_link_vlan_alloc(void)
393 {
394 	struct rtnl_link *link;
395 	int err;
396 
397 	if (!(link = rtnl_link_alloc()))
398 		return NULL;
399 
400 	if ((err = rtnl_link_set_type(link, "vlan")) < 0) {
401 		rtnl_link_put(link);
402 		return NULL;
403 	}
404 
405 	return link;
406 }
407 
408 /**
409  * Check if link is a VLAN link
410  * @arg link		Link object
411  *
412  * @return True if link is a VLAN link, otherwise false is returned.
413  */
rtnl_link_is_vlan(struct rtnl_link * link)414 int rtnl_link_is_vlan(struct rtnl_link *link)
415 {
416 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vlan");
417 }
418 
419 /**
420  * Set VLAN ID
421  * @arg link		Link object
422  * @arg id		VLAN identifier
423  *
424  * @return 0 on success or a negative error code
425  */
rtnl_link_vlan_set_id(struct rtnl_link * link,uint16_t id)426 int rtnl_link_vlan_set_id(struct rtnl_link *link, uint16_t id)
427 {
428 	struct vlan_info *vi = link->l_info;
429 
430 	IS_VLAN_LINK_ASSERT(link);
431 
432 	vi->vi_vlan_id = id;
433 	vi->vi_mask |= VLAN_HAS_ID;
434 
435 	return 0;
436 }
437 
438 /**
439  * Get VLAN Id
440  * @arg link		Link object
441  *
442  * @return VLAN id, 0 if not set or a negative error code.
443  */
rtnl_link_vlan_get_id(struct rtnl_link * link)444 int rtnl_link_vlan_get_id(struct rtnl_link *link)
445 {
446 	struct vlan_info *vi = link->l_info;
447 
448 	IS_VLAN_LINK_ASSERT(link);
449 
450 	if (vi->vi_mask & VLAN_HAS_ID)
451 		return vi->vi_vlan_id;
452 	else
453 		return 0;
454 }
455 
456 /**
457  * Set VLAN protocol
458  * @arg link		Link object
459  * @arg protocol	VLAN protocol in network byte order.
460  *   Probably you want to set it to something like htons(ETH_P_8021Q).
461  *
462  * @return 0 on success or a negative error code
463  */
rtnl_link_vlan_set_protocol(struct rtnl_link * link,uint16_t protocol)464 int rtnl_link_vlan_set_protocol(struct rtnl_link *link, uint16_t protocol)
465 {
466 	struct vlan_info *vi = link->l_info;
467 
468 	IS_VLAN_LINK_ASSERT(link);
469 
470 	vi->vi_protocol = protocol;
471 	vi->vi_mask |= VLAN_HAS_PROTOCOL;
472 
473 	return 0;
474 }
475 
476 /**
477  * Get VLAN protocol
478  * @arg link		Link object
479  *
480  * @return VLAN protocol in network byte order like htons(ETH_P_8021Q),
481  *   0 if not set or a negative error code.
482  */
rtnl_link_vlan_get_protocol(struct rtnl_link * link)483 int rtnl_link_vlan_get_protocol(struct rtnl_link *link)
484 {
485 	struct vlan_info *vi = link->l_info;
486 
487 	IS_VLAN_LINK_ASSERT(link);
488 
489 	if (vi->vi_mask & VLAN_HAS_PROTOCOL)
490 		return vi->vi_protocol;
491 	else
492 		return 0;
493 }
494 
495 /**
496  * Set VLAN flags
497  * @arg link		Link object
498  * @arg flags		VLAN flags
499  *
500  * @return 0 on success or a negative error code.
501  */
rtnl_link_vlan_set_flags(struct rtnl_link * link,unsigned int flags)502 int rtnl_link_vlan_set_flags(struct rtnl_link *link, unsigned int flags)
503 {
504 	struct vlan_info *vi = link->l_info;
505 
506 	IS_VLAN_LINK_ASSERT(link);
507 
508 	vi->vi_flags_mask |= flags;
509 	vi->vi_flags |= flags;
510 	vi->vi_mask |= VLAN_HAS_FLAGS;
511 
512 	return 0;
513 }
514 
515 /**
516  * Unset VLAN flags
517  * @arg link		Link object
518  * @arg flags		VLAN flags
519  *
520  * @return 0 on success or a negative error code.
521  */
rtnl_link_vlan_unset_flags(struct rtnl_link * link,unsigned int flags)522 int rtnl_link_vlan_unset_flags(struct rtnl_link *link, unsigned int flags)
523 {
524 	struct vlan_info *vi = link->l_info;
525 
526 	IS_VLAN_LINK_ASSERT(link);
527 
528 	vi->vi_flags_mask |= flags;
529 	vi->vi_flags &= ~flags;
530 	vi->vi_mask |= VLAN_HAS_FLAGS;
531 
532 	return 0;
533 }
534 
535 /**
536  * Get VLAN flags
537  * @arg link		Link object
538  *
539  * @return VLAN flags, 0 if none set, or a negative error code.
540  */
rtnl_link_vlan_get_flags(struct rtnl_link * link)541 int rtnl_link_vlan_get_flags(struct rtnl_link *link)
542 {
543 	struct vlan_info *vi = link->l_info;
544 
545 	IS_VLAN_LINK_ASSERT(link);
546 
547 	return vi->vi_flags;
548 }
549 
550 /** @} */
551 
552 /**
553  * @name Quality of Service
554  * @{
555  */
556 
rtnl_link_vlan_set_ingress_map(struct rtnl_link * link,int from,uint32_t to)557 int rtnl_link_vlan_set_ingress_map(struct rtnl_link *link, int from,
558 				   uint32_t to)
559 {
560 	struct vlan_info *vi = link->l_info;
561 
562 	IS_VLAN_LINK_ASSERT(link);
563 
564 	if (from < 0 || from > VLAN_PRIO_MAX)
565 		return -NLE_INVAL;
566 
567 	vi->vi_ingress_qos_mask |= (1 << from);
568 	vi->vi_ingress_qos[from] = to;
569 	vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
570 
571 	return 0;
572 }
573 
rtnl_link_vlan_get_ingress_map(struct rtnl_link * link)574 uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *link)
575 {
576 	struct vlan_info *vi = link->l_info;
577 
578 	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
579 		return NULL;
580 
581 	if (vi->vi_mask & VLAN_HAS_INGRESS_QOS)
582 		return vi->vi_ingress_qos;
583 	else
584 		return NULL;
585 }
586 
rtnl_link_vlan_set_egress_map(struct rtnl_link * link,uint32_t from,int to)587 int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to)
588 {
589 	struct vlan_info *vi = link->l_info;
590 
591 	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
592 		return -NLE_OPNOTSUPP;
593 
594 	if (to < 0 || to > VLAN_PRIO_MAX)
595 		return -NLE_INVAL;
596 
597 	if (vi->vi_negress >= vi->vi_egress_size) {
598 		uint32_t new_size = vi->vi_egress_size + 1 + vi->vi_egress_size / 2;
599 		size_t bytes;
600 		void *ptr;
601 
602 		if (new_size < vi->vi_egress_size)
603 			return -NLE_NOMEM;
604 		bytes = (size_t) new_size * sizeof(struct vlan_map);
605 		if (bytes / sizeof (struct vlan_map) != new_size)
606 			return -NLE_NOMEM;
607 		ptr = realloc(vi->vi_egress_qos, bytes);
608 		if (!ptr)
609 			return -NLE_NOMEM;
610 
611 		vi->vi_egress_qos = ptr;
612 		vi->vi_egress_size = new_size;
613 	}
614 
615 	vi->vi_egress_qos[vi->vi_negress].vm_from = from;
616 	vi->vi_egress_qos[vi->vi_negress].vm_to = to;
617 	vi->vi_negress++;
618 	vi->vi_mask |= VLAN_HAS_EGRESS_QOS;
619 
620 	return 0;
621 }
622 
rtnl_link_vlan_get_egress_map(struct rtnl_link * link,int * negress)623 struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *link,
624 					       int *negress)
625 {
626 	struct vlan_info *vi = link->l_info;
627 
628 	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
629 		return NULL;
630 
631 	if (negress == NULL)
632 		return NULL;
633 
634 	if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
635 		*negress = vi->vi_negress;
636 		return vi->vi_egress_qos;
637 	} else {
638 		*negress = 0;
639 		return NULL;
640 	}
641 }
642 
643 /** @} */
644 
645 static const struct trans_tbl vlan_flags[] = {
646 	__ADD(VLAN_FLAG_REORDER_HDR, reorder_hdr),
647 	__ADD(VLAN_FLAG_GVRP, gvrp),
648 	__ADD(VLAN_FLAG_LOOSE_BINDING, loose_binding),
649 	__ADD(VLAN_FLAG_MVRP, mvrp),
650 };
651 
652 /**
653  * @name Flag Translation
654  * @{
655  */
656 
rtnl_link_vlan_flags2str(int flags,char * buf,size_t len)657 char *rtnl_link_vlan_flags2str(int flags, char *buf, size_t len)
658 {
659 	return __flags2str(flags, buf, len, vlan_flags, ARRAY_SIZE(vlan_flags));
660 }
661 
rtnl_link_vlan_str2flags(const char * name)662 int rtnl_link_vlan_str2flags(const char *name)
663 {
664 	return __str2flags(name, vlan_flags, ARRAY_SIZE(vlan_flags));
665 }
666 
667 /** @} */
668 
669 
vlan_init(void)670 static void __init vlan_init(void)
671 {
672 	rtnl_link_register_info(&vlan_info_ops);
673 }
674 
vlan_exit(void)675 static void __exit vlan_exit(void)
676 {
677 	rtnl_link_unregister_info(&vlan_info_ops);
678 }
679 
680 /** @} */
681