• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2010-2013 Thomas Graf <tgraf@suug.ch>
4  */
5 
6 /**
7  * @ingroup link
8  * @defgroup bridge Bridging
9  *
10  * @details
11  * @{
12  */
13 
14 #include <netlink-private/netlink.h>
15 #include <netlink/netlink.h>
16 #include <netlink/attr.h>
17 #include <netlink/route/rtnl.h>
18 #include <netlink/route/link/bridge.h>
19 #include <netlink-private/route/link/api.h>
20 #include <linux/if_bridge.h>
21 
22 #define VLAN_VID_MASK           0x0fff /* VLAN Identifier */
23 
24 /** @cond SKIP */
25 #define BRIDGE_ATTR_PORT_STATE		(1 << 0)
26 #define BRIDGE_ATTR_PRIORITY		(1 << 1)
27 #define BRIDGE_ATTR_COST		(1 << 2)
28 #define BRIDGE_ATTR_FLAGS		(1 << 3)
29 #define BRIDGE_ATTR_PORT_VLAN           (1 << 4)
30 #define BRIDGE_ATTR_HWMODE		(1 << 5)
31 #define BRIDGE_ATTR_SELF		(1 << 6)
32 
33 #define PRIV_FLAG_NEW_ATTRS		(1 << 0)
34 
35 struct bridge_data
36 {
37 	uint8_t			b_port_state;
38 	uint8_t			b_priv_flags; /* internal flags */
39 	uint16_t		b_hwmode;
40 	uint16_t		b_priority;
41 	uint16_t		b_self; /* here for comparison reasons */
42 	uint32_t		b_cost;
43 	uint32_t		b_flags;
44 	uint32_t		b_flags_mask;
45 	uint32_t                ce_mask; /* HACK to support attr macros */
46 	struct rtnl_link_bridge_vlan vlan_info;
47 };
48 
set_bit(unsigned nr,uint32_t * addr)49 static void set_bit(unsigned nr, uint32_t *addr)
50 {
51 	if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
52 		addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
53 }
54 
find_next_bit(int i,uint32_t x)55 static int find_next_bit(int i, uint32_t x)
56 {
57 	int j;
58 
59 	if (i >= 32)
60 		return -1;
61 
62 	/* find first bit */
63 	if (i < 0)
64 		return __builtin_ffs(x);
65 
66 	/* mask off prior finds to get next */
67 	j = __builtin_ffs(x >> i);
68 	return j ? j + i : 0;
69 }
70 
71 static struct rtnl_link_af_ops bridge_ops;
72 
73 #define IS_BRIDGE_LINK_ASSERT(link) \
74 	if (!rtnl_link_is_bridge(link)) { \
75 		APPBUG("A function was expecting a link object of type bridge."); \
76 		return -NLE_OPNOTSUPP; \
77 	}
78 
bridge_data(struct rtnl_link * link)79 static inline struct bridge_data *bridge_data(struct rtnl_link *link)
80 {
81 	return rtnl_link_af_data(link, &bridge_ops);
82 }
83 
bridge_alloc(struct rtnl_link * link)84 static void *bridge_alloc(struct rtnl_link *link)
85 {
86 	return calloc(1, sizeof(struct bridge_data));
87 }
88 
bridge_clone(struct rtnl_link * link,void * data)89 static void *bridge_clone(struct rtnl_link *link, void *data)
90 {
91 	struct bridge_data *bd;
92 
93 	if ((bd = bridge_alloc(link)))
94 		memcpy(bd, data, sizeof(*bd));
95 
96 	return bd;
97 }
98 
bridge_free(struct rtnl_link * link,void * data)99 static void bridge_free(struct rtnl_link *link, void *data)
100 {
101 	free(data);
102 }
103 
104 static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = {
105 	[IFLA_BRPORT_STATE]		= { .type = NLA_U8 },
106 	[IFLA_BRPORT_PRIORITY]		= { .type = NLA_U16 },
107 	[IFLA_BRPORT_COST]		= { .type = NLA_U32 },
108 	[IFLA_BRPORT_MODE]		= { .type = NLA_U8 },
109 	[IFLA_BRPORT_GUARD]		= { .type = NLA_U8 },
110 	[IFLA_BRPORT_PROTECT]		= { .type = NLA_U8 },
111 	[IFLA_BRPORT_FAST_LEAVE]	= { .type = NLA_U8 },
112 	[IFLA_BRPORT_LEARNING]		= { .type = NLA_U8 },
113 	[IFLA_BRPORT_LEARNING_SYNC]	= { .type = NLA_U8 },
114 	[IFLA_BRPORT_UNICAST_FLOOD]	= { .type = NLA_U8 },
115 };
116 
check_flag(struct rtnl_link * link,struct nlattr * attrs[],int type,int flag)117 static void check_flag(struct rtnl_link *link, struct nlattr *attrs[],
118 		       int type, int flag)
119 {
120 	if (attrs[type] && nla_get_u8(attrs[type]))
121 		rtnl_link_bridge_set_flags(link, flag);
122 }
123 
bridge_parse_protinfo(struct rtnl_link * link,struct nlattr * attr,void * data)124 static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
125 				 void *data)
126 {
127 	struct bridge_data *bd = data;
128 	struct nlattr *br_attrs[IFLA_BRPORT_MAX+1];
129 	int err;
130 
131 	/* Backwards compatibility */
132 	if (!nla_is_nested(attr)) {
133 		if (nla_len(attr) < 1)
134 			return -NLE_RANGE;
135 
136 		bd->b_port_state = nla_get_u8(attr);
137 		bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
138 
139 		return 0;
140 	}
141 
142 	if ((err = nla_parse_nested(br_attrs, IFLA_BRPORT_MAX, attr,
143 	     br_attrs_policy)) < 0)
144 		return err;
145 
146 	bd->b_priv_flags |= PRIV_FLAG_NEW_ATTRS;
147 
148 	if (br_attrs[IFLA_BRPORT_STATE]) {
149 		bd->b_port_state = nla_get_u8(br_attrs[IFLA_BRPORT_STATE]);
150 		bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
151 	}
152 
153 	if (br_attrs[IFLA_BRPORT_PRIORITY]) {
154 		bd->b_priority = nla_get_u16(br_attrs[IFLA_BRPORT_PRIORITY]);
155 		bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
156 	}
157 
158 	if (br_attrs[IFLA_BRPORT_COST]) {
159 		bd->b_cost = nla_get_u32(br_attrs[IFLA_BRPORT_COST]);
160 		bd->ce_mask |= BRIDGE_ATTR_COST;
161 	}
162 
163 	check_flag(link, br_attrs, IFLA_BRPORT_MODE, RTNL_BRIDGE_HAIRPIN_MODE);
164 	check_flag(link, br_attrs, IFLA_BRPORT_GUARD, RTNL_BRIDGE_BPDU_GUARD);
165 	check_flag(link, br_attrs, IFLA_BRPORT_PROTECT, RTNL_BRIDGE_ROOT_BLOCK);
166 	check_flag(link, br_attrs, IFLA_BRPORT_FAST_LEAVE, RTNL_BRIDGE_FAST_LEAVE);
167 	check_flag(link, br_attrs, IFLA_BRPORT_UNICAST_FLOOD,
168 	           RTNL_BRIDGE_UNICAST_FLOOD);
169 	check_flag(link, br_attrs, IFLA_BRPORT_LEARNING, RTNL_BRIDGE_LEARNING);
170 	check_flag(link, br_attrs, IFLA_BRPORT_LEARNING_SYNC,
171 	           RTNL_BRIDGE_LEARNING_SYNC);
172 
173 	return 0;
174 }
175 
bridge_parse_af_full(struct rtnl_link * link,struct nlattr * attr_full,void * data)176 static int bridge_parse_af_full(struct rtnl_link *link, struct nlattr *attr_full,
177                                 void *data)
178 {
179 	struct bridge_data *bd = data;
180 	struct bridge_vlan_info *vinfo = NULL;
181 	uint16_t vid_range_start = 0;
182 	uint16_t vid_range_flags = -1;
183 
184 	struct nlattr *attr;
185 	int remaining;
186 
187 	nla_for_each_nested(attr, attr_full, remaining) {
188 
189 		if (nla_type(attr) == IFLA_BRIDGE_MODE) {
190 			bd->b_hwmode = nla_get_u16(attr);
191 			bd->ce_mask |= BRIDGE_ATTR_HWMODE;
192 		} else if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
193 			continue;
194 
195 		if (nla_len(attr) != sizeof(struct bridge_vlan_info))
196 			return -EINVAL;
197 
198 		vinfo = nla_data(attr);
199 		if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
200 			return -EINVAL;
201 
202 
203 		if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
204 			vid_range_start = vinfo->vid;
205 			vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN);
206 			continue;
207 		}
208 
209 		if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) {
210 			/* sanity check the range flags */
211 			if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) {
212 				NL_DBG(1, "VLAN range flags differ; can not handle it.\n");
213 				return -EINVAL;
214 			}
215 		} else {
216 			vid_range_start = vinfo->vid;
217 		}
218 
219 		for (; vid_range_start <= vinfo->vid; vid_range_start++) {
220 			if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
221 				bd->vlan_info.pvid = vinfo->vid;
222 
223 			if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
224 				set_bit(vid_range_start, bd->vlan_info.untagged_bitmap);
225 
226 			set_bit(vid_range_start, bd->vlan_info.vlan_bitmap);
227 			bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
228 		}
229 
230 		vid_range_flags = -1;
231 	}
232 
233 	return 0;
234 }
235 
bridge_fill_af(struct rtnl_link * link,struct nl_msg * msg,void * data)236 static int bridge_fill_af(struct rtnl_link *link, struct nl_msg *msg,
237 		   void *data)
238 {
239 	struct bridge_data *bd = data;
240 
241 	if ((bd->ce_mask & BRIDGE_ATTR_SELF)||(bd->ce_mask & BRIDGE_ATTR_HWMODE))
242 		NLA_PUT_U16(msg, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
243 
244 	if (bd->ce_mask & BRIDGE_ATTR_HWMODE)
245 		NLA_PUT_U16(msg, IFLA_BRIDGE_MODE, bd->b_hwmode);
246 
247 	return 0;
248 
249 nla_put_failure:
250 	return -NLE_MSGSIZE;
251 }
252 
bridge_fill_pi(struct rtnl_link * link,struct nl_msg * msg,void * data)253 static int bridge_fill_pi(struct rtnl_link *link, struct nl_msg *msg,
254 		   void *data)
255 {
256 	struct bridge_data *bd = data;
257 
258 	if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
259 		if (bd->b_flags_mask & RTNL_BRIDGE_BPDU_GUARD) {
260 			NLA_PUT_U8(msg, IFLA_BRPORT_GUARD,
261 						bd->b_flags & RTNL_BRIDGE_BPDU_GUARD);
262 		}
263 		if (bd->b_flags_mask & RTNL_BRIDGE_HAIRPIN_MODE) {
264 			NLA_PUT_U8(msg, IFLA_BRPORT_MODE,
265 			           bd->b_flags & RTNL_BRIDGE_HAIRPIN_MODE);
266 		}
267 		if (bd->b_flags_mask & RTNL_BRIDGE_FAST_LEAVE) {
268 			NLA_PUT_U8(msg, IFLA_BRPORT_FAST_LEAVE,
269 			           bd->b_flags & RTNL_BRIDGE_FAST_LEAVE);
270 		}
271 		if (bd->b_flags_mask & RTNL_BRIDGE_ROOT_BLOCK) {
272 			NLA_PUT_U8(msg, IFLA_BRPORT_PROTECT,
273 			           bd->b_flags & RTNL_BRIDGE_ROOT_BLOCK);
274 		}
275 		if (bd->b_flags_mask & RTNL_BRIDGE_UNICAST_FLOOD) {
276 			NLA_PUT_U8(msg, IFLA_BRPORT_UNICAST_FLOOD,
277 			           bd->b_flags & RTNL_BRIDGE_UNICAST_FLOOD);
278 		}
279 		if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING) {
280 			NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING,
281 			           bd->b_flags & RTNL_BRIDGE_LEARNING);
282 		}
283 		if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING_SYNC) {
284 			NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING_SYNC,
285 			           bd->b_flags & RTNL_BRIDGE_LEARNING_SYNC);
286 		}
287 	}
288 
289 	if (bd->ce_mask & BRIDGE_ATTR_COST)
290 		NLA_PUT_U32(msg, IFLA_BRPORT_COST, bd->b_cost);
291 
292 	if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
293 		NLA_PUT_U16(msg, IFLA_BRPORT_PRIORITY, bd->b_priority);
294 
295 	if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
296 		NLA_PUT_U8(msg, IFLA_BRPORT_STATE, bd->b_port_state);
297 
298 	return 0;
299 
300 nla_put_failure:
301 	return -NLE_MSGSIZE;
302 }
303 
bridge_override_rtm(struct rtnl_link * link)304 static int bridge_override_rtm(struct rtnl_link *link) {
305         struct bridge_data *bd;
306 
307         if (!rtnl_link_is_bridge(link))
308                 return 0;
309 
310         bd = bridge_data(link);
311 
312         if (bd->ce_mask & BRIDGE_ATTR_FLAGS)
313                 return 1;
314 
315         return 0;
316 }
317 
bridge_get_af(struct nl_msg * msg,uint32_t * ext_filter_mask)318 static int bridge_get_af(struct nl_msg *msg, uint32_t *ext_filter_mask)
319 {
320 	*ext_filter_mask |= RTEXT_FILTER_BRVLAN;
321 	return 0;
322 }
323 
dump_bitmap(struct nl_dump_params * p,const uint32_t * b)324 static void dump_bitmap(struct nl_dump_params *p, const uint32_t *b)
325 {
326 	int i = -1, j, k;
327 	int start = -1, prev = -1;
328 	int done, found = 0;
329 
330 	for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
331 		int base_bit;
332 		uint32_t a = b[k];
333 
334 		base_bit = k * 32;
335 		i = -1;
336 		done = 0;
337 		while (!done) {
338 			j = find_next_bit(i, a);
339 			if (j > 0) {
340 				/* first hit of any bit */
341 				if (start < 0 && prev < 0) {
342 					start = prev = j - 1 + base_bit;
343 					goto next;
344 				}
345 				/* this bit is a continuation of prior bits */
346 				if (j - 2 + base_bit == prev) {
347 					prev++;
348 					goto next;
349 				}
350 			} else
351 				done = 1;
352 
353 			if (start >= 0) {
354 				found++;
355 				if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
356 					break;
357 
358 				nl_dump(p, " %d", start);
359 				if (start != prev)
360 					nl_dump(p, "-%d", prev);
361 
362 				if (done)
363 					break;
364 			}
365 			if (j > 0)
366 				start = prev = j - 1 + base_bit;
367 next:
368 			i = j;
369 		}
370 	}
371 	if (!found)
372 		nl_dump(p, " <none>");
373 
374 	return;
375 }
376 
rtnl_link_bridge_dump_vlans(struct nl_dump_params * p,struct bridge_data * bd)377 static void rtnl_link_bridge_dump_vlans(struct nl_dump_params *p,
378 					struct bridge_data *bd)
379 {
380 	nl_dump(p, "pvid %u", bd->vlan_info.pvid);
381 
382 	nl_dump(p, "   all vlans:");
383 	dump_bitmap(p, bd->vlan_info.vlan_bitmap);
384 
385 	nl_dump(p, "   untagged vlans:");
386 	dump_bitmap(p, bd->vlan_info.untagged_bitmap);
387 }
388 
bridge_dump_details(struct rtnl_link * link,struct nl_dump_params * p,void * data)389 static void bridge_dump_details(struct rtnl_link *link,
390 				struct nl_dump_params *p, void *data)
391 {
392 	struct bridge_data *bd = data;
393 
394 	nl_dump_line(p, "    bridge: ");
395 
396 	if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
397 		nl_dump(p, "port-state %u ", bd->b_port_state);
398 
399 	if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
400 		nl_dump(p, "prio %u ", bd->b_priority);
401 
402 	if (bd->ce_mask & BRIDGE_ATTR_COST)
403 		nl_dump(p, "cost %u ", bd->b_cost);
404 
405 	if (bd->ce_mask & BRIDGE_ATTR_HWMODE) {
406 		char hbuf[32];
407 
408 		rtnl_link_bridge_hwmode2str(bd->b_hwmode, hbuf, sizeof(hbuf));
409 		nl_dump(p, "hwmode %s", hbuf);
410 	}
411 
412 	if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
413 		rtnl_link_bridge_dump_vlans(p, bd);
414 
415 	if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
416 		char buf[256];
417 
418 		rtnl_link_bridge_flags2str(bd->b_flags & bd->b_flags_mask,
419 					   buf, sizeof(buf));
420 		nl_dump(p, "%s", buf);
421 	}
422 
423 	nl_dump(p, "\n");
424 }
425 
bridge_compare(struct rtnl_link * _a,struct rtnl_link * _b,int family,uint32_t attrs,int flags)426 static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b,
427 			  int family, uint32_t attrs, int flags)
428 {
429 	struct bridge_data *a = bridge_data(_a);
430 	struct bridge_data *b = bridge_data(_b);
431 	int diff = 0;
432 
433 #define BRIDGE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, BRIDGE_ATTR_##ATTR, a, b, EXPR)
434 	diff |= BRIDGE_DIFF(PORT_STATE,	a->b_port_state != b->b_port_state);
435 	diff |= BRIDGE_DIFF(PRIORITY, a->b_priority != b->b_priority);
436 	diff |= BRIDGE_DIFF(COST, a->b_cost != b->b_cost);
437 	diff |= BRIDGE_DIFF(PORT_VLAN, memcmp(&a->vlan_info, &b->vlan_info,
438 					      sizeof(struct rtnl_link_bridge_vlan)));
439 	diff |= BRIDGE_DIFF(HWMODE, a->b_hwmode != b->b_hwmode);
440 	diff |= BRIDGE_DIFF(SELF, a->b_self != b->b_self);
441 
442 	if (flags & LOOSE_COMPARISON)
443 		diff |= BRIDGE_DIFF(FLAGS,
444 				  (a->b_flags ^ b->b_flags) & b->b_flags_mask);
445 	else
446 		diff |= BRIDGE_DIFF(FLAGS, a->b_flags != b->b_flags);
447 #undef BRIDGE_DIFF
448 
449 	return diff;
450 }
451 /** @endcond */
452 
453 /**
454  * Allocate link object of type bridge
455  *
456  * @return Allocated link object or NULL.
457  */
rtnl_link_bridge_alloc(void)458 struct rtnl_link *rtnl_link_bridge_alloc(void)
459 {
460 	struct rtnl_link *link;
461 
462 	if (!(link = rtnl_link_alloc()))
463 		return NULL;
464 
465 	if (rtnl_link_set_type(link, "bridge") < 0) {
466 		rtnl_link_put(link);
467 		return NULL;
468 	}
469 
470 	return link;
471 }
472 
473 /**
474  * Create a new kernel bridge device
475  * @arg sk              netlink socket
476  * @arg name            name of the bridge device or NULL
477  *
478  * Creates a new bridge device in the kernel. If no name is
479  * provided, the kernel will automatically pick a name of the
480  * form "type%d" (e.g. bridge0, vlan1, etc.)
481  *
482  * @return 0 on success or a negative error code
483 */
rtnl_link_bridge_add(struct nl_sock * sk,const char * name)484 int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
485 {
486 	int err;
487 	struct rtnl_link *link;
488 
489 	if (!(link = rtnl_link_bridge_alloc()))
490 		return -NLE_NOMEM;
491 
492 	if(name)
493 		rtnl_link_set_name(link, name);
494 
495 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
496 	rtnl_link_put(link);
497 
498 	return err;
499 }
500 
501 /**
502  * Check if a link is a bridge
503  * @arg link		Link object
504  *
505  * @return 1 if the link is a bridge, 0 otherwise.
506  */
rtnl_link_is_bridge(struct rtnl_link * link)507 int rtnl_link_is_bridge(struct rtnl_link *link)
508 {
509 	return link->l_family == AF_BRIDGE &&
510 	       link->l_af_ops == &bridge_ops;
511 }
512 
513 /**
514  * Check if bridge has extended information
515  * @arg link		Link object of type bridge
516  *
517  * Checks if the bridge object has been constructed based on
518  * information that is only available in newer kernels. This
519  * affectes the following functions:
520  *  - rtnl_link_bridge_get_cost()
521  *  - rtnl_link_bridge_get_priority()
522  *  - rtnl_link_bridge_get_flags()
523  *
524  * @return 1 if extended information is available, otherwise 0 is returned.
525  */
rtnl_link_bridge_has_ext_info(struct rtnl_link * link)526 int rtnl_link_bridge_has_ext_info(struct rtnl_link *link)
527 {
528 	struct bridge_data *bd;
529 
530 	if (!rtnl_link_is_bridge(link))
531 		return 0;
532 
533 	bd = bridge_data(link);
534 	return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS);
535 }
536 
537 /**
538  * Set Spanning Tree Protocol (STP) port state
539  * @arg link		Link object of type bridge
540  * @arg state		New STP port state
541  *
542  * The value of state must be one of the following:
543  *   - BR_STATE_DISABLED
544  *   - BR_STATE_LISTENING
545  *   - BR_STATE_LEARNING
546  *   - BR_STATE_FORWARDING
547  *   - BR_STATE_BLOCKING
548  *
549  * @see rtnl_link_bridge_get_port_state()
550  *
551  * @return 0 on success or a negative error code.
552  * @retval -NLE_OPNOTSUPP Link is not a bridge
553  * @retval -NLE_INVAL Invalid state value (0..BR_STATE_BLOCKING)
554  */
rtnl_link_bridge_set_port_state(struct rtnl_link * link,uint8_t state)555 int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
556 {
557 	struct bridge_data *bd = bridge_data(link);
558 
559 	IS_BRIDGE_LINK_ASSERT(link);
560 
561 	if (state > BR_STATE_BLOCKING)
562 		return -NLE_INVAL;
563 
564 	bd->b_port_state = state;
565 	bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
566 
567 	return 0;
568 }
569 
570 /**
571  * Get Spanning Tree Protocol (STP) port state
572  * @arg link		Link object of type bridge
573  *
574  * @see rtnl_link_bridge_set_port_state()
575  *
576  * @return The STP port state or a negative error code.
577  * @retval -NLE_OPNOTSUPP Link is not a bridge
578  */
rtnl_link_bridge_get_port_state(struct rtnl_link * link)579 int rtnl_link_bridge_get_port_state(struct rtnl_link *link)
580 {
581 	struct bridge_data *bd = bridge_data(link);
582 
583 	IS_BRIDGE_LINK_ASSERT(link);
584 
585 	return bd->b_port_state;
586 }
587 
588 /**
589  * Set priority
590  * @arg link		Link object of type bridge
591  * @arg prio		Bridge priority
592  *
593  * @see rtnl_link_bridge_get_priority()
594  *
595  * @return 0 on success or a negative error code.
596  * @retval -NLE_OPNOTSUPP Link is not a bridge
597  */
rtnl_link_bridge_set_priority(struct rtnl_link * link,uint16_t prio)598 int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
599 {
600 	struct bridge_data *bd = bridge_data(link);
601 
602 	IS_BRIDGE_LINK_ASSERT(link);
603 
604 	bd->b_priority = prio;
605 	bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
606 
607 	return 0;
608 }
609 
610 /**
611  * Get priority
612  * @arg link		Link object of type bridge
613  *
614  * @see rtnl_link_bridge_set_priority()
615  *
616  * @return 0 on success or a negative error code.
617  * @retval -NLE_OPNOTSUPP Link is not a bridge
618  */
rtnl_link_bridge_get_priority(struct rtnl_link * link)619 int rtnl_link_bridge_get_priority(struct rtnl_link *link)
620 {
621 	struct bridge_data *bd = bridge_data(link);
622 
623 	IS_BRIDGE_LINK_ASSERT(link);
624 
625 	return bd->b_priority;
626 }
627 
628 /**
629  * Set Spanning Tree Protocol (STP) path cost
630  * @arg link		Link object of type bridge
631  * @arg cost		New STP path cost value
632  *
633  * @see rtnl_link_bridge_get_cost()
634  *
635  * @return The bridge priority or a negative error code.
636  * @retval -NLE_OPNOTSUPP Link is not a bridge
637  */
rtnl_link_bridge_set_cost(struct rtnl_link * link,uint32_t cost)638 int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
639 {
640 	struct bridge_data *bd = bridge_data(link);
641 
642 	IS_BRIDGE_LINK_ASSERT(link);
643 
644 	bd->b_cost = cost;
645 	bd->ce_mask |= BRIDGE_ATTR_COST;
646 
647 	return 0;
648 }
649 
650 /**
651  * Get Spanning Tree Protocol (STP) path cost
652  * @arg link		Link object of type bridge
653  * @arg cost		Pointer to store STP cost value
654  *
655  * @see rtnl_link_bridge_set_cost()
656  *
657  * @return 0 on success or a negative error code.
658  * @retval -NLE_OPNOTSUPP Link is not a bridge
659  * @retval -NLE_INVAL `cost` is not a valid pointer
660  */
rtnl_link_bridge_get_cost(struct rtnl_link * link,uint32_t * cost)661 int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
662 {
663 	struct bridge_data *bd = bridge_data(link);
664 
665 	IS_BRIDGE_LINK_ASSERT(link);
666 
667 	if (!cost)
668 		return -NLE_INVAL;
669 
670 	*cost = bd->b_cost;
671 
672 	return 0;
673 }
674 
675 /**
676  * Unset flags
677  * @arg link		Link object of type bridge
678  * @arg flags		Bridging flags to unset
679  *
680  * @see rtnl_link_bridge_set_flags()
681  * @see rtnl_link_bridge_get_flags()
682  *
683  * @return 0 on success or a negative error code.
684  * @retval -NLE_OPNOTSUPP Link is not a bridge
685  */
rtnl_link_bridge_unset_flags(struct rtnl_link * link,unsigned int flags)686 int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
687 {
688 	struct bridge_data *bd = bridge_data(link);
689 
690 	IS_BRIDGE_LINK_ASSERT(link);
691 
692 	bd->b_flags_mask |= flags;
693 	bd->b_flags &= ~flags;
694 	bd->ce_mask |= BRIDGE_ATTR_FLAGS;
695 
696 	return 0;
697 }
698 
699 /**
700  * Set flags
701  * @arg link		Link object of type bridge
702  * @arg flags		Bridging flags to set
703  *
704  * Valid flags are:
705  *   - RTNL_BRIDGE_HAIRPIN_MODE
706  *   - RTNL_BRIDGE_BPDU_GUARD
707  *   - RTNL_BRIDGE_ROOT_BLOCK
708  *   - RTNL_BRIDGE_FAST_LEAVE
709  *   - RTNL_BRIDGE_UNICAST_FLOOD
710  *   - RTNL_BRIDGE_LEARNING
711  *   - RTNL_BRIDGE_LEARNING_SYNC
712  *
713  * @see rtnl_link_bridge_unset_flags()
714  * @see rtnl_link_bridge_get_flags()
715  *
716  * @return 0 on success or a negative error code.
717  * @retval -NLE_OPNOTSUPP Link is not a bridge
718  */
rtnl_link_bridge_set_flags(struct rtnl_link * link,unsigned int flags)719 int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
720 {
721 	struct bridge_data *bd = bridge_data(link);
722 
723 	IS_BRIDGE_LINK_ASSERT(link);
724 
725 	bd->b_flags_mask |= flags;
726 	bd->b_flags |= flags;
727 	bd->ce_mask |= BRIDGE_ATTR_FLAGS;
728 
729 	return 0;
730 }
731 
732 /**
733  * Get flags
734  * @arg link		Link object of type bridge
735  *
736  * @see rtnl_link_bridge_set_flags()
737  * @see rtnl_link_bridge_unset_flags()
738  *
739  * @return Flags or a negative error code.
740  * @retval -NLE_OPNOTSUPP Link is not a bridge
741  */
rtnl_link_bridge_get_flags(struct rtnl_link * link)742 int rtnl_link_bridge_get_flags(struct rtnl_link *link)
743 {
744 	struct bridge_data *bd = bridge_data(link);
745 
746 	IS_BRIDGE_LINK_ASSERT(link);
747 
748 	return bd->b_flags;
749 }
750 
751 /**
752  * Set link change type to self
753  * @arg link		Link Object of type bridge
754  *
755  * This will set the bridge change flag to self, meaning that changes to
756  * be applied with this link object will be applied directly to the physical
757  * device in a bridge instead of the virtual device.
758  *
759  * @return 0 on success or negative error code
760  * @return -NLE_OPNOTSUP Link is not a bridge
761  */
rtnl_link_bridge_set_self(struct rtnl_link * link)762 int rtnl_link_bridge_set_self(struct rtnl_link *link)
763 {
764 	struct bridge_data *bd = bridge_data(link);
765 
766 	IS_BRIDGE_LINK_ASSERT(link);
767 
768 	bd->b_self |= 1;
769 	bd->ce_mask |= BRIDGE_ATTR_SELF;
770 
771 	return 0;
772 }
773 
774 /**
775  * Get hardware mode
776  * @arg link            Link object of type bridge
777  * @arg hwmode          Output argument.
778  *
779  * @see rtnl_link_bridge_set_hwmode()
780  *
781  * @return 0 if hardware mode is present and returned in hwmode
782  * @return -NLE_NOATTR if hardware mode is not present
783  * @return -NLE_OPNOTSUP Link is not a bridge
784  */
rtnl_link_bridge_get_hwmode(struct rtnl_link * link,uint16_t * hwmode)785 int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
786 {
787 	struct bridge_data *bd = bridge_data(link);
788 
789 	IS_BRIDGE_LINK_ASSERT(link);
790 
791 	if (!(bd->ce_mask & BRIDGE_ATTR_HWMODE))
792 		return -NLE_NOATTR;
793 
794 	*hwmode = bd->b_hwmode;
795 	return 0;
796 }
797 
798 /**
799  * Set hardware mode
800  * @arg link		Link object of type bridge
801  * @arg hwmode		Hardware mode to set on link
802  *
803  * This will set the hardware mode of a link when it supports hardware
804  * offloads for bridging.
805  * @see rtnl_link_bridge_get_hwmode()
806  *
807  * Valid modes are:
808  *   - RTNL_BRIDGE_HWMODE_VEB
809  *   - RTNL_BRIDGE_HWMODE_VEPA
810  *
811  * When setting hardware mode, the change type will be set to self.
812  * @see rtnl_link_bridge_set_self()
813  *
814  * @return 0 on success or negative error code
815  * @return -NLE_OPNOTSUP Link is not a bridge
816  * @return -NLE_INVAL when specified hwmode is unsupported.
817  */
rtnl_link_bridge_set_hwmode(struct rtnl_link * link,uint16_t hwmode)818 int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
819 {
820 	int err;
821 	struct bridge_data *bd = bridge_data(link);
822 
823 	if (hwmode > RTNL_BRIDGE_HWMODE_MAX)
824 		return -NLE_INVAL;
825 
826 	if ((err = rtnl_link_bridge_set_self(link)) < 0)
827 		return err;
828 
829 	bd->b_hwmode = hwmode;
830 	bd->ce_mask |= BRIDGE_ATTR_HWMODE;
831 
832 	return 0;
833 }
834 
835 
836 static const struct trans_tbl bridge_flags[] = {
837 	__ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode),
838 	__ADD(RTNL_BRIDGE_BPDU_GUARD, 	bpdu_guard),
839 	__ADD(RTNL_BRIDGE_ROOT_BLOCK,	root_block),
840 	__ADD(RTNL_BRIDGE_FAST_LEAVE,	fast_leave),
841 	__ADD(RTNL_BRIDGE_UNICAST_FLOOD,	flood),
842 	__ADD(RTNL_BRIDGE_LEARNING,			learning),
843 	__ADD(RTNL_BRIDGE_LEARNING_SYNC,	learning_sync),
844 };
845 
846 /**
847  * @name Flag Translation
848  * @{
849  */
850 
rtnl_link_bridge_flags2str(int flags,char * buf,size_t len)851 char *rtnl_link_bridge_flags2str(int flags, char *buf, size_t len)
852 {
853 	return __flags2str(flags, buf, len, bridge_flags, ARRAY_SIZE(bridge_flags));
854 }
855 
rtnl_link_bridge_str2flags(const char * name)856 int rtnl_link_bridge_str2flags(const char *name)
857 {
858 	return __str2flags(name, bridge_flags, ARRAY_SIZE(bridge_flags));
859 }
860 
861 /** @} */
862 
863 static const struct trans_tbl port_states[] = {
864 	__ADD(BR_STATE_DISABLED, disabled),
865 	__ADD(BR_STATE_LISTENING, listening),
866 	__ADD(BR_STATE_LEARNING, learning),
867 	__ADD(BR_STATE_FORWARDING, forwarding),
868 	__ADD(BR_STATE_BLOCKING, blocking),
869 };
870 
871 /**
872  * @name Port State Translation
873  * @{
874  */
875 
rtnl_link_bridge_portstate2str(int st,char * buf,size_t len)876 char *rtnl_link_bridge_portstate2str(int st, char *buf, size_t len)
877 {
878 	return __type2str(st, buf, len, port_states, ARRAY_SIZE(port_states));
879 }
880 
rtnl_link_bridge_str2portstate(const char * name)881 int rtnl_link_bridge_str2portstate(const char *name)
882 {
883 	return __str2type(name, port_states, ARRAY_SIZE(port_states));
884 }
885 
886 /** @} */
887 
888 static const struct trans_tbl hw_modes[] = {
889 	__ADD(RTNL_BRIDGE_HWMODE_VEB, veb),
890 	__ADD(RTNL_BRIDGE_HWMODE_VEPA, vepa),
891 	__ADD(RTNL_BRIDGE_HWMODE_UNDEF, undef),
892 };
893 
894 /**
895  * @name Hardware Mode Translation
896  * @{
897  */
898 
rtnl_link_bridge_hwmode2str(uint16_t st,char * buf,size_t len)899 char *rtnl_link_bridge_hwmode2str(uint16_t st, char *buf, size_t len) {
900 	return __type2str(st, buf, len, hw_modes, ARRAY_SIZE(hw_modes));
901 }
902 
rtnl_link_bridge_str2hwmode(const char * name)903 uint16_t rtnl_link_bridge_str2hwmode(const char *name)
904 {
905 	return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
906 }
907 
908 /** @} */
909 
rtnl_link_bridge_pvid(struct rtnl_link * link)910 int rtnl_link_bridge_pvid(struct rtnl_link *link)
911 {
912 	struct bridge_data *bd;
913 
914 	IS_BRIDGE_LINK_ASSERT(link);
915 
916 	bd = link->l_af_data[AF_BRIDGE];
917 	if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
918 		return (int) bd->vlan_info.pvid;
919 
920 	return -EINVAL;
921 }
922 
rtnl_link_bridge_has_vlan(struct rtnl_link * link)923 int rtnl_link_bridge_has_vlan(struct rtnl_link *link)
924 {
925 	struct bridge_data *bd;
926 	int i;
927 
928 	IS_BRIDGE_LINK_ASSERT(link);
929 
930 	bd = link->l_af_data[AF_BRIDGE];
931 	if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
932 		if (bd->vlan_info.pvid)
933 			return 1;
934 
935 		for (i = 0; i < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; ++i) {
936 			if (bd->vlan_info.vlan_bitmap[i] ||
937 			    bd->vlan_info.untagged_bitmap[i])
938 				return 1;
939 		}
940 	}
941 	return 0;
942 }
943 
rtnl_link_bridge_get_port_vlan(struct rtnl_link * link)944 struct rtnl_link_bridge_vlan *rtnl_link_bridge_get_port_vlan(struct rtnl_link *link)
945 {
946 	struct bridge_data *data;
947 
948 	if (!rtnl_link_is_bridge(link))
949 		return NULL;
950 
951 	data = link->l_af_data[AF_BRIDGE];
952 	if (data && (data->ce_mask & BRIDGE_ATTR_PORT_VLAN))
953 		return &data->vlan_info;
954 
955 	return NULL;
956 }
957 
958 static struct rtnl_link_af_ops bridge_ops = {
959 	.ao_family			= AF_BRIDGE,
960 	.ao_alloc			= &bridge_alloc,
961 	.ao_clone			= &bridge_clone,
962 	.ao_free			= &bridge_free,
963 	.ao_parse_protinfo		= &bridge_parse_protinfo,
964 	.ao_dump[NL_DUMP_DETAILS]	= &bridge_dump_details,
965 	.ao_compare			= &bridge_compare,
966 	.ao_parse_af_full		= &bridge_parse_af_full,
967 	.ao_get_af			= &bridge_get_af,
968 	.ao_fill_af			= &bridge_fill_af,
969 	.ao_fill_pi			= &bridge_fill_pi,
970 	.ao_fill_pi_flags	= NLA_F_NESTED,
971 	.ao_override_rtm		= &bridge_override_rtm,
972 	.ao_fill_af_no_nest	= 1,
973 };
974 
bridge_init(void)975 static void __init bridge_init(void)
976 {
977 	rtnl_link_af_register(&bridge_ops);
978 }
979 
bridge_exit(void)980 static void __exit bridge_exit(void)
981 {
982 	rtnl_link_af_unregister(&bridge_ops);
983 }
984 
985 /** @} */
986