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