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