xref: /aosp_15_r20/external/libnl/lib/route/link/bridge.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2010-2013 Thomas Graf <[email protected]>
4  */
5 
6 /**
7  * @ingroup link
8  * @defgroup bridge Bridging
9  *
10  * @details
11  * @{
12  */
13 
14 #include "nl-default.h"
15 
16 #include <linux/if_bridge.h>
17 
18 #include <netlink/netlink.h>
19 #include <netlink/attr.h>
20 #include <netlink/route/rtnl.h>
21 #include <netlink/route/link/bridge.h>
22 
23 #include "nl-route.h"
24 #include "link-api.h"
25 #include "nl-priv-dynamic-core/nl-core.h"
26 #include "nl-priv-static-route/nl-priv-static-route.h"
27 
28 #define VLAN_VID_MASK           0x0fff /* VLAN Identifier */
29 
30 /** @cond SKIP */
31 #define BRIDGE_ATTR_PORT_STATE		(1 << 0)
32 #define BRIDGE_ATTR_PRIORITY		(1 << 1)
33 #define BRIDGE_ATTR_COST		(1 << 2)
34 #define BRIDGE_ATTR_FLAGS		(1 << 3)
35 #define BRIDGE_ATTR_PORT_VLAN           (1 << 4)
36 #define BRIDGE_ATTR_HWMODE		(1 << 5)
37 #define BRIDGE_ATTR_CONFIG_MODE		(1 << 6)
38 
39 #define PRIV_FLAG_NEW_ATTRS		(1 << 0)
40 
41 struct bridge_data
42 {
43 	uint8_t			b_port_state;
44 	uint8_t			b_priv_flags; /* internal flags */
45 	uint16_t		b_hwmode;
46 	uint16_t		b_priority;
47 	uint16_t		b_config_mode;
48 	uint32_t		b_cost;
49 	uint32_t		b_flags;
50 	uint32_t		b_flags_mask;
51 	uint32_t                ce_mask; /* HACK to support attr macros */
52 	struct rtnl_link_bridge_vlan vlan_info;
53 };
54 
set_bit(unsigned nr,uint32_t * addr)55 static void set_bit(unsigned nr, uint32_t *addr)
56 {
57 	if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
58 		addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
59 }
60 
unset_bit(unsigned nr,uint32_t * addr)61 static void unset_bit(unsigned nr, uint32_t *addr)
62 {
63 	if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
64 		addr[nr / 32] &= ~(((uint32_t) 1) << (nr % 32));
65 }
66 
vlan_id_untagged(struct rtnl_link_bridge_vlan * vlan_info,uint16_t vid)67 static bool vlan_id_untagged(struct rtnl_link_bridge_vlan *vlan_info, uint16_t vid)
68 {
69 	uint32_t mask, bit;
70 
71 	_nl_assert(vid / 32u < ARRAY_SIZE(vlan_info->untagged_bitmap));
72 
73 	mask = vlan_info->untagged_bitmap[vid / 32];
74 	bit = (((uint32_t) 1) << vid % 32);
75 
76 	return mask & bit;
77 }
78 
find_next_bit(int i,uint32_t x)79 static int find_next_bit(int i, uint32_t x)
80 {
81 	int j;
82 
83 	if (i >= 32)
84 		return -1;
85 
86 	/* find first bit */
87 	if (i < 0)
88 		return __builtin_ffs(x);
89 
90 	/* mask off prior finds to get next */
91 	j = __builtin_ffs(x >> i);
92 	return j ? j + i : 0;
93 }
94 
95 static struct rtnl_link_af_ops bridge_ops;
96 
97 #define IS_BRIDGE_LINK_ASSERT(link) \
98 	if (!rtnl_link_is_bridge(link)) { \
99 		APPBUG("A function was expecting a link object of type bridge."); \
100 		return -NLE_OPNOTSUPP; \
101 	}
102 
bridge_data(struct rtnl_link * link)103 static inline struct bridge_data *bridge_data(struct rtnl_link *link)
104 {
105 	return rtnl_link_af_data(link, &bridge_ops);
106 }
107 
bridge_alloc(struct rtnl_link * link)108 static void *bridge_alloc(struct rtnl_link *link)
109 {
110 	return calloc(1, sizeof(struct bridge_data));
111 }
112 
bridge_clone(struct rtnl_link * link,void * data)113 static void *bridge_clone(struct rtnl_link *link, void *data)
114 {
115 	struct bridge_data *bd;
116 
117 	if ((bd = bridge_alloc(link)))
118 		memcpy(bd, data, sizeof(*bd));
119 
120 	return bd;
121 }
122 
bridge_free(struct rtnl_link * link,void * data)123 static void bridge_free(struct rtnl_link *link, void *data)
124 {
125 	free(data);
126 }
127 
128 static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = {
129 	[IFLA_BRPORT_STATE]		= { .type = NLA_U8 },
130 	[IFLA_BRPORT_PRIORITY]		= { .type = NLA_U16 },
131 	[IFLA_BRPORT_COST]		= { .type = NLA_U32 },
132 	[IFLA_BRPORT_MODE]		= { .type = NLA_U8 },
133 	[IFLA_BRPORT_GUARD]		= { .type = NLA_U8 },
134 	[IFLA_BRPORT_PROTECT]		= { .type = NLA_U8 },
135 	[IFLA_BRPORT_FAST_LEAVE]	= { .type = NLA_U8 },
136 	[IFLA_BRPORT_LEARNING]		= { .type = NLA_U8 },
137 	[IFLA_BRPORT_LEARNING_SYNC]	= { .type = NLA_U8 },
138 	[IFLA_BRPORT_UNICAST_FLOOD]	= { .type = NLA_U8 },
139 };
140 
check_flag(struct rtnl_link * link,struct nlattr * attrs[],int type,int flag)141 static void check_flag(struct rtnl_link *link, struct nlattr *attrs[],
142 		       int type, int flag)
143 {
144 	if (attrs[type] && nla_get_u8(attrs[type]))
145 		rtnl_link_bridge_set_flags(link, flag);
146 }
147 
bridge_parse_protinfo(struct rtnl_link * link,struct nlattr * attr,void * data)148 static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
149 				 void *data)
150 {
151 	struct bridge_data *bd = data;
152 	struct nlattr *br_attrs[IFLA_BRPORT_MAX+1];
153 	int err;
154 
155 	/* Backwards compatibility */
156 	if (!nla_is_nested(attr)) {
157 		if (nla_len(attr) < 1)
158 			return -NLE_RANGE;
159 
160 		bd->b_port_state = nla_get_u8(attr);
161 		bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
162 
163 		return 0;
164 	}
165 
166 	if ((err = nla_parse_nested(br_attrs, IFLA_BRPORT_MAX, attr,
167 	     br_attrs_policy)) < 0)
168 		return err;
169 
170 	bd->b_priv_flags |= PRIV_FLAG_NEW_ATTRS;
171 
172 	if (br_attrs[IFLA_BRPORT_STATE]) {
173 		bd->b_port_state = nla_get_u8(br_attrs[IFLA_BRPORT_STATE]);
174 		bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
175 	}
176 
177 	if (br_attrs[IFLA_BRPORT_PRIORITY]) {
178 		bd->b_priority = nla_get_u16(br_attrs[IFLA_BRPORT_PRIORITY]);
179 		bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
180 	}
181 
182 	if (br_attrs[IFLA_BRPORT_COST]) {
183 		bd->b_cost = nla_get_u32(br_attrs[IFLA_BRPORT_COST]);
184 		bd->ce_mask |= BRIDGE_ATTR_COST;
185 	}
186 
187 	check_flag(link, br_attrs, IFLA_BRPORT_MODE, RTNL_BRIDGE_HAIRPIN_MODE);
188 	check_flag(link, br_attrs, IFLA_BRPORT_GUARD, RTNL_BRIDGE_BPDU_GUARD);
189 	check_flag(link, br_attrs, IFLA_BRPORT_PROTECT, RTNL_BRIDGE_ROOT_BLOCK);
190 	check_flag(link, br_attrs, IFLA_BRPORT_FAST_LEAVE, RTNL_BRIDGE_FAST_LEAVE);
191 	check_flag(link, br_attrs, IFLA_BRPORT_UNICAST_FLOOD,
192 	           RTNL_BRIDGE_UNICAST_FLOOD);
193 	check_flag(link, br_attrs, IFLA_BRPORT_LEARNING, RTNL_BRIDGE_LEARNING);
194 	check_flag(link, br_attrs, IFLA_BRPORT_LEARNING_SYNC,
195 	           RTNL_BRIDGE_LEARNING_SYNC);
196 
197 	return 0;
198 }
199 
bridge_parse_af_full(struct rtnl_link * link,struct nlattr * attr_full,void * data)200 static int bridge_parse_af_full(struct rtnl_link *link, struct nlattr *attr_full,
201                                 void *data)
202 {
203 	struct bridge_data *bd = data;
204 	struct bridge_vlan_info *vinfo = NULL;
205 	uint16_t vid_range_start = 0;
206 	uint16_t vid_range_flags = -1;
207 
208 	struct nlattr *attr;
209 	int remaining;
210 
211 	nla_for_each_nested(attr, attr_full, remaining) {
212 
213 		if (nla_type(attr) == IFLA_BRIDGE_MODE) {
214 			bd->b_hwmode = nla_get_u16(attr);
215 			bd->ce_mask |= BRIDGE_ATTR_HWMODE;
216 			continue;
217 		} else if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
218 			continue;
219 
220 		if (nla_len(attr) != sizeof(struct bridge_vlan_info))
221 			return -EINVAL;
222 
223 		vinfo = nla_data(attr);
224 		if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
225 			return -EINVAL;
226 
227 
228 		if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
229 			vid_range_start = vinfo->vid;
230 			vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN);
231 			continue;
232 		}
233 
234 		if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) {
235 			/* sanity check the range flags */
236 			if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) {
237 				NL_DBG(1, "VLAN range flags differ; can not handle it.\n");
238 				return -EINVAL;
239 			}
240 		} else {
241 			vid_range_start = vinfo->vid;
242 		}
243 
244 		for (; vid_range_start <= vinfo->vid; vid_range_start++) {
245 			if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
246 				bd->vlan_info.pvid = vinfo->vid;
247 
248 			if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
249 				set_bit(vid_range_start, bd->vlan_info.untagged_bitmap);
250 
251 			set_bit(vid_range_start, bd->vlan_info.vlan_bitmap);
252 			bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
253 		}
254 
255 		vid_range_flags = -1;
256 	}
257 
258 	return 0;
259 }
260 
_nl_bridge_fill_vlan_info(struct nl_msg * msg,struct rtnl_link_bridge_vlan * vlan_info)261 int _nl_bridge_fill_vlan_info(struct nl_msg *msg, struct rtnl_link_bridge_vlan * vlan_info)
262 {
263 	struct bridge_vlan_info vinfo;
264 	int i = -1, j, k;
265 	int start = -1, prev = -1;
266 	int done;
267 	bool untagged = false;
268 
269 	for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++)
270 	{
271 		int base_bit;
272 		uint32_t a = vlan_info->vlan_bitmap[k];
273 
274 		base_bit = k * 32;
275 		i = -1;
276 		done = 0;
277 		while (!done)
278 		{
279 			j = find_next_bit(i, a);
280 			if (j > 0)
281 			{
282 				/* Skip if id equal to pvid */
283 				if (vlan_info->pvid != 0 && j - 1 + base_bit == vlan_info->pvid)
284 					goto nxt;
285 				/* first hit of any bit */
286 				if (start < 0 && prev < 0)
287 				{
288 					start = prev = j - 1 + base_bit;
289 					/* Start range attribute */
290 					untagged = vlan_id_untagged(vlan_info,start);
291 					vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
292 					vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
293 					vinfo.vid = start;
294 					goto nxt;
295 				}
296 				/* this bit is a continuation of prior bits */
297 				if (j - 2 + base_bit == prev)
298 				{
299 					prev++;
300 					/* Hit end of untagged/tagged range */
301 					if (untagged != vlan_id_untagged(vlan_info,prev))
302 					{
303 						/* put vlan into attributes */
304 						if (start == prev-1)
305 						{
306 							/* only 1 vid in range */
307 							vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
308 							NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
309 						}
310 						else
311 						{
312 							/* end of untagged/tagged range */
313 							NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
314 
315 							vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END;
316 							vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
317 							vinfo.vid = prev-1;
318 							NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
319 						}
320 						/* start of new range */
321 						untagged = !untagged;
322 						vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
323 						vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
324 						vinfo.vid = prev;
325 					}
326 					goto nxt;
327 				}
328 			}
329 			else
330 				done = 1;
331 
332 			if (start >= 0)
333 			{
334 				if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
335 					break;
336 
337 				if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN && start != prev)
338 				{
339 					NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
340 
341 					vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END;
342 					vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
343 					vinfo.vid = prev;
344 					NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
345 				}
346 				else if (start == prev)
347 				{
348 					vinfo.flags = untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
349 					vinfo.vid = start;
350 					NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
351 				}
352 
353 				if (done)
354 					break;
355 			}
356 			if (j > 0)
357 			{
358 				start = prev = j - 1 + base_bit;
359 				untagged = vlan_id_untagged(vlan_info,start);
360 				vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
361 				vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
362 				vinfo.vid = start;
363 			}
364 nxt:
365 			i = j;
366 		}
367 	}
368 
369 	if (vlan_info->pvid != 0)
370 	{
371 		untagged = vlan_id_untagged(vlan_info,vlan_info->pvid);
372 		vinfo.flags = BRIDGE_VLAN_INFO_PVID;
373 		vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
374 		vinfo.vid = vlan_info->pvid;
375 		NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
376 	}
377 
378 	return 0;
379 
380 nla_put_failure:
381 	return -NLE_MSGSIZE;
382 }
383 
bridge_fill_af(struct rtnl_link * link,struct nl_msg * msg,void * data)384 static int bridge_fill_af(struct rtnl_link *link, struct nl_msg *msg,
385 		   void *data)
386 {
387 	struct bridge_data *bd = data;
388 
389 	if (bd->ce_mask & BRIDGE_ATTR_HWMODE)
390 	{
391 		NLA_PUT_U16(msg, IFLA_BRIDGE_MODE, bd->b_hwmode);
392 		bd->b_config_mode = BRIDGE_FLAGS_SELF;
393 		bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
394 	}
395 
396 	if (bd->ce_mask & BRIDGE_ATTR_CONFIG_MODE)
397 		NLA_PUT_U16(msg, IFLA_BRIDGE_FLAGS, bd->b_config_mode);
398 
399 	if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
400 		if (_nl_bridge_fill_vlan_info(msg, &bd->vlan_info)) {
401 			goto nla_put_failure;
402 		}
403 	}
404 
405 	return 0;
406 
407 nla_put_failure:
408 	return -NLE_MSGSIZE;
409 }
410 
bridge_fill_pi(struct rtnl_link * link,struct nl_msg * msg,void * data)411 static int bridge_fill_pi(struct rtnl_link *link, struct nl_msg *msg,
412 		   void *data)
413 {
414 	struct bridge_data *bd = data;
415 
416 	if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
417 		if (bd->b_flags_mask & RTNL_BRIDGE_BPDU_GUARD) {
418 			NLA_PUT_U8(msg, IFLA_BRPORT_GUARD,
419 						bd->b_flags & RTNL_BRIDGE_BPDU_GUARD);
420 		}
421 		if (bd->b_flags_mask & RTNL_BRIDGE_HAIRPIN_MODE) {
422 			NLA_PUT_U8(msg, IFLA_BRPORT_MODE,
423 			           bd->b_flags & RTNL_BRIDGE_HAIRPIN_MODE);
424 		}
425 		if (bd->b_flags_mask & RTNL_BRIDGE_FAST_LEAVE) {
426 			NLA_PUT_U8(msg, IFLA_BRPORT_FAST_LEAVE,
427 			           bd->b_flags & RTNL_BRIDGE_FAST_LEAVE);
428 		}
429 		if (bd->b_flags_mask & RTNL_BRIDGE_ROOT_BLOCK) {
430 			NLA_PUT_U8(msg, IFLA_BRPORT_PROTECT,
431 			           bd->b_flags & RTNL_BRIDGE_ROOT_BLOCK);
432 		}
433 		if (bd->b_flags_mask & RTNL_BRIDGE_UNICAST_FLOOD) {
434 			NLA_PUT_U8(msg, IFLA_BRPORT_UNICAST_FLOOD,
435 			           bd->b_flags & RTNL_BRIDGE_UNICAST_FLOOD);
436 		}
437 		if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING) {
438 			NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING,
439 			           bd->b_flags & RTNL_BRIDGE_LEARNING);
440 		}
441 		if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING_SYNC) {
442 			NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING_SYNC,
443 			           bd->b_flags & RTNL_BRIDGE_LEARNING_SYNC);
444 		}
445 	}
446 
447 	if (bd->ce_mask & BRIDGE_ATTR_COST)
448 		NLA_PUT_U32(msg, IFLA_BRPORT_COST, bd->b_cost);
449 
450 	if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
451 		NLA_PUT_U16(msg, IFLA_BRPORT_PRIORITY, bd->b_priority);
452 
453 	if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
454 		NLA_PUT_U8(msg, IFLA_BRPORT_STATE, bd->b_port_state);
455 
456 	return 0;
457 
458 nla_put_failure:
459 	return -NLE_MSGSIZE;
460 }
461 
bridge_override_rtm(struct rtnl_link * link)462 static int bridge_override_rtm(struct rtnl_link *link) {
463         struct bridge_data *bd;
464 
465         if (!rtnl_link_is_bridge(link))
466                 return 0;
467 
468         bd = bridge_data(link);
469 
470         if (bd->ce_mask & BRIDGE_ATTR_FLAGS)
471                 return 1;
472 
473         return 0;
474 }
475 
bridge_get_af(struct nl_msg * msg,uint32_t * ext_filter_mask)476 static int bridge_get_af(struct nl_msg *msg, uint32_t *ext_filter_mask)
477 {
478 	*ext_filter_mask |= RTEXT_FILTER_BRVLAN;
479 	return 0;
480 }
481 
dump_bitmap(struct nl_dump_params * p,const uint32_t * b)482 static void dump_bitmap(struct nl_dump_params *p, const uint32_t *b)
483 {
484 	int i = -1, j, k;
485 	int start = -1, prev = -1;
486 	int done, found = 0;
487 
488 	for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
489 		int base_bit;
490 		uint32_t a = b[k];
491 
492 		base_bit = k * 32;
493 		i = -1;
494 		done = 0;
495 		while (!done) {
496 			j = find_next_bit(i, a);
497 			if (j > 0) {
498 				/* first hit of any bit */
499 				if (start < 0 && prev < 0) {
500 					start = prev = j - 1 + base_bit;
501 					goto next;
502 				}
503 				/* this bit is a continuation of prior bits */
504 				if (j - 2 + base_bit == prev) {
505 					prev++;
506 					goto next;
507 				}
508 			} else
509 				done = 1;
510 
511 			if (start >= 0) {
512 				found++;
513 				if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
514 					break;
515 
516 				nl_dump(p, " %d", start);
517 				if (start != prev)
518 					nl_dump(p, "-%d", prev);
519 
520 				if (done)
521 					break;
522 			}
523 			if (j > 0)
524 				start = prev = j - 1 + base_bit;
525 next:
526 			i = j;
527 		}
528 	}
529 	if (!found)
530 		nl_dump(p, " <none>");
531 
532 	return;
533 }
534 
rtnl_link_bridge_dump_vlans(struct nl_dump_params * p,struct bridge_data * bd)535 static void rtnl_link_bridge_dump_vlans(struct nl_dump_params *p,
536 					struct bridge_data *bd)
537 {
538 	nl_dump(p, "pvid %u", bd->vlan_info.pvid);
539 
540 	nl_dump(p, "   all vlans:");
541 	dump_bitmap(p, bd->vlan_info.vlan_bitmap);
542 
543 	nl_dump(p, "   untagged vlans:");
544 	dump_bitmap(p, bd->vlan_info.untagged_bitmap);
545 }
546 
bridge_dump_details(struct rtnl_link * link,struct nl_dump_params * p,void * data)547 static void bridge_dump_details(struct rtnl_link *link,
548 				struct nl_dump_params *p, void *data)
549 {
550 	struct bridge_data *bd = data;
551 
552 	nl_dump_line(p, "    bridge: ");
553 
554 	if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
555 		nl_dump(p, "port-state %u ", bd->b_port_state);
556 
557 	if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
558 		nl_dump(p, "prio %u ", bd->b_priority);
559 
560 	if (bd->ce_mask & BRIDGE_ATTR_COST)
561 		nl_dump(p, "cost %u ", bd->b_cost);
562 
563 	if (bd->ce_mask & BRIDGE_ATTR_HWMODE) {
564 		char hbuf[32];
565 
566 		rtnl_link_bridge_hwmode2str(bd->b_hwmode, hbuf, sizeof(hbuf));
567 		nl_dump(p, "hwmode %s", hbuf);
568 	}
569 
570 	if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
571 		rtnl_link_bridge_dump_vlans(p, bd);
572 
573 	if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
574 		char buf[256];
575 
576 		rtnl_link_bridge_flags2str(bd->b_flags & bd->b_flags_mask,
577 					   buf, sizeof(buf));
578 		nl_dump(p, "%s", buf);
579 	}
580 
581 	nl_dump(p, "\n");
582 }
583 
bridge_compare(struct rtnl_link * _a,struct rtnl_link * _b,int family,uint32_t attrs,int flags)584 static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b,
585 			  int family, uint32_t attrs, int flags)
586 {
587 	struct bridge_data *a = bridge_data(_a);
588 	struct bridge_data *b = bridge_data(_b);
589 	int diff = 0;
590 
591 #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
592 	diff |= _DIFF(BRIDGE_ATTR_PORT_STATE,
593 		      a->b_port_state != b->b_port_state);
594 	diff |= _DIFF(BRIDGE_ATTR_PRIORITY, a->b_priority != b->b_priority);
595 	diff |= _DIFF(BRIDGE_ATTR_COST, a->b_cost != b->b_cost);
596 	diff |= _DIFF(BRIDGE_ATTR_PORT_VLAN,
597 		      memcmp(&a->vlan_info, &b->vlan_info,
598 			     sizeof(struct rtnl_link_bridge_vlan)));
599 	diff |= _DIFF(BRIDGE_ATTR_HWMODE, a->b_hwmode != b->b_hwmode);
600 	diff |= _DIFF(BRIDGE_ATTR_CONFIG_MODE, a->b_config_mode != b->b_config_mode);
601 
602 	if (flags & LOOSE_COMPARISON)
603 		diff |= _DIFF(BRIDGE_ATTR_FLAGS,
604 			      (a->b_flags ^ b->b_flags) & b->b_flags_mask);
605 	else
606 		diff |= _DIFF(BRIDGE_ATTR_FLAGS, a->b_flags != b->b_flags);
607 #undef _DIFF
608 
609 	return diff;
610 }
611 /** @endcond */
612 
613 /**
614  * Allocate link object of type bridge
615  *
616  * @return Allocated link object or NULL.
617  */
rtnl_link_bridge_alloc(void)618 struct rtnl_link *rtnl_link_bridge_alloc(void)
619 {
620 	struct rtnl_link *link;
621 
622 	if (!(link = rtnl_link_alloc()))
623 		return NULL;
624 
625 	if (rtnl_link_set_type(link, "bridge") < 0) {
626 		rtnl_link_put(link);
627 		return NULL;
628 	}
629 
630 	return link;
631 }
632 
633 /**
634  * Create a new kernel bridge device
635  * @arg sk              netlink socket
636  * @arg name            name of the bridge device or NULL
637  *
638  * Creates a new bridge device in the kernel. If no name is
639  * provided, the kernel will automatically pick a name of the
640  * form "type%d" (e.g. bridge0, vlan1, etc.)
641  *
642  * @return 0 on success or a negative error code
643 */
rtnl_link_bridge_add(struct nl_sock * sk,const char * name)644 int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
645 {
646 	int err;
647 	struct rtnl_link *link;
648 
649 	if (!(link = rtnl_link_bridge_alloc()))
650 		return -NLE_NOMEM;
651 
652 	if(name)
653 		rtnl_link_set_name(link, name);
654 
655 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
656 	rtnl_link_put(link);
657 
658 	return err;
659 }
660 
661 /**
662  * Check if a link is a bridge
663  * @arg link		Link object
664  *
665  * @return 1 if the link is a bridge, 0 otherwise.
666  */
rtnl_link_is_bridge(struct rtnl_link * link)667 int rtnl_link_is_bridge(struct rtnl_link *link)
668 {
669 	return link->l_family == AF_BRIDGE &&
670 	       link->l_af_ops == &bridge_ops;
671 }
672 
673 /**
674  * Check if bridge has extended information
675  * @arg link		Link object of type bridge
676  *
677  * Checks if the bridge object has been constructed based on
678  * information that is only available in newer kernels. This
679  * affectes the following functions:
680  *  - rtnl_link_bridge_get_cost()
681  *  - rtnl_link_bridge_get_priority()
682  *  - rtnl_link_bridge_get_flags()
683  *
684  * @return 1 if extended information is available, otherwise 0 is returned.
685  */
rtnl_link_bridge_has_ext_info(struct rtnl_link * link)686 int rtnl_link_bridge_has_ext_info(struct rtnl_link *link)
687 {
688 	struct bridge_data *bd;
689 
690 	if (!rtnl_link_is_bridge(link))
691 		return 0;
692 
693 	bd = bridge_data(link);
694 	return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS);
695 }
696 
697 /**
698  * Set Spanning Tree Protocol (STP) port state
699  * @arg link		Link object of type bridge
700  * @arg state		New STP port state
701  *
702  * The value of state must be one of the following:
703  *   - BR_STATE_DISABLED
704  *   - BR_STATE_LISTENING
705  *   - BR_STATE_LEARNING
706  *   - BR_STATE_FORWARDING
707  *   - BR_STATE_BLOCKING
708  *
709  * @see rtnl_link_bridge_get_port_state()
710  *
711  * @return 0 on success or a negative error code.
712  * @retval -NLE_OPNOTSUPP Link is not a bridge
713  * @retval -NLE_INVAL Invalid state value (0..BR_STATE_BLOCKING)
714  */
rtnl_link_bridge_set_port_state(struct rtnl_link * link,uint8_t state)715 int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
716 {
717 	struct bridge_data *bd = bridge_data(link);
718 
719 	IS_BRIDGE_LINK_ASSERT(link);
720 
721 	if (state > BR_STATE_BLOCKING)
722 		return -NLE_INVAL;
723 
724 	bd->b_port_state = state;
725 	bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
726 
727 	return 0;
728 }
729 
730 /**
731  * Get Spanning Tree Protocol (STP) port state
732  * @arg link		Link object of type bridge
733  *
734  * @see rtnl_link_bridge_set_port_state()
735  *
736  * @return The STP port state or a negative error code.
737  * @retval -NLE_OPNOTSUPP Link is not a bridge
738  */
rtnl_link_bridge_get_port_state(struct rtnl_link * link)739 int rtnl_link_bridge_get_port_state(struct rtnl_link *link)
740 {
741 	struct bridge_data *bd = bridge_data(link);
742 
743 	IS_BRIDGE_LINK_ASSERT(link);
744 
745 	return bd->b_port_state;
746 }
747 
748 /**
749  * Set priority
750  * @arg link		Link object of type bridge
751  * @arg prio		Bridge priority
752  *
753  * @see rtnl_link_bridge_get_priority()
754  *
755  * @return 0 on success or a negative error code.
756  * @retval -NLE_OPNOTSUPP Link is not a bridge
757  */
rtnl_link_bridge_set_priority(struct rtnl_link * link,uint16_t prio)758 int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
759 {
760 	struct bridge_data *bd = bridge_data(link);
761 
762 	IS_BRIDGE_LINK_ASSERT(link);
763 
764 	bd->b_priority = prio;
765 	bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
766 
767 	return 0;
768 }
769 
770 /**
771  * Get priority
772  * @arg link		Link object of type bridge
773  *
774  * @see rtnl_link_bridge_set_priority()
775  *
776  * @return 0 on success or a negative error code.
777  * @retval -NLE_OPNOTSUPP Link is not a bridge
778  */
rtnl_link_bridge_get_priority(struct rtnl_link * link)779 int rtnl_link_bridge_get_priority(struct rtnl_link *link)
780 {
781 	struct bridge_data *bd = bridge_data(link);
782 
783 	IS_BRIDGE_LINK_ASSERT(link);
784 
785 	return bd->b_priority;
786 }
787 
788 /**
789  * Set Spanning Tree Protocol (STP) path cost
790  * @arg link		Link object of type bridge
791  * @arg cost		New STP path cost value
792  *
793  * @see rtnl_link_bridge_get_cost()
794  *
795  * @return The bridge priority or a negative error code.
796  * @retval -NLE_OPNOTSUPP Link is not a bridge
797  */
rtnl_link_bridge_set_cost(struct rtnl_link * link,uint32_t cost)798 int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
799 {
800 	struct bridge_data *bd = bridge_data(link);
801 
802 	IS_BRIDGE_LINK_ASSERT(link);
803 
804 	bd->b_cost = cost;
805 	bd->ce_mask |= BRIDGE_ATTR_COST;
806 
807 	return 0;
808 }
809 
810 /**
811  * Get Spanning Tree Protocol (STP) path cost
812  * @arg link		Link object of type bridge
813  * @arg cost		Pointer to store STP cost value
814  *
815  * @see rtnl_link_bridge_set_cost()
816  *
817  * @return 0 on success or a negative error code.
818  * @retval -NLE_OPNOTSUPP Link is not a bridge
819  * @retval -NLE_INVAL `cost` is not a valid pointer
820  */
rtnl_link_bridge_get_cost(struct rtnl_link * link,uint32_t * cost)821 int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
822 {
823 	struct bridge_data *bd = bridge_data(link);
824 
825 	IS_BRIDGE_LINK_ASSERT(link);
826 
827 	if (!cost)
828 		return -NLE_INVAL;
829 
830 	*cost = bd->b_cost;
831 
832 	return 0;
833 }
834 
835 /**
836  * Unset flags
837  * @arg link		Link object of type bridge
838  * @arg flags		Bridging flags to unset
839  *
840  * @see rtnl_link_bridge_set_flags()
841  * @see rtnl_link_bridge_get_flags()
842  *
843  * @return 0 on success or a negative error code.
844  * @retval -NLE_OPNOTSUPP Link is not a bridge
845  */
rtnl_link_bridge_unset_flags(struct rtnl_link * link,unsigned int flags)846 int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
847 {
848 	struct bridge_data *bd = bridge_data(link);
849 
850 	IS_BRIDGE_LINK_ASSERT(link);
851 
852 	bd->b_flags_mask |= flags;
853 	bd->b_flags &= ~flags;
854 	bd->ce_mask |= BRIDGE_ATTR_FLAGS;
855 
856 	return 0;
857 }
858 
859 /**
860  * Set flags
861  * @arg link		Link object of type bridge
862  * @arg flags		Bridging flags to set
863  *
864  * Valid flags are:
865  *   - RTNL_BRIDGE_HAIRPIN_MODE
866  *   - RTNL_BRIDGE_BPDU_GUARD
867  *   - RTNL_BRIDGE_ROOT_BLOCK
868  *   - RTNL_BRIDGE_FAST_LEAVE
869  *   - RTNL_BRIDGE_UNICAST_FLOOD
870  *   - RTNL_BRIDGE_LEARNING
871  *   - RTNL_BRIDGE_LEARNING_SYNC
872  *
873  * @see rtnl_link_bridge_unset_flags()
874  * @see rtnl_link_bridge_get_flags()
875  *
876  * @return 0 on success or a negative error code.
877  * @retval -NLE_OPNOTSUPP Link is not a bridge
878  */
rtnl_link_bridge_set_flags(struct rtnl_link * link,unsigned int flags)879 int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
880 {
881 	struct bridge_data *bd = bridge_data(link);
882 
883 	IS_BRIDGE_LINK_ASSERT(link);
884 
885 	bd->b_flags_mask |= flags;
886 	bd->b_flags |= flags;
887 	bd->ce_mask |= BRIDGE_ATTR_FLAGS;
888 
889 	return 0;
890 }
891 
892 /**
893  * Get flags
894  * @arg link		Link object of type bridge
895  *
896  * @see rtnl_link_bridge_set_flags()
897  * @see rtnl_link_bridge_unset_flags()
898  *
899  * @return Flags or a negative error code.
900  * @retval -NLE_OPNOTSUPP Link is not a bridge
901  */
rtnl_link_bridge_get_flags(struct rtnl_link * link)902 int rtnl_link_bridge_get_flags(struct rtnl_link *link)
903 {
904 	struct bridge_data *bd = bridge_data(link);
905 
906 	IS_BRIDGE_LINK_ASSERT(link);
907 
908 	return bd->b_flags;
909 }
910 
911 /**
912  * Set link change type to self
913  * @arg link		Link Object of type bridge
914  *
915  * This will set the bridge change flag to self, meaning that changes to
916  * be applied with this link object will be applied directly to the physical
917  * device in a bridge instead of the virtual device.
918  *
919  * @return 0 on success or negative error code
920  * @return -NLE_OPNOTSUP Link is not a bridge
921  */
rtnl_link_bridge_set_self(struct rtnl_link * link)922 int rtnl_link_bridge_set_self(struct rtnl_link *link)
923 {
924 	struct bridge_data *bd = bridge_data(link);
925 
926 	IS_BRIDGE_LINK_ASSERT(link);
927 
928 	bd->b_config_mode = BRIDGE_FLAGS_SELF;
929 	bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
930 
931 	return 0;
932 }
933 
934 /**
935  * Set link change type to master
936  * @arg link		Link Object of type bridge
937  *
938  * This will set the bridge change flag to master, meaning that changes to
939  * be applied with this link object will be applied directly to the virtual
940  * device in a bridge instead of the physical device.
941  *
942  * @return 0 on success or negative error code
943  * @return -NLE_OPNOTSUP Link is not a bridge
944  */
rtnl_link_bridge_set_master(struct rtnl_link * link)945 int rtnl_link_bridge_set_master(struct rtnl_link *link)
946 {
947 	struct bridge_data *bd = bridge_data(link);
948 
949 	IS_BRIDGE_LINK_ASSERT(link);
950 
951 	bd->b_config_mode = BRIDGE_FLAGS_MASTER;
952 	bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
953 
954 	return 0;
955 }
956 
957 /**
958  * Get hardware mode
959  * @arg link            Link object of type bridge
960  * @arg hwmode          Output argument.
961  *
962  * @see rtnl_link_bridge_set_hwmode()
963  *
964  * @return 0 if hardware mode is present and returned in hwmode
965  * @return -NLE_NOATTR if hardware mode is not present
966  * @return -NLE_OPNOTSUP Link is not a bridge
967  */
rtnl_link_bridge_get_hwmode(struct rtnl_link * link,uint16_t * hwmode)968 int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
969 {
970 	struct bridge_data *bd = bridge_data(link);
971 
972 	IS_BRIDGE_LINK_ASSERT(link);
973 
974 	if (!(bd->ce_mask & BRIDGE_ATTR_HWMODE))
975 		return -NLE_NOATTR;
976 
977 	*hwmode = bd->b_hwmode;
978 	return 0;
979 }
980 
981 /**
982  * Set hardware mode
983  * @arg link		Link object of type bridge
984  * @arg hwmode		Hardware mode to set on link
985  *
986  * This will set the hardware mode of a link when it supports hardware
987  * offloads for bridging.
988  * @see rtnl_link_bridge_get_hwmode()
989  *
990  * Valid modes are:
991  *   - RTNL_BRIDGE_HWMODE_VEB
992  *   - RTNL_BRIDGE_HWMODE_VEPA
993  *
994  * When setting hardware mode, the change type will be set to self.
995  * @see rtnl_link_bridge_set_self()
996  *
997  * @return 0 on success or negative error code
998  * @return -NLE_OPNOTSUP Link is not a bridge
999  * @return -NLE_INVAL when specified hwmode is unsupported.
1000  */
rtnl_link_bridge_set_hwmode(struct rtnl_link * link,uint16_t hwmode)1001 int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
1002 {
1003 	int err;
1004 	struct bridge_data *bd = bridge_data(link);
1005 
1006 	if (hwmode > RTNL_BRIDGE_HWMODE_MAX)
1007 		return -NLE_INVAL;
1008 
1009 	if ((err = rtnl_link_bridge_set_self(link)) < 0)
1010 		return err;
1011 
1012 	bd->b_hwmode = hwmode;
1013 	bd->ce_mask |= BRIDGE_ATTR_HWMODE;
1014 
1015 	return 0;
1016 }
1017 
1018 
1019 static const struct trans_tbl bridge_flags[] = {
1020 	__ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode),
1021 	__ADD(RTNL_BRIDGE_BPDU_GUARD, 	bpdu_guard),
1022 	__ADD(RTNL_BRIDGE_ROOT_BLOCK,	root_block),
1023 	__ADD(RTNL_BRIDGE_FAST_LEAVE,	fast_leave),
1024 	__ADD(RTNL_BRIDGE_UNICAST_FLOOD,	flood),
1025 	__ADD(RTNL_BRIDGE_LEARNING,			learning),
1026 	__ADD(RTNL_BRIDGE_LEARNING_SYNC,	learning_sync),
1027 };
1028 
1029 /**
1030  * @name Flag Translation
1031  * @{
1032  */
1033 
rtnl_link_bridge_flags2str(int flags,char * buf,size_t len)1034 char *rtnl_link_bridge_flags2str(int flags, char *buf, size_t len)
1035 {
1036 	return __flags2str(flags, buf, len, bridge_flags, ARRAY_SIZE(bridge_flags));
1037 }
1038 
rtnl_link_bridge_str2flags(const char * name)1039 int rtnl_link_bridge_str2flags(const char *name)
1040 {
1041 	return __str2flags(name, bridge_flags, ARRAY_SIZE(bridge_flags));
1042 }
1043 
1044 /** @} */
1045 
1046 static const struct trans_tbl port_states[] = {
1047 	__ADD(BR_STATE_DISABLED, disabled),
1048 	__ADD(BR_STATE_LISTENING, listening),
1049 	__ADD(BR_STATE_LEARNING, learning),
1050 	__ADD(BR_STATE_FORWARDING, forwarding),
1051 	__ADD(BR_STATE_BLOCKING, blocking),
1052 };
1053 
1054 /**
1055  * @name Port State Translation
1056  * @{
1057  */
1058 
rtnl_link_bridge_portstate2str(int st,char * buf,size_t len)1059 char *rtnl_link_bridge_portstate2str(int st, char *buf, size_t len)
1060 {
1061 	return __type2str(st, buf, len, port_states, ARRAY_SIZE(port_states));
1062 }
1063 
rtnl_link_bridge_str2portstate(const char * name)1064 int rtnl_link_bridge_str2portstate(const char *name)
1065 {
1066 	return __str2type(name, port_states, ARRAY_SIZE(port_states));
1067 }
1068 
1069 /** @} */
1070 
1071 static const struct trans_tbl hw_modes[] = {
1072 	__ADD(RTNL_BRIDGE_HWMODE_VEB, veb),
1073 	__ADD(RTNL_BRIDGE_HWMODE_VEPA, vepa),
1074 	__ADD(RTNL_BRIDGE_HWMODE_UNDEF, undef),
1075 };
1076 
1077 /**
1078  * @name Hardware Mode Translation
1079  * @{
1080  */
1081 
rtnl_link_bridge_hwmode2str(uint16_t st,char * buf,size_t len)1082 char *rtnl_link_bridge_hwmode2str(uint16_t st, char *buf, size_t len) {
1083 	return __type2str(st, buf, len, hw_modes, ARRAY_SIZE(hw_modes));
1084 }
1085 
rtnl_link_bridge_str2hwmode(const char * name)1086 uint16_t rtnl_link_bridge_str2hwmode(const char *name)
1087 {
1088 	return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
1089 }
1090 
1091 /** @} */
1092 
1093 /**
1094  * Enable the ability to set vlan info
1095  * @arg link		Link object of type bridge
1096  *
1097  * @return 0 on success or negative error code
1098  * @return -NLE_OPNOTSUP 	Link is not a bridge
1099  */
rtnl_link_bridge_enable_vlan(struct rtnl_link * link)1100 int rtnl_link_bridge_enable_vlan(struct rtnl_link *link)
1101 {
1102 	struct bridge_data *bd = bridge_data(link);
1103 
1104 	IS_BRIDGE_LINK_ASSERT(link);
1105 
1106 	bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
1107 
1108 	return 0;
1109 }
1110 
1111 /**
1112  * @name Quality of Service
1113  * @{
1114  */
1115 
1116 /**
1117  * Set port vlan membership range
1118  * @arg link		Link object of type bridge
1119  * @arg start		Start of membership range.
1120  * @arg end			End of membership range.
1121  * @arg untagged	Set membership range to be untagged.
1122  *
1123  * This will set the vlan membership range for a bridge port.
1124  * This will unset the untagged membership if untagged is false.
1125  * Supported range is 1-4094
1126  *
1127  * @return 0 on success or negative error code
1128  * @return -NLE_NOATTR		if port vlan attribute not present
1129  * @return -NLE_OPNOTSUP 	Link is not a bridge
1130  * @return -NLE_INVAL 		range is not in supported range.
1131  */
rtnl_link_bridge_set_port_vlan_map_range(struct rtnl_link * link,uint16_t start,uint16_t end,int untagged)1132 int rtnl_link_bridge_set_port_vlan_map_range (struct rtnl_link *link, uint16_t start, uint16_t end, int untagged)
1133 {
1134 	struct rtnl_link_bridge_vlan * vinfo;
1135 
1136 	IS_BRIDGE_LINK_ASSERT(link);
1137 
1138 	vinfo = rtnl_link_bridge_get_port_vlan(link);
1139 
1140 	if (!vinfo)
1141 		return -NLE_NOATTR;
1142 
1143 	if (start == 0 || start > end || end >= VLAN_VID_MASK)
1144 		return -NLE_INVAL;
1145 
1146 	for (uint16_t i = start; i <= end; i++)
1147 	{
1148 		set_bit(i,vinfo->vlan_bitmap);
1149 		if (untagged) {
1150 			set_bit(i,vinfo->untagged_bitmap);
1151 		} else {
1152 			unset_bit(i,vinfo->untagged_bitmap);
1153 		}
1154 	}
1155 	return 0;
1156 }
1157 
1158 /**
1159  * Unset port vlan membership range
1160  * @arg link		Link object of type bridge
1161  * @arg start		Start of membership range.
1162  * @arg end			End of membership range.
1163  *
1164  * This will unset the vlan membership range for a bridge port
1165  * for both tagged and untagged membership.
1166  * Supported range is 1-4094
1167  *
1168  * @return 0 on success or negative error code
1169  * @return -NLE_NOATTR		if port vlan attribute not present
1170  * @return -NLE_OPNOTSUP 	Link is not a bridge
1171  * @return -NLE_INVAL 		range is not in supported range.
1172  */
rtnl_link_bridge_unset_port_vlan_map_range(struct rtnl_link * link,uint16_t start,uint16_t end)1173 int rtnl_link_bridge_unset_port_vlan_map_range (struct rtnl_link *link, uint16_t start, uint16_t end)
1174 {
1175 	struct rtnl_link_bridge_vlan * vinfo;
1176 
1177 	IS_BRIDGE_LINK_ASSERT(link);
1178 
1179 	vinfo = rtnl_link_bridge_get_port_vlan(link);
1180 
1181 	if (!vinfo)
1182 		return -NLE_NOATTR;
1183 
1184 	if (start == 0 || start > end || end >= VLAN_VID_MASK)
1185 		return -NLE_INVAL;
1186 
1187 	for (uint16_t i = start; i <= end; i++)
1188 	{
1189 		unset_bit(i,vinfo->vlan_bitmap);
1190 		unset_bit(i,vinfo->untagged_bitmap);
1191 	}
1192 	return 0;
1193 }
1194 
1195 /**
1196  * Set port primary vlan id
1197  * @arg link		Link object of type bridge
1198  * @arg pvid		PVID to set.
1199  * @arg untagged	Set vlan id to be untagged.
1200  *
1201  * This will set the primary vlan id for a bridge port.
1202  * Supported range is 0-4094, Setting pvid to 0 will unset it.
1203  * You will most likely want to set/unset pvid in the vlan map.
1204  * @see rtnl_link_bridge_set_port_vlan_map_range()
1205  * @see rtnl_link_bridge_unset_port_vlan_map_range()
1206  *
1207  * @return 0 on success or negative error code
1208  * @return -NLE_NOATTR		if port vlan attribute not present
1209  * @return -NLE_OPNOTSUP 	Link is not a bridge
1210  * @return -NLE_INVAL 		PVID is above supported range.
1211  */
rtnl_link_bridge_set_port_vlan_pvid(struct rtnl_link * link,uint16_t pvid)1212 int rtnl_link_bridge_set_port_vlan_pvid (struct rtnl_link *link, uint16_t pvid)
1213 {
1214 	struct rtnl_link_bridge_vlan * vinfo;
1215 
1216 	IS_BRIDGE_LINK_ASSERT(link);
1217 
1218 	vinfo = rtnl_link_bridge_get_port_vlan(link);
1219 
1220 	if (!vinfo)
1221 		return -NLE_NOATTR;
1222 
1223 	if (pvid >= VLAN_VID_MASK)
1224 		return -NLE_INVAL;
1225 
1226 	vinfo->pvid = pvid;
1227 
1228 	return 0;
1229 }
1230 
1231 /** @} */
1232 
rtnl_link_bridge_pvid(struct rtnl_link * link)1233 int rtnl_link_bridge_pvid(struct rtnl_link *link)
1234 {
1235 	struct bridge_data *bd;
1236 
1237 	IS_BRIDGE_LINK_ASSERT(link);
1238 
1239 	bd = link->l_af_data[AF_BRIDGE];
1240 	if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
1241 		return (int) bd->vlan_info.pvid;
1242 
1243 	return -EINVAL;
1244 }
1245 
rtnl_link_bridge_has_vlan(struct rtnl_link * link)1246 int rtnl_link_bridge_has_vlan(struct rtnl_link *link)
1247 {
1248 	struct bridge_data *bd;
1249 	int i;
1250 
1251 	IS_BRIDGE_LINK_ASSERT(link);
1252 
1253 	bd = link->l_af_data[AF_BRIDGE];
1254 	if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
1255 		if (bd->vlan_info.pvid)
1256 			return 1;
1257 
1258 		for (i = 0; i < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; ++i) {
1259 			if (bd->vlan_info.vlan_bitmap[i] ||
1260 			    bd->vlan_info.untagged_bitmap[i])
1261 				return 1;
1262 		}
1263 	}
1264 	return 0;
1265 }
1266 
rtnl_link_bridge_get_port_vlan(struct rtnl_link * link)1267 struct rtnl_link_bridge_vlan *rtnl_link_bridge_get_port_vlan(struct rtnl_link *link)
1268 {
1269 	struct bridge_data *data;
1270 
1271 	if (!rtnl_link_is_bridge(link))
1272 		return NULL;
1273 
1274 	data = link->l_af_data[AF_BRIDGE];
1275 	if (data && (data->ce_mask & BRIDGE_ATTR_PORT_VLAN))
1276 		return &data->vlan_info;
1277 
1278 	return NULL;
1279 }
1280 
1281 static struct rtnl_link_af_ops bridge_ops = {
1282 	.ao_family			= AF_BRIDGE,
1283 	.ao_alloc			= &bridge_alloc,
1284 	.ao_clone			= &bridge_clone,
1285 	.ao_free			= &bridge_free,
1286 	.ao_parse_protinfo		= &bridge_parse_protinfo,
1287 	.ao_dump[NL_DUMP_DETAILS]	= &bridge_dump_details,
1288 	.ao_compare			= &bridge_compare,
1289 	.ao_parse_af_full		= &bridge_parse_af_full,
1290 	.ao_get_af			= &bridge_get_af,
1291 	.ao_fill_af			= &bridge_fill_af,
1292 	.ao_fill_pi			= &bridge_fill_pi,
1293 	.ao_fill_pi_flags	= NLA_F_NESTED,
1294 	.ao_override_rtm		= &bridge_override_rtm,
1295 	.ao_fill_af_no_nest	= 1,
1296 };
1297 
bridge_init(void)1298 static void _nl_init bridge_init(void)
1299 {
1300 	rtnl_link_af_register(&bridge_ops);
1301 }
1302 
bridge_exit(void)1303 static void _nl_exit bridge_exit(void)
1304 {
1305 	rtnl_link_af_unregister(&bridge_ops);
1306 }
1307 
1308 /** @} */
1309