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