libnl 3.9.0
bridge.c
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 "nl-default.h"
15
16#include <linux/if_bridge.h>
17
18#include <netlink/netlink.h>
19#include <netlink/attr.h>
20#include <netlink/route/rtnl.h>
21#include <netlink/route/link/bridge.h>
22
23#include "nl-route.h"
24#include "link-api.h"
25#include "nl-priv-dynamic-core/nl-core.h"
26
27#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
28
29/** @cond SKIP */
30#define BRIDGE_ATTR_PORT_STATE (1 << 0)
31#define BRIDGE_ATTR_PRIORITY (1 << 1)
32#define BRIDGE_ATTR_COST (1 << 2)
33#define BRIDGE_ATTR_FLAGS (1 << 3)
34#define BRIDGE_ATTR_PORT_VLAN (1 << 4)
35#define BRIDGE_ATTR_HWMODE (1 << 5)
36#define BRIDGE_ATTR_SELF (1 << 6)
37
38#define PRIV_FLAG_NEW_ATTRS (1 << 0)
39
40struct bridge_data
41{
42 uint8_t b_port_state;
43 uint8_t b_priv_flags; /* internal flags */
44 uint16_t b_hwmode;
45 uint16_t b_priority;
46 uint16_t b_self; /* here for comparison reasons */
47 uint32_t b_cost;
48 uint32_t b_flags;
49 uint32_t b_flags_mask;
50 uint32_t ce_mask; /* HACK to support attr macros */
51 struct rtnl_link_bridge_vlan vlan_info;
52};
53
54static void set_bit(unsigned nr, uint32_t *addr)
55{
56 if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
57 addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
58}
59
60static int find_next_bit(int i, uint32_t x)
61{
62 int j;
63
64 if (i >= 32)
65 return -1;
66
67 /* find first bit */
68 if (i < 0)
69 return __builtin_ffs(x);
70
71 /* mask off prior finds to get next */
72 j = __builtin_ffs(x >> i);
73 return j ? j + i : 0;
74}
75
76static struct rtnl_link_af_ops bridge_ops;
77
78#define IS_BRIDGE_LINK_ASSERT(link) \
79 if (!rtnl_link_is_bridge(link)) { \
80 APPBUG("A function was expecting a link object of type bridge."); \
81 return -NLE_OPNOTSUPP; \
82 }
83
84static inline struct bridge_data *bridge_data(struct rtnl_link *link)
85{
86 return rtnl_link_af_data(link, &bridge_ops);
87}
88
89static void *bridge_alloc(struct rtnl_link *link)
90{
91 return calloc(1, sizeof(struct bridge_data));
92}
93
94static void *bridge_clone(struct rtnl_link *link, void *data)
95{
96 struct bridge_data *bd;
97
98 if ((bd = bridge_alloc(link)))
99 memcpy(bd, data, sizeof(*bd));
100
101 return bd;
102}
103
104static void bridge_free(struct rtnl_link *link, void *data)
105{
106 free(data);
107}
108
109static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = {
110 [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
111 [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
112 [IFLA_BRPORT_COST] = { .type = NLA_U32 },
113 [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
114 [IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
115 [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
116 [IFLA_BRPORT_FAST_LEAVE] = { .type = NLA_U8 },
117 [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 },
118 [IFLA_BRPORT_LEARNING_SYNC] = { .type = NLA_U8 },
119 [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
120};
121
122static void check_flag(struct rtnl_link *link, struct nlattr *attrs[],
123 int type, int flag)
124{
125 if (attrs[type] && nla_get_u8(attrs[type]))
126 rtnl_link_bridge_set_flags(link, flag);
127}
128
129static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
130 void *data)
131{
132 struct bridge_data *bd = data;
133 struct nlattr *br_attrs[IFLA_BRPORT_MAX+1];
134 int err;
135
136 /* Backwards compatibility */
137 if (!nla_is_nested(attr)) {
138 if (nla_len(attr) < 1)
139 return -NLE_RANGE;
140
141 bd->b_port_state = nla_get_u8(attr);
142 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
143
144 return 0;
145 }
146
147 if ((err = nla_parse_nested(br_attrs, IFLA_BRPORT_MAX, attr,
148 br_attrs_policy)) < 0)
149 return err;
150
151 bd->b_priv_flags |= PRIV_FLAG_NEW_ATTRS;
152
153 if (br_attrs[IFLA_BRPORT_STATE]) {
154 bd->b_port_state = nla_get_u8(br_attrs[IFLA_BRPORT_STATE]);
155 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
156 }
157
158 if (br_attrs[IFLA_BRPORT_PRIORITY]) {
159 bd->b_priority = nla_get_u16(br_attrs[IFLA_BRPORT_PRIORITY]);
160 bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
161 }
162
163 if (br_attrs[IFLA_BRPORT_COST]) {
164 bd->b_cost = nla_get_u32(br_attrs[IFLA_BRPORT_COST]);
165 bd->ce_mask |= BRIDGE_ATTR_COST;
166 }
167
168 check_flag(link, br_attrs, IFLA_BRPORT_MODE, RTNL_BRIDGE_HAIRPIN_MODE);
169 check_flag(link, br_attrs, IFLA_BRPORT_GUARD, RTNL_BRIDGE_BPDU_GUARD);
170 check_flag(link, br_attrs, IFLA_BRPORT_PROTECT, RTNL_BRIDGE_ROOT_BLOCK);
171 check_flag(link, br_attrs, IFLA_BRPORT_FAST_LEAVE, RTNL_BRIDGE_FAST_LEAVE);
172 check_flag(link, br_attrs, IFLA_BRPORT_UNICAST_FLOOD,
173 RTNL_BRIDGE_UNICAST_FLOOD);
174 check_flag(link, br_attrs, IFLA_BRPORT_LEARNING, RTNL_BRIDGE_LEARNING);
175 check_flag(link, br_attrs, IFLA_BRPORT_LEARNING_SYNC,
176 RTNL_BRIDGE_LEARNING_SYNC);
177
178 return 0;
179}
180
181static int bridge_parse_af_full(struct rtnl_link *link, struct nlattr *attr_full,
182 void *data)
183{
184 struct bridge_data *bd = data;
185 struct bridge_vlan_info *vinfo = NULL;
186 uint16_t vid_range_start = 0;
187 uint16_t vid_range_flags = -1;
188
189 struct nlattr *attr;
190 int remaining;
191
192 nla_for_each_nested(attr, attr_full, remaining) {
193
194 if (nla_type(attr) == IFLA_BRIDGE_MODE) {
195 bd->b_hwmode = nla_get_u16(attr);
196 bd->ce_mask |= BRIDGE_ATTR_HWMODE;
197 continue;
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
242static 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
255nla_put_failure:
256 return -NLE_MSGSIZE;
257}
258
259static 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
306nla_put_failure:
307 return -NLE_MSGSIZE;
308}
309
310static 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
324static 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
330static 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;
373next:
374 i = j;
375 }
376 }
377 if (!found)
378 nl_dump(p, " <none>");
379
380 return;
381}
382
383static 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
395static 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
432static 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 _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
440 diff |= _DIFF(BRIDGE_ATTR_PORT_STATE,
441 a->b_port_state != b->b_port_state);
442 diff |= _DIFF(BRIDGE_ATTR_PRIORITY, a->b_priority != b->b_priority);
443 diff |= _DIFF(BRIDGE_ATTR_COST, a->b_cost != b->b_cost);
444 diff |= _DIFF(BRIDGE_ATTR_PORT_VLAN,
445 memcmp(&a->vlan_info, &b->vlan_info,
446 sizeof(struct rtnl_link_bridge_vlan)));
447 diff |= _DIFF(BRIDGE_ATTR_HWMODE, a->b_hwmode != b->b_hwmode);
448 diff |= _DIFF(BRIDGE_ATTR_SELF, a->b_self != b->b_self);
449
450 if (flags & LOOSE_COMPARISON)
451 diff |= _DIFF(BRIDGE_ATTR_FLAGS,
452 (a->b_flags ^ b->b_flags) & b->b_flags_mask);
453 else
454 diff |= _DIFF(BRIDGE_ATTR_FLAGS, a->b_flags != b->b_flags);
455#undef _DIFF
456
457 return diff;
458}
459/** @endcond */
460
461/**
462 * Allocate link object of type bridge
463 *
464 * @return Allocated link object or NULL.
465 */
467{
468 struct rtnl_link *link;
469
470 if (!(link = rtnl_link_alloc()))
471 return NULL;
472
473 if (rtnl_link_set_type(link, "bridge") < 0) {
474 rtnl_link_put(link);
475 return NULL;
476 }
477
478 return link;
479}
480
481/**
482 * Create a new kernel bridge device
483 * @arg sk netlink socket
484 * @arg name name of the bridge device or NULL
485 *
486 * Creates a new bridge device in the kernel. If no name is
487 * provided, the kernel will automatically pick a name of the
488 * form "type%d" (e.g. bridge0, vlan1, etc.)
489 *
490 * @return 0 on success or a negative error code
491*/
492int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
493{
494 int err;
495 struct rtnl_link *link;
496
497 if (!(link = rtnl_link_bridge_alloc()))
498 return -NLE_NOMEM;
499
500 if(name)
501 rtnl_link_set_name(link, name);
502
503 err = rtnl_link_add(sk, link, NLM_F_CREATE);
504 rtnl_link_put(link);
505
506 return err;
507}
508
509/**
510 * Check if a link is a bridge
511 * @arg link Link object
512 *
513 * @return 1 if the link is a bridge, 0 otherwise.
514 */
516{
517 return link->l_family == AF_BRIDGE &&
518 link->l_af_ops == &bridge_ops;
519}
520
521/**
522 * Check if bridge has extended information
523 * @arg link Link object of type bridge
524 *
525 * Checks if the bridge object has been constructed based on
526 * information that is only available in newer kernels. This
527 * affectes the following functions:
528 * - rtnl_link_bridge_get_cost()
529 * - rtnl_link_bridge_get_priority()
530 * - rtnl_link_bridge_get_flags()
531 *
532 * @return 1 if extended information is available, otherwise 0 is returned.
533 */
535{
536 struct bridge_data *bd;
537
538 if (!rtnl_link_is_bridge(link))
539 return 0;
540
541 bd = bridge_data(link);
542 return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS);
543}
544
545/**
546 * Set Spanning Tree Protocol (STP) port state
547 * @arg link Link object of type bridge
548 * @arg state New STP port state
549 *
550 * The value of state must be one of the following:
551 * - BR_STATE_DISABLED
552 * - BR_STATE_LISTENING
553 * - BR_STATE_LEARNING
554 * - BR_STATE_FORWARDING
555 * - BR_STATE_BLOCKING
556 *
557 * @see rtnl_link_bridge_get_port_state()
558 *
559 * @return 0 on success or a negative error code.
560 * @retval -NLE_OPNOTSUPP Link is not a bridge
561 * @retval -NLE_INVAL Invalid state value (0..BR_STATE_BLOCKING)
562 */
563int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
564{
565 struct bridge_data *bd = bridge_data(link);
566
567 IS_BRIDGE_LINK_ASSERT(link);
568
569 if (state > BR_STATE_BLOCKING)
570 return -NLE_INVAL;
571
572 bd->b_port_state = state;
573 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
574
575 return 0;
576}
577
578/**
579 * Get Spanning Tree Protocol (STP) port state
580 * @arg link Link object of type bridge
581 *
582 * @see rtnl_link_bridge_set_port_state()
583 *
584 * @return The STP port state or a negative error code.
585 * @retval -NLE_OPNOTSUPP Link is not a bridge
586 */
588{
589 struct bridge_data *bd = bridge_data(link);
590
591 IS_BRIDGE_LINK_ASSERT(link);
592
593 return bd->b_port_state;
594}
595
596/**
597 * Set priority
598 * @arg link Link object of type bridge
599 * @arg prio Bridge priority
600 *
601 * @see rtnl_link_bridge_get_priority()
602 *
603 * @return 0 on success or a negative error code.
604 * @retval -NLE_OPNOTSUPP Link is not a bridge
605 */
606int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
607{
608 struct bridge_data *bd = bridge_data(link);
609
610 IS_BRIDGE_LINK_ASSERT(link);
611
612 bd->b_priority = prio;
613 bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
614
615 return 0;
616}
617
618/**
619 * Get priority
620 * @arg link Link object of type bridge
621 *
622 * @see rtnl_link_bridge_set_priority()
623 *
624 * @return 0 on success or a negative error code.
625 * @retval -NLE_OPNOTSUPP Link is not a bridge
626 */
628{
629 struct bridge_data *bd = bridge_data(link);
630
631 IS_BRIDGE_LINK_ASSERT(link);
632
633 return bd->b_priority;
634}
635
636/**
637 * Set Spanning Tree Protocol (STP) path cost
638 * @arg link Link object of type bridge
639 * @arg cost New STP path cost value
640 *
641 * @see rtnl_link_bridge_get_cost()
642 *
643 * @return The bridge priority or a negative error code.
644 * @retval -NLE_OPNOTSUPP Link is not a bridge
645 */
646int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
647{
648 struct bridge_data *bd = bridge_data(link);
649
650 IS_BRIDGE_LINK_ASSERT(link);
651
652 bd->b_cost = cost;
653 bd->ce_mask |= BRIDGE_ATTR_COST;
654
655 return 0;
656}
657
658/**
659 * Get Spanning Tree Protocol (STP) path cost
660 * @arg link Link object of type bridge
661 * @arg cost Pointer to store STP cost value
662 *
663 * @see rtnl_link_bridge_set_cost()
664 *
665 * @return 0 on success or a negative error code.
666 * @retval -NLE_OPNOTSUPP Link is not a bridge
667 * @retval -NLE_INVAL `cost` is not a valid pointer
668 */
669int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
670{
671 struct bridge_data *bd = bridge_data(link);
672
673 IS_BRIDGE_LINK_ASSERT(link);
674
675 if (!cost)
676 return -NLE_INVAL;
677
678 *cost = bd->b_cost;
679
680 return 0;
681}
682
683/**
684 * Unset flags
685 * @arg link Link object of type bridge
686 * @arg flags Bridging flags to unset
687 *
688 * @see rtnl_link_bridge_set_flags()
689 * @see rtnl_link_bridge_get_flags()
690 *
691 * @return 0 on success or a negative error code.
692 * @retval -NLE_OPNOTSUPP Link is not a bridge
693 */
694int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
695{
696 struct bridge_data *bd = bridge_data(link);
697
698 IS_BRIDGE_LINK_ASSERT(link);
699
700 bd->b_flags_mask |= flags;
701 bd->b_flags &= ~flags;
702 bd->ce_mask |= BRIDGE_ATTR_FLAGS;
703
704 return 0;
705}
706
707/**
708 * Set flags
709 * @arg link Link object of type bridge
710 * @arg flags Bridging flags to set
711 *
712 * Valid flags are:
713 * - RTNL_BRIDGE_HAIRPIN_MODE
714 * - RTNL_BRIDGE_BPDU_GUARD
715 * - RTNL_BRIDGE_ROOT_BLOCK
716 * - RTNL_BRIDGE_FAST_LEAVE
717 * - RTNL_BRIDGE_UNICAST_FLOOD
718 * - RTNL_BRIDGE_LEARNING
719 * - RTNL_BRIDGE_LEARNING_SYNC
720 *
721 * @see rtnl_link_bridge_unset_flags()
722 * @see rtnl_link_bridge_get_flags()
723 *
724 * @return 0 on success or a negative error code.
725 * @retval -NLE_OPNOTSUPP Link is not a bridge
726 */
727int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
728{
729 struct bridge_data *bd = bridge_data(link);
730
731 IS_BRIDGE_LINK_ASSERT(link);
732
733 bd->b_flags_mask |= flags;
734 bd->b_flags |= flags;
735 bd->ce_mask |= BRIDGE_ATTR_FLAGS;
736
737 return 0;
738}
739
740/**
741 * Get flags
742 * @arg link Link object of type bridge
743 *
744 * @see rtnl_link_bridge_set_flags()
745 * @see rtnl_link_bridge_unset_flags()
746 *
747 * @return Flags or a negative error code.
748 * @retval -NLE_OPNOTSUPP Link is not a bridge
749 */
751{
752 struct bridge_data *bd = bridge_data(link);
753
754 IS_BRIDGE_LINK_ASSERT(link);
755
756 return bd->b_flags;
757}
758
759/**
760 * Set link change type to self
761 * @arg link Link Object of type bridge
762 *
763 * This will set the bridge change flag to self, meaning that changes to
764 * be applied with this link object will be applied directly to the physical
765 * device in a bridge instead of the virtual device.
766 *
767 * @return 0 on success or negative error code
768 * @return -NLE_OPNOTSUP Link is not a bridge
769 */
771{
772 struct bridge_data *bd = bridge_data(link);
773
774 IS_BRIDGE_LINK_ASSERT(link);
775
776 bd->b_self |= 1;
777 bd->ce_mask |= BRIDGE_ATTR_SELF;
778
779 return 0;
780}
781
782/**
783 * Get hardware mode
784 * @arg link Link object of type bridge
785 * @arg hwmode Output argument.
786 *
787 * @see rtnl_link_bridge_set_hwmode()
788 *
789 * @return 0 if hardware mode is present and returned in hwmode
790 * @return -NLE_NOATTR if hardware mode is not present
791 * @return -NLE_OPNOTSUP Link is not a bridge
792 */
793int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
794{
795 struct bridge_data *bd = bridge_data(link);
796
797 IS_BRIDGE_LINK_ASSERT(link);
798
799 if (!(bd->ce_mask & BRIDGE_ATTR_HWMODE))
800 return -NLE_NOATTR;
801
802 *hwmode = bd->b_hwmode;
803 return 0;
804}
805
806/**
807 * Set hardware mode
808 * @arg link Link object of type bridge
809 * @arg hwmode Hardware mode to set on link
810 *
811 * This will set the hardware mode of a link when it supports hardware
812 * offloads for bridging.
813 * @see rtnl_link_bridge_get_hwmode()
814 *
815 * Valid modes are:
816 * - RTNL_BRIDGE_HWMODE_VEB
817 * - RTNL_BRIDGE_HWMODE_VEPA
818 *
819 * When setting hardware mode, the change type will be set to self.
820 * @see rtnl_link_bridge_set_self()
821 *
822 * @return 0 on success or negative error code
823 * @return -NLE_OPNOTSUP Link is not a bridge
824 * @return -NLE_INVAL when specified hwmode is unsupported.
825 */
826int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
827{
828 int err;
829 struct bridge_data *bd = bridge_data(link);
830
831 if (hwmode > RTNL_BRIDGE_HWMODE_MAX)
832 return -NLE_INVAL;
833
834 if ((err = rtnl_link_bridge_set_self(link)) < 0)
835 return err;
836
837 bd->b_hwmode = hwmode;
838 bd->ce_mask |= BRIDGE_ATTR_HWMODE;
839
840 return 0;
841}
842
843
844static const struct trans_tbl bridge_flags[] = {
845 __ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode),
846 __ADD(RTNL_BRIDGE_BPDU_GUARD, bpdu_guard),
847 __ADD(RTNL_BRIDGE_ROOT_BLOCK, root_block),
848 __ADD(RTNL_BRIDGE_FAST_LEAVE, fast_leave),
849 __ADD(RTNL_BRIDGE_UNICAST_FLOOD, flood),
850 __ADD(RTNL_BRIDGE_LEARNING, learning),
851 __ADD(RTNL_BRIDGE_LEARNING_SYNC, learning_sync),
852};
853
854/**
855 * @name Flag Translation
856 * @{
857 */
858
859char *rtnl_link_bridge_flags2str(int flags, char *buf, size_t len)
860{
861 return __flags2str(flags, buf, len, bridge_flags, ARRAY_SIZE(bridge_flags));
862}
863
864int rtnl_link_bridge_str2flags(const char *name)
865{
866 return __str2flags(name, bridge_flags, ARRAY_SIZE(bridge_flags));
867}
868
869/** @} */
870
871static const struct trans_tbl port_states[] = {
872 __ADD(BR_STATE_DISABLED, disabled),
873 __ADD(BR_STATE_LISTENING, listening),
874 __ADD(BR_STATE_LEARNING, learning),
875 __ADD(BR_STATE_FORWARDING, forwarding),
876 __ADD(BR_STATE_BLOCKING, blocking),
877};
878
879/**
880 * @name Port State Translation
881 * @{
882 */
883
884char *rtnl_link_bridge_portstate2str(int st, char *buf, size_t len)
885{
886 return __type2str(st, buf, len, port_states, ARRAY_SIZE(port_states));
887}
888
889int rtnl_link_bridge_str2portstate(const char *name)
890{
891 return __str2type(name, port_states, ARRAY_SIZE(port_states));
892}
893
894/** @} */
895
896static const struct trans_tbl hw_modes[] = {
897 __ADD(RTNL_BRIDGE_HWMODE_VEB, veb),
898 __ADD(RTNL_BRIDGE_HWMODE_VEPA, vepa),
899 __ADD(RTNL_BRIDGE_HWMODE_UNDEF, undef),
900};
901
902/**
903 * @name Hardware Mode Translation
904 * @{
905 */
906
907char *rtnl_link_bridge_hwmode2str(uint16_t st, char *buf, size_t len) {
908 return __type2str(st, buf, len, hw_modes, ARRAY_SIZE(hw_modes));
909}
910
911uint16_t rtnl_link_bridge_str2hwmode(const char *name)
912{
913 return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
914}
915
916/** @} */
917
918int rtnl_link_bridge_pvid(struct rtnl_link *link)
919{
920 struct bridge_data *bd;
921
922 IS_BRIDGE_LINK_ASSERT(link);
923
924 bd = link->l_af_data[AF_BRIDGE];
925 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
926 return (int) bd->vlan_info.pvid;
927
928 return -EINVAL;
929}
930
931int rtnl_link_bridge_has_vlan(struct rtnl_link *link)
932{
933 struct bridge_data *bd;
934 int i;
935
936 IS_BRIDGE_LINK_ASSERT(link);
937
938 bd = link->l_af_data[AF_BRIDGE];
939 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
940 if (bd->vlan_info.pvid)
941 return 1;
942
943 for (i = 0; i < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; ++i) {
944 if (bd->vlan_info.vlan_bitmap[i] ||
945 bd->vlan_info.untagged_bitmap[i])
946 return 1;
947 }
948 }
949 return 0;
950}
951
952struct rtnl_link_bridge_vlan *rtnl_link_bridge_get_port_vlan(struct rtnl_link *link)
953{
954 struct bridge_data *data;
955
956 if (!rtnl_link_is_bridge(link))
957 return NULL;
958
959 data = link->l_af_data[AF_BRIDGE];
960 if (data && (data->ce_mask & BRIDGE_ATTR_PORT_VLAN))
961 return &data->vlan_info;
962
963 return NULL;
964}
965
966static struct rtnl_link_af_ops bridge_ops = {
967 .ao_family = AF_BRIDGE,
968 .ao_alloc = &bridge_alloc,
969 .ao_clone = &bridge_clone,
970 .ao_free = &bridge_free,
971 .ao_parse_protinfo = &bridge_parse_protinfo,
972 .ao_dump[NL_DUMP_DETAILS] = &bridge_dump_details,
973 .ao_compare = &bridge_compare,
974 .ao_parse_af_full = &bridge_parse_af_full,
975 .ao_get_af = &bridge_get_af,
976 .ao_fill_af = &bridge_fill_af,
977 .ao_fill_pi = &bridge_fill_pi,
978 .ao_fill_pi_flags = NLA_F_NESTED,
979 .ao_override_rtm = &bridge_override_rtm,
980 .ao_fill_af_no_nest = 1,
981};
982
983static void _nl_init bridge_init(void)
984{
985 rtnl_link_af_register(&bridge_ops);
986}
987
988static void _nl_exit bridge_exit(void)
989{
990 rtnl_link_af_unregister(&bridge_ops);
991}
992
993/** @} */
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition attr.c:710
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition attr.c:660
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
Definition attr.h:212
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition attr.h:194
int nla_type(const struct nlattr *nla)
Return type of the attribute.
Definition attr.c:108
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition attr.c:119
int nla_is_nested(const struct nlattr *attr)
Return true if attribute has NLA_F_NESTED flag set.
Definition attr.c:1045
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition attr.h:230
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition attr.c:610
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition attr.c:1033
#define nla_for_each_nested(pos, nla, rem)
Iterate over a stream of nested attributes.
Definition attr.h:324
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition attr.c:130
@ NLA_U8
8 bit integer
Definition attr.h:35
@ NLA_U16
16 bit integer
Definition attr.h:36
@ NLA_U32
32 bit integer
Definition attr.h:37
int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
Set Spanning Tree Protocol (STP) path cost.
Definition bridge.c:646
int rtnl_link_bridge_get_port_state(struct rtnl_link *link)
Get Spanning Tree Protocol (STP) port state.
Definition bridge.c:587
int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
Set hardware mode.
Definition bridge.c:826
int rtnl_link_bridge_has_ext_info(struct rtnl_link *link)
Check if bridge has extended information.
Definition bridge.c:534
int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
Create a new kernel bridge device.
Definition bridge.c:492
int rtnl_link_is_bridge(struct rtnl_link *link)
Check if a link is a bridge.
Definition bridge.c:515
int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
Set Spanning Tree Protocol (STP) port state.
Definition bridge.c:563
int rtnl_link_bridge_set_self(struct rtnl_link *link)
Set link change type to self.
Definition bridge.c:770
struct rtnl_link * rtnl_link_bridge_alloc(void)
Allocate link object of type bridge.
Definition bridge.c:466
int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
Get hardware mode.
Definition bridge.c:793
int rtnl_link_bridge_get_flags(struct rtnl_link *link)
Get flags.
Definition bridge.c:750
int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
Get Spanning Tree Protocol (STP) path cost.
Definition bridge.c:669
int rtnl_link_bridge_get_priority(struct rtnl_link *link)
Get priority.
Definition bridge.c:627
int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
Unset flags.
Definition bridge.c:694
int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
Set priority.
Definition bridge.c:606
int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
Set flags.
Definition bridge.c:727
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition utils.c:1017
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition types.h:21
Dumping parameters.
Definition types.h:32
Attribute validation policy.
Definition attr.h:63
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition attr.h:65