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