libnl 3.11.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#include <linux/rtnetlink.h>
18
19#include <netlink/netlink.h>
20#include <netlink/attr.h>
21#include <netlink/route/rtnl.h>
22#include <netlink/route/link/bridge.h>
23#include <netlink/list.h>
24
25#include "nl-route.h"
26#include "link-api.h"
27#include "nl-priv-dynamic-core/nl-core.h"
28#include "nl-priv-static-route/nl-priv-static-route.h"
29
30#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
31
32/** @cond SKIP */
33#define BRIDGE_ATTR_PORT_STATE (1UL << 0)
34#define BRIDGE_ATTR_PRIORITY (1UL << 1)
35#define BRIDGE_ATTR_COST (1UL << 2)
36#define BRIDGE_ATTR_FLAGS (1UL << 3)
37#define BRIDGE_ATTR_PORT_VLAN (1UL << 4)
38#define BRIDGE_ATTR_HWMODE (1UL << 5)
39#define BRIDGE_ATTR_CONFIG_MODE (1UL << 6)
40#define BRIDGE_ATTR_MST (1UL << 7)
41
42#define PRIV_FLAG_NEW_ATTRS (1UL << 0)
43
44struct bridge_data
45{
46 uint8_t b_port_state;
47 uint8_t b_priv_flags; /* internal flags */
48 uint16_t b_hwmode;
49 uint16_t b_priority;
50 uint16_t b_config_mode;
51 uint32_t b_cost;
52 uint32_t b_flags;
53 uint32_t b_flags_mask;
54 uint32_t ce_mask; /* HACK to support attr macros */
55 struct rtnl_link_bridge_vlan vlan_info;
56 struct nl_list_head mst_list;
57};
58
59struct mst_state_entry {
60 struct nl_list_head list_node;
61 uint16_t msti; /* unique within a list */
62 uint8_t state;
63};
64
65static void set_bit(unsigned nr, uint32_t *addr)
66{
67 if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
68 addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
69}
70
71static void unset_bit(unsigned nr, uint32_t *addr)
72{
73 if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
74 addr[nr / 32] &= ~(((uint32_t) 1) << (nr % 32));
75}
76
77static bool vlan_id_untagged(struct rtnl_link_bridge_vlan *vlan_info, uint16_t vid)
78{
79 uint32_t mask, bit;
80
81 _nl_assert(vid / 32u < ARRAY_SIZE(vlan_info->untagged_bitmap));
82
83 mask = vlan_info->untagged_bitmap[vid / 32];
84 bit = (((uint32_t) 1) << vid % 32);
85
86 return mask & bit;
87}
88
89static int find_next_bit(int i, uint32_t x)
90{
91 int j;
92
93 if (i >= 32)
94 return -1;
95
96 /* find first bit */
97 if (i < 0)
98 return __builtin_ffs(x);
99
100 /* mask off prior finds to get next */
101 j = __builtin_ffs(x >> i);
102 return j ? j + i : 0;
103}
104
105static struct rtnl_link_af_ops bridge_ops;
106
107#define IS_BRIDGE_LINK_ASSERT(link) \
108 if (!rtnl_link_is_bridge(link)) { \
109 APPBUG("A function was expecting a link object of type bridge."); \
110 return -NLE_OPNOTSUPP; \
111 }
112
113static inline struct bridge_data *bridge_data(struct rtnl_link *link)
114{
115 return rtnl_link_af_data(link, &bridge_ops);
116}
117
118static void *bridge_alloc(struct rtnl_link *link)
119{
120 struct bridge_data *bridge_data = calloc(1, sizeof(struct bridge_data));
121
122 if (bridge_data == NULL)
123 return NULL;
124
125 nl_init_list_head(&bridge_data->mst_list);
126
127 return bridge_data;
128}
129
130static struct mst_state_entry *mst_state_entry_alloc(void)
131{
132 struct mst_state_entry *entry;
133
134 entry = calloc(1, sizeof(*entry));
135 if (entry == NULL)
136 return NULL;
137
138 nl_init_list_head(&entry->list_node);
139
140 return entry;
141}
142
143static struct mst_state_entry *mst_state_entry_create(uint16_t msti,
144 uint8_t state)
145{
146 struct mst_state_entry *entry;
147
148 entry = mst_state_entry_alloc();
149 if (entry == NULL)
150 return NULL;
151
152 entry->msti = msti;
153 entry->state = state;
154
155 return entry;
156}
157
158static void mst_state_entry_del(struct mst_state_entry *entry)
159{
160 nl_list_del(&entry->list_node);
161 free(entry);
162}
163
164static void mst_list_clear(struct nl_list_head *mst_list)
165{
166 struct mst_state_entry *entry;
167 struct mst_state_entry *entry_safe;
168
169 nl_list_for_each_entry_safe(entry, entry_safe, mst_list, list_node)
170 mst_state_entry_del(entry);
171}
172
173static void bridge_data_free(struct bridge_data *bd)
174{
175 mst_list_clear(&bd->mst_list);
176 free(bd);
177}
178
179static void bridge_free(struct rtnl_link *link, void *data)
180{
181 bridge_data_free(data);
182}
183
184static struct mst_state_entry *find_mst_state_entry(struct bridge_data *bd,
185 uint16_t msti)
186{
187 struct mst_state_entry *entry;
188
189 nl_list_for_each_entry(entry, &bd->mst_list, list_node) {
190 if (entry->msti == msti)
191 return entry;
192 }
193
194 return NULL;
195}
196
197static struct mst_state_entry *
198mst_state_entry_clone(struct mst_state_entry *src)
199{
200 return mst_state_entry_create(src->msti, src->state);
201}
202
203static void *bridge_clone(struct rtnl_link *link, void *data)
204{
205 struct bridge_data *src_bd = (struct bridge_data *)data;
206 struct bridge_data *dst_bd;
207 struct mst_state_entry *entry;
208
209 dst_bd = calloc(1, sizeof(*dst_bd));
210 if (!dst_bd)
211 return NULL;
212
213 memcpy(dst_bd, src_bd, sizeof(*dst_bd));
214
215 nl_init_list_head(&dst_bd->mst_list);
216
217 nl_list_for_each_entry(entry, &src_bd->mst_list, list_node) {
218 struct mst_state_entry *entry_copy =
219 mst_state_entry_clone(entry);
220
221 if (!entry_copy) {
222 bridge_data_free(dst_bd);
223 return NULL;
224 }
225
226 nl_list_add_tail(&entry_copy->list_node, &dst_bd->mst_list);
227 }
228
229 return dst_bd;
230}
231
232static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = {
233 [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
234 [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
235 [IFLA_BRPORT_COST] = { .type = NLA_U32 },
236 [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
237 [IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
238 [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
239 [IFLA_BRPORT_FAST_LEAVE] = { .type = NLA_U8 },
240 [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 },
241 [IFLA_BRPORT_LEARNING_SYNC] = { .type = NLA_U8 },
242 [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
243 [IFLA_BRPORT_PROXYARP] = { .type = NLA_U8 },
244 [IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 },
245 [IFLA_BRPORT_MCAST_FLOOD] = { .type = NLA_U8 },
246 [IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NLA_U8 },
247 [IFLA_BRPORT_VLAN_TUNNEL] = { .type = NLA_U8 },
248 [IFLA_BRPORT_BCAST_FLOOD] = { .type = NLA_U8 },
249 [IFLA_BRPORT_NEIGH_SUPPRESS] = { .type = NLA_U8 },
250 [IFLA_BRPORT_ISOLATED] = { .type = NLA_U8 },
251 [IFLA_BRPORT_LOCKED] = { .type = NLA_U8 },
252 [IFLA_BRPORT_MAB] = { .type = NLA_U8 },
254};
255
256static void check_flag(struct rtnl_link *link, struct nlattr *attrs[],
257 int type, int flag)
258{
259 if (attrs[type] && nla_get_u8(attrs[type]))
261}
262
263static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
264 void *data)
265{
266 struct bridge_data *bd = data;
267 struct nlattr *br_attrs[IFLA_BRPORT_MAX+1];
268 int err;
269
270 /* Backwards compatibility */
271 if (!nla_is_nested(attr)) {
272 if (nla_len(attr) < 1)
273 return -NLE_RANGE;
274
275 bd->b_port_state = nla_get_u8(attr);
276 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
277
278 return 0;
279 }
280
281 if ((err = nla_parse_nested(br_attrs, IFLA_BRPORT_MAX, attr,
282 br_attrs_policy)) < 0)
283 return err;
284
285 bd->b_priv_flags |= PRIV_FLAG_NEW_ATTRS;
286
287 if (br_attrs[IFLA_BRPORT_STATE]) {
288 bd->b_port_state = nla_get_u8(br_attrs[IFLA_BRPORT_STATE]);
289 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
290 }
291
292 if (br_attrs[IFLA_BRPORT_PRIORITY]) {
293 bd->b_priority = nla_get_u16(br_attrs[IFLA_BRPORT_PRIORITY]);
294 bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
295 }
296
297 if (br_attrs[IFLA_BRPORT_COST]) {
298 bd->b_cost = nla_get_u32(br_attrs[IFLA_BRPORT_COST]);
299 bd->ce_mask |= BRIDGE_ATTR_COST;
300 }
301
302 check_flag(link, br_attrs, IFLA_BRPORT_MODE, RTNL_BRIDGE_HAIRPIN_MODE);
303 check_flag(link, br_attrs, IFLA_BRPORT_GUARD, RTNL_BRIDGE_BPDU_GUARD);
304 check_flag(link, br_attrs, IFLA_BRPORT_PROTECT, RTNL_BRIDGE_ROOT_BLOCK);
305 check_flag(link, br_attrs, IFLA_BRPORT_FAST_LEAVE, RTNL_BRIDGE_FAST_LEAVE);
306 check_flag(link, br_attrs, IFLA_BRPORT_UNICAST_FLOOD,
307 RTNL_BRIDGE_UNICAST_FLOOD);
308 check_flag(link, br_attrs, IFLA_BRPORT_LEARNING, RTNL_BRIDGE_LEARNING);
309 check_flag(link, br_attrs, IFLA_BRPORT_LEARNING_SYNC,
310 RTNL_BRIDGE_LEARNING_SYNC);
311 check_flag(link, br_attrs, IFLA_BRPORT_PROXYARP, RTNL_BRIDGE_PROXYARP);
312 check_flag(link, br_attrs, IFLA_BRPORT_PROXYARP_WIFI,
313 RTNL_BRIDGE_PROXYARP_WIFI);
314 check_flag(link, br_attrs, IFLA_BRPORT_MCAST_FLOOD,
315 RTNL_BRIDGE_MCAST_FLOOD);
316 check_flag(link, br_attrs, IFLA_BRPORT_MCAST_TO_UCAST,
317 RTNL_BRIDGE_MCAST_TO_UCAST);
318 check_flag(link, br_attrs, IFLA_BRPORT_VLAN_TUNNEL,
319 RTNL_BRIDGE_VLAN_TUNNEL);
320 check_flag(link, br_attrs, IFLA_BRPORT_BCAST_FLOOD,
321 RTNL_BRIDGE_BCAST_FLOOD);
322 check_flag(link, br_attrs, IFLA_BRPORT_NEIGH_SUPPRESS,
323 RTNL_BRIDGE_NEIGH_SUPPRESS);
324 check_flag(link, br_attrs, IFLA_BRPORT_ISOLATED, RTNL_BRIDGE_ISOLATED);
325 check_flag(link, br_attrs, IFLA_BRPORT_LOCKED, RTNL_BRIDGE_LOCKED);
326 check_flag(link, br_attrs, IFLA_BRPORT_MAB, RTNL_BRIDGE_MAB);
327 check_flag(link, br_attrs, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
328 RTNL_BRIDGE_NEIGH_VLAN_SUPPRESS);
329
330 return 0;
331}
332
335 [IFLA_BRIDGE_MST_ENTRY_STATE] = { .type = NLA_U8 },
336};
337
338static int bridge_parse_mst_state_entry(struct nlattr *attr,
339 struct bridge_data *bd)
340{
341 struct nlattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
342 struct mst_state_entry *new_entry;
343 struct mst_state_entry *existing_entry;
344 uint16_t msti;
345 uint8_t state;
346
347 if (nla_parse_nested(tb, IFLA_BRIDGE_MST_ENTRY_MAX, attr,
348 br_mst_entry_policy) < 0)
349 return -EINVAL;
350
351 if (!tb[IFLA_BRIDGE_MST_ENTRY_MSTI] ||
352 !tb[IFLA_BRIDGE_MST_ENTRY_STATE]) {
353 return -EINVAL;
354 }
355
356 msti = nla_get_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
357 state = nla_get_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
358
359 existing_entry = find_mst_state_entry(bd, msti);
360 if (existing_entry) {
361 existing_entry->state = state;
362 return 0;
363 }
364
365 new_entry = mst_state_entry_create(msti, state);
366 if (!new_entry)
367 return -ENOMEM;
368
369 nl_list_add_tail(&new_entry->list_node, &bd->mst_list);
370 bd->ce_mask |= BRIDGE_ATTR_MST;
371
372 return 0;
373}
374
375static int bridge_parse_mst(struct nlattr *mst_attr, struct bridge_data *bd) {
376 struct nlattr *attr;
377 int remaining;
378
379 nla_for_each_nested(attr, mst_attr, remaining) {
380 int err = 0;
381
382 switch (nla_type(attr)) {
383 case IFLA_BRIDGE_MST_ENTRY:
384 err = bridge_parse_mst_state_entry(attr, bd);
385 break;
386 default:
387 continue;
388 }
389
390 if (err)
391 return err;
392 }
393
394 return 0;
395}
396
397static int bridge_parse_af_full(struct rtnl_link *link, struct nlattr *attr_full,
398 void *data)
399{
400 struct bridge_data *bd = data;
401 struct bridge_vlan_info *vinfo = NULL;
402 uint16_t vid_range_start = 0;
403 uint16_t vid_range_flags = -1;
404
405 struct nlattr *attr;
406 int remaining;
407
408 nla_for_each_nested(attr, attr_full, remaining) {
409
410 if (nla_type(attr) == IFLA_BRIDGE_MODE) {
411 bd->b_hwmode = nla_get_u16(attr);
412 bd->ce_mask |= BRIDGE_ATTR_HWMODE;
413 continue;
414 } else if (nla_type(attr) == IFLA_BRIDGE_MST) {
415 int err = bridge_parse_mst(attr, bd);
416 if (err < 0)
417 return err;
418 continue;
419 } else if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
420 continue;
421
422 if (nla_len(attr) != sizeof(struct bridge_vlan_info))
423 return -EINVAL;
424
425 vinfo = nla_data(attr);
426 if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
427 return -EINVAL;
428
429
430 if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
431 vid_range_start = vinfo->vid;
432 vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN);
433 continue;
434 }
435
436 if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) {
437 /* sanity check the range flags */
438 if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) {
439 NL_DBG(1, "VLAN range flags differ; can not handle it.\n");
440 return -EINVAL;
441 }
442 } else {
443 vid_range_start = vinfo->vid;
444 }
445
446 for (; vid_range_start <= vinfo->vid; vid_range_start++) {
447 if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
448 bd->vlan_info.pvid = vinfo->vid;
449
450 if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
451 set_bit(vid_range_start, bd->vlan_info.untagged_bitmap);
452
453 set_bit(vid_range_start, bd->vlan_info.vlan_bitmap);
454 bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
455 }
456
457 vid_range_flags = -1;
458 }
459
460 return 0;
461}
462
463int _nl_bridge_fill_vlan_info(struct nl_msg *msg, struct rtnl_link_bridge_vlan * vlan_info)
464{
465 struct bridge_vlan_info vinfo;
466 int i = -1, j, k;
467 int start = -1, prev = -1;
468 int done;
469 bool untagged = false;
470
471 for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++)
472 {
473 int base_bit;
474 uint32_t a = vlan_info->vlan_bitmap[k];
475
476 base_bit = k * 32;
477 i = -1;
478 done = 0;
479 while (!done)
480 {
481 j = find_next_bit(i, a);
482 if (j > 0)
483 {
484 /* Skip if id equal to pvid */
485 if (vlan_info->pvid != 0 && j - 1 + base_bit == vlan_info->pvid)
486 goto nxt;
487 /* first hit of any bit */
488 if (start < 0 && prev < 0)
489 {
490 start = prev = j - 1 + base_bit;
491 /* Start range attribute */
492 untagged = vlan_id_untagged(vlan_info,start);
493 vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
494 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
495 vinfo.vid = start;
496 goto nxt;
497 }
498 /* this bit is a continuation of prior bits */
499 if (j - 2 + base_bit == prev)
500 {
501 prev++;
502 /* Hit end of untagged/tagged range */
503 if (untagged != vlan_id_untagged(vlan_info,prev))
504 {
505 /* put vlan into attributes */
506 if (start == prev-1)
507 {
508 /* only 1 vid in range */
509 vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
510 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
511 }
512 else
513 {
514 /* end of untagged/tagged range */
515 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
516
517 vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END;
518 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
519 vinfo.vid = prev-1;
520 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
521 }
522 /* start of new range */
523 untagged = !untagged;
524 vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
525 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
526 vinfo.vid = prev;
527 }
528 goto nxt;
529 }
530 }
531 else
532 done = 1;
533
534 if (start >= 0)
535 {
536 if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
537 break;
538
539 if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN && start != prev)
540 {
541 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
542
543 vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END;
544 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
545 vinfo.vid = prev;
546 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
547 }
548 else if (start == prev)
549 {
550 vinfo.flags = untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
551 vinfo.vid = start;
552 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
553 }
554
555 if (done)
556 break;
557 }
558 if (j > 0)
559 {
560 start = prev = j - 1 + base_bit;
561 untagged = vlan_id_untagged(vlan_info,start);
562 vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
563 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
564 vinfo.vid = start;
565 }
566nxt:
567 i = j;
568 }
569 }
570
571 if (vlan_info->pvid != 0)
572 {
573 untagged = vlan_id_untagged(vlan_info,vlan_info->pvid);
574 vinfo.flags = BRIDGE_VLAN_INFO_PVID;
575 vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
576 vinfo.vid = vlan_info->pvid;
577 NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
578 }
579
580 return 0;
581
582nla_put_failure:
583 return -NLE_MSGSIZE;
584}
585
586static int bridge_fill_mst(struct nl_msg *msg, struct nl_list_head *mst_list) {
587 struct nlattr *attr = NULL;
588 struct nlattr *entry_attr = NULL;
589 struct mst_state_entry *entry;
590
591 if (nl_list_empty(mst_list))
592 return 0;
593
594 attr = nla_nest_start(msg, IFLA_BRIDGE_MST);
595 if (!attr)
596 goto err_out;
597
598 nl_list_for_each_entry(entry, mst_list, list_node) {
599 entry_attr = nla_nest_start(msg, IFLA_BRIDGE_MST_ENTRY);
600 if (!entry_attr)
601 goto err_out_nest_cancel_attr;
602
603 NLA_PUT_U16(msg, IFLA_BRIDGE_MST_ENTRY_MSTI, entry->msti);
604 NLA_PUT_U8(msg, IFLA_BRIDGE_MST_ENTRY_STATE, entry->state);
605
606 nla_nest_end(msg, entry_attr);
607 }
608
609 nla_nest_end(msg, attr);
610
611 return 0;
612
613nla_put_failure:
614 nla_nest_cancel(msg, entry_attr);
615err_out_nest_cancel_attr:
616 nla_nest_cancel(msg, attr);
617err_out:
618 return -NLE_MSGSIZE;
619}
620
621static int bridge_fill_af(struct rtnl_link *link, struct nl_msg *msg,
622 void *data)
623{
624 struct bridge_data *bd = data;
625
626 if (bd->ce_mask & BRIDGE_ATTR_HWMODE)
627 {
628 NLA_PUT_U16(msg, IFLA_BRIDGE_MODE, bd->b_hwmode);
629 bd->b_config_mode = BRIDGE_FLAGS_SELF;
630 bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
631 }
632
633 if (bd->ce_mask & BRIDGE_ATTR_MST)
634 {
635 if (bridge_fill_mst(msg, &bd->mst_list) < 0) {
636 goto nla_put_failure;
637 }
638 }
639
640 if (bd->ce_mask & BRIDGE_ATTR_CONFIG_MODE)
641 NLA_PUT_U16(msg, IFLA_BRIDGE_FLAGS, bd->b_config_mode);
642
643 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
644 if (_nl_bridge_fill_vlan_info(msg, &bd->vlan_info)) {
645 goto nla_put_failure;
646 }
647 }
648
649 return 0;
650
651nla_put_failure:
652 return -NLE_MSGSIZE;
653}
654
655static int bridge_fill_pi(struct rtnl_link *link, struct nl_msg *msg,
656 void *data)
657{
658 struct bridge_data *bd = data;
659
660 if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
661 if (bd->b_flags_mask & RTNL_BRIDGE_BPDU_GUARD) {
662 NLA_PUT_U8(msg, IFLA_BRPORT_GUARD,
663 !!(bd->b_flags & RTNL_BRIDGE_BPDU_GUARD));
664 }
665 if (bd->b_flags_mask & RTNL_BRIDGE_HAIRPIN_MODE) {
666 NLA_PUT_U8(msg, IFLA_BRPORT_MODE,
667 !!(bd->b_flags & RTNL_BRIDGE_HAIRPIN_MODE));
668 }
669 if (bd->b_flags_mask & RTNL_BRIDGE_FAST_LEAVE) {
670 NLA_PUT_U8(msg, IFLA_BRPORT_FAST_LEAVE,
671 !!(bd->b_flags & RTNL_BRIDGE_FAST_LEAVE));
672 }
673 if (bd->b_flags_mask & RTNL_BRIDGE_ROOT_BLOCK) {
674 NLA_PUT_U8(msg, IFLA_BRPORT_PROTECT,
675 !!(bd->b_flags & RTNL_BRIDGE_ROOT_BLOCK));
676 }
677 if (bd->b_flags_mask & RTNL_BRIDGE_UNICAST_FLOOD) {
678 NLA_PUT_U8(msg, IFLA_BRPORT_UNICAST_FLOOD,
679 !!(bd->b_flags & RTNL_BRIDGE_UNICAST_FLOOD));
680 }
681 if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING) {
682 NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING,
683 !!(bd->b_flags & RTNL_BRIDGE_LEARNING));
684 }
685 if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING_SYNC) {
686 NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING_SYNC,
687 !!(bd->b_flags & RTNL_BRIDGE_LEARNING_SYNC));
688 }
689 if (bd->b_flags_mask & RTNL_BRIDGE_PROXYARP) {
690 NLA_PUT_U8(msg, IFLA_BRPORT_PROXYARP,
691 !!(bd->b_flags & RTNL_BRIDGE_PROXYARP));
692 }
693 if (bd->b_flags_mask & RTNL_BRIDGE_PROXYARP_WIFI) {
694 NLA_PUT_U8(msg, IFLA_BRPORT_PROXYARP_WIFI,
695 !!(bd->b_flags & RTNL_BRIDGE_PROXYARP_WIFI));
696 }
697 if (bd->b_flags_mask & RTNL_BRIDGE_MCAST_FLOOD) {
698 NLA_PUT_U8(msg, IFLA_BRPORT_MCAST_FLOOD,
699 !!(bd->b_flags & RTNL_BRIDGE_MCAST_FLOOD));
700 }
701 if (bd->b_flags_mask & RTNL_BRIDGE_MCAST_TO_UCAST) {
702 NLA_PUT_U8(msg, IFLA_BRPORT_MCAST_TO_UCAST,
703 !!(bd->b_flags &
704 RTNL_BRIDGE_MCAST_TO_UCAST));
705 }
706 if (bd->b_flags_mask & RTNL_BRIDGE_VLAN_TUNNEL) {
707 NLA_PUT_U8(msg, IFLA_BRPORT_VLAN_TUNNEL,
708 !!(bd->b_flags & RTNL_BRIDGE_VLAN_TUNNEL));
709 }
710 if (bd->b_flags_mask & RTNL_BRIDGE_BCAST_FLOOD) {
711 NLA_PUT_U8(msg, IFLA_BRPORT_BCAST_FLOOD,
712 !!(bd->b_flags & RTNL_BRIDGE_BCAST_FLOOD));
713 }
714 if (bd->b_flags_mask & RTNL_BRIDGE_NEIGH_SUPPRESS) {
715 NLA_PUT_U8(msg, IFLA_BRPORT_NEIGH_SUPPRESS,
716 !!(bd->b_flags &
717 RTNL_BRIDGE_NEIGH_SUPPRESS));
718 }
719 if (bd->b_flags_mask & RTNL_BRIDGE_ISOLATED) {
720 NLA_PUT_U8(msg, IFLA_BRPORT_ISOLATED,
721 !!(bd->b_flags & RTNL_BRIDGE_ISOLATED));
722 }
723 if (bd->b_flags_mask & RTNL_BRIDGE_LOCKED) {
724 NLA_PUT_U8(msg, IFLA_BRPORT_LOCKED,
725 !!(bd->b_flags & RTNL_BRIDGE_LOCKED));
726 }
727 if (bd->b_flags_mask & RTNL_BRIDGE_MAB) {
728 NLA_PUT_U8(msg, IFLA_BRPORT_MAB,
729 !!(bd->b_flags & RTNL_BRIDGE_MAB));
730 }
731 if (bd->b_flags_mask & RTNL_BRIDGE_NEIGH_VLAN_SUPPRESS) {
732 NLA_PUT_U8(msg, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
733 !!(bd->b_flags &
734 RTNL_BRIDGE_NEIGH_VLAN_SUPPRESS));
735 }
736 }
737
738 if (bd->ce_mask & BRIDGE_ATTR_COST)
739 NLA_PUT_U32(msg, IFLA_BRPORT_COST, bd->b_cost);
740
741 if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
742 NLA_PUT_U16(msg, IFLA_BRPORT_PRIORITY, bd->b_priority);
743
744 if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
745 NLA_PUT_U8(msg, IFLA_BRPORT_STATE, bd->b_port_state);
746
747 return 0;
748
749nla_put_failure:
750 return -NLE_MSGSIZE;
751}
752
753static int bridge_override_rtm(struct rtnl_link *link) {
754 struct bridge_data *bd;
755
756 if (!rtnl_link_is_bridge(link))
757 return 0;
758
759 bd = bridge_data(link);
760
761 if (bd->ce_mask & (BRIDGE_ATTR_FLAGS | BRIDGE_ATTR_MST))
762 return 1;
763
764 return 0;
765}
766
767static int bridge_get_af(struct nl_msg *msg, uint32_t *ext_filter_mask)
768{
769 *ext_filter_mask |= RTEXT_FILTER_BRVLAN | RTEXT_FILTER_MST;
770 return 0;
771}
772
773static void dump_bitmap(struct nl_dump_params *p, const uint32_t *b)
774{
775 int i = -1, j, k;
776 int start = -1, prev = -1;
777 int done, found = 0;
778
779 for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
780 int base_bit;
781 uint32_t a = b[k];
782
783 base_bit = k * 32;
784 i = -1;
785 done = 0;
786 while (!done) {
787 j = find_next_bit(i, a);
788 if (j > 0) {
789 /* first hit of any bit */
790 if (start < 0 && prev < 0) {
791 start = prev = j - 1 + base_bit;
792 goto next;
793 }
794 /* this bit is a continuation of prior bits */
795 if (j - 2 + base_bit == prev) {
796 prev++;
797 goto next;
798 }
799 } else
800 done = 1;
801
802 if (start >= 0) {
803 found++;
804 if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
805 break;
806
807 nl_dump(p, " %d", start);
808 if (start != prev)
809 nl_dump(p, "-%d", prev);
810
811 if (done)
812 break;
813 }
814 if (j > 0)
815 start = prev = j - 1 + base_bit;
816next:
817 i = j;
818 }
819 }
820 if (!found)
821 nl_dump(p, " <none>");
822
823 return;
824}
825
826static void rtnl_link_bridge_dump_vlans(struct nl_dump_params *p,
827 struct bridge_data *bd)
828{
829 nl_dump(p, "pvid %u", bd->vlan_info.pvid);
830
831 nl_dump(p, " all vlans:");
832 dump_bitmap(p, bd->vlan_info.vlan_bitmap);
833
834 nl_dump(p, " untagged vlans:");
835 dump_bitmap(p, bd->vlan_info.untagged_bitmap);
836}
837
838static const char *const br_port_state_names[] = {
839 [BR_STATE_DISABLED] = "disabled",
840 [BR_STATE_LISTENING] = "listening",
841 [BR_STATE_LEARNING] = "learning",
842 [BR_STATE_FORWARDING] = "forwarding",
843 [BR_STATE_BLOCKING] = "blocking",
844};
845
846static const char *stp_state2str(uint8_t state) {
847 if (state > BR_STATE_BLOCKING)
848 return "unknown";
849
850 return br_port_state_names[state];
851}
852
853static void bridge_dump_details(struct rtnl_link *link,
854 struct nl_dump_params *p, void *data)
855{
856 struct bridge_data *bd = data;
857
858 nl_dump_line(p, " bridge: ");
859
860 if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
861 nl_dump(p, "port-state %u ", bd->b_port_state);
862
863 if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
864 nl_dump(p, "prio %u ", bd->b_priority);
865
866 if (bd->ce_mask & BRIDGE_ATTR_COST)
867 nl_dump(p, "cost %u ", bd->b_cost);
868
869 if (bd->ce_mask & BRIDGE_ATTR_HWMODE) {
870 char hbuf[32];
871
872 rtnl_link_bridge_hwmode2str(bd->b_hwmode, hbuf, sizeof(hbuf));
873 nl_dump(p, "hwmode %s", hbuf);
874 }
875
876 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
877 rtnl_link_bridge_dump_vlans(p, bd);
878
879 if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
880 char buf[256];
881
882 rtnl_link_bridge_flags2str(bd->b_flags & bd->b_flags_mask,
883 buf, sizeof(buf));
884 nl_dump(p, "%s", buf);
885 }
886
887 nl_dump(p, "\n");
888
889 if (bd->ce_mask & BRIDGE_ATTR_MST && !nl_list_empty(&bd->mst_list)) {
890 struct mst_state_entry *entry;
891
892 nl_dump_line(p, " mst:\n");
893
894 nl_list_for_each_entry(entry, &bd->mst_list, list_node) {
895 nl_dump_line(p, " instance %u: %s\n",
896 entry->msti, stp_state2str(entry->state));
897 }
898 }
899}
900
901static bool mst_state_entries_are_equal(const struct mst_state_entry *a,
902 const struct mst_state_entry *b)
903{
904 return a->msti == b->msti && a->state == b->state;
905}
906
907/**
908 * Compares two MST lists for equality
909 * @arg list_1 The first list
910 * @arg list_2 The second list
911 *
912 * This comparison checks that the MST lists have the same entries and that they
913 * are in the same order (although the ordering is not significant to the
914 * kernel).
915 *
916 * @return true if the lists are equal, false otherwise
917 */
918static bool msts_lists_are_equal(struct nl_list_head *list_1,
919 struct nl_list_head *list_2)
920{
921 struct mst_state_entry *entry_a;
922 struct mst_state_entry *entry_b;
923
924 entry_a =
925 nl_list_entry(list_1->next, struct mst_state_entry, list_node);
926 entry_b =
927 nl_list_entry(list_2->next, struct mst_state_entry, list_node);
928
929 /* while both lists have items left to process */
930 while (&entry_a->list_node != list_1 && &entry_b->list_node != list_2) {
931 if (!mst_state_entries_are_equal(entry_a, entry_b)) {
932 return false;
933 }
934
935 entry_a = nl_list_entry(entry_a->list_node.next,
936 struct mst_state_entry, list_node);
937 entry_b = nl_list_entry(entry_b->list_node.next,
938 struct mst_state_entry, list_node);
939 }
940
941 /* return true only if both lists were the same length */
942 return &entry_a->list_node == list_1 && &entry_b->list_node == list_2;
943}
944
945static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b,
946 int family, uint32_t attrs, int flags)
947{
948 struct bridge_data *a = bridge_data(_a);
949 struct bridge_data *b = bridge_data(_b);
950 int diff = 0;
951
952#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
953 diff |= _DIFF(BRIDGE_ATTR_PORT_STATE,
954 a->b_port_state != b->b_port_state);
955 diff |= _DIFF(BRIDGE_ATTR_PRIORITY, a->b_priority != b->b_priority);
956 diff |= _DIFF(BRIDGE_ATTR_COST, a->b_cost != b->b_cost);
957 diff |= _DIFF(BRIDGE_ATTR_PORT_VLAN,
958 memcmp(&a->vlan_info, &b->vlan_info,
959 sizeof(struct rtnl_link_bridge_vlan)));
960 diff |= _DIFF(BRIDGE_ATTR_HWMODE, a->b_hwmode != b->b_hwmode);
961 diff |= _DIFF(BRIDGE_ATTR_CONFIG_MODE, a->b_config_mode != b->b_config_mode);
962 diff |= _DIFF(BRIDGE_ATTR_MST,
963 !msts_lists_are_equal(&a->mst_list, &b->mst_list));
964
965 if (flags & LOOSE_COMPARISON)
966 diff |= _DIFF(BRIDGE_ATTR_FLAGS,
967 (a->b_flags ^ b->b_flags) & b->b_flags_mask);
968 else
969 diff |= _DIFF(BRIDGE_ATTR_FLAGS, a->b_flags != b->b_flags);
970#undef _DIFF
971
972 return diff;
973}
974/** @endcond */
975
976/**
977 * Allocate link object of type bridge
978 *
979 * @return Allocated link object or NULL.
980 */
982{
983 struct rtnl_link *link;
984
985 if (!(link = rtnl_link_alloc()))
986 return NULL;
987
988 if (rtnl_link_set_type(link, "bridge") < 0) {
989 rtnl_link_put(link);
990 return NULL;
991 }
992
993 return link;
994}
995
996/**
997 * Create a new kernel bridge device
998 * @arg sk netlink socket
999 * @arg name name of the bridge device or NULL
1000 *
1001 * Creates a new bridge device in the kernel. If no name is
1002 * provided, the kernel will automatically pick a name of the
1003 * form "type%d" (e.g. bridge0, vlan1, etc.)
1004 *
1005 * @return 0 on success or a negative error code
1006*/
1007int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
1008{
1009 int err;
1010 struct rtnl_link *link;
1011
1012 if (!(link = rtnl_link_bridge_alloc()))
1013 return -NLE_NOMEM;
1014
1015 if(name)
1016 rtnl_link_set_name(link, name);
1017
1018 err = rtnl_link_add(sk, link, NLM_F_CREATE);
1019 rtnl_link_put(link);
1020
1021 return err;
1022}
1023
1024/**
1025 * Check if a link is a bridge
1026 * @arg link Link object
1027 *
1028 * @return 1 if the link is a bridge, 0 otherwise.
1029 */
1031{
1032 return link->l_family == AF_BRIDGE &&
1033 link->l_af_ops == &bridge_ops;
1034}
1035
1036/**
1037 * Check if bridge has extended information
1038 * @arg link Link object of type bridge
1039 *
1040 * Checks if the bridge object has been constructed based on
1041 * information that is only available in newer kernels. This
1042 * affectes the following functions:
1043 * - rtnl_link_bridge_get_cost()
1044 * - rtnl_link_bridge_get_priority()
1045 * - rtnl_link_bridge_get_flags()
1046 *
1047 * @return 1 if extended information is available, otherwise 0 is returned.
1048 */
1050{
1051 struct bridge_data *bd;
1052
1053 if (!rtnl_link_is_bridge(link))
1054 return 0;
1055
1056 bd = bridge_data(link);
1057 return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS);
1058}
1059
1060/**
1061 * Set Spanning Tree Protocol (STP) port state
1062 * @arg link Link object of type bridge
1063 * @arg state New STP port state
1064 *
1065 * The value of state must be one of the following:
1066 * - BR_STATE_DISABLED
1067 * - BR_STATE_LISTENING
1068 * - BR_STATE_LEARNING
1069 * - BR_STATE_FORWARDING
1070 * - BR_STATE_BLOCKING
1071 *
1072 * @see rtnl_link_bridge_get_port_state()
1073 *
1074 * @return 0 on success or a negative error code.
1075 * @retval -NLE_OPNOTSUPP Link is not a bridge
1076 * @retval -NLE_INVAL Invalid state value (0..BR_STATE_BLOCKING)
1077 */
1078int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
1079{
1080 struct bridge_data *bd = bridge_data(link);
1081
1082 IS_BRIDGE_LINK_ASSERT(link);
1083
1084 if (state > BR_STATE_BLOCKING)
1085 return -NLE_INVAL;
1086
1087 bd->b_port_state = state;
1088 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
1089
1090 return 0;
1091}
1092
1093/**
1094 * Get Spanning Tree Protocol (STP) port state
1095 * @arg link Link object of type bridge
1096 *
1097 * @see rtnl_link_bridge_set_port_state()
1098 *
1099 * @return The STP port state or a negative error code.
1100 * @retval -NLE_OPNOTSUPP Link is not a bridge
1101 */
1103{
1104 struct bridge_data *bd = bridge_data(link);
1105
1106 IS_BRIDGE_LINK_ASSERT(link);
1107
1108 return bd->b_port_state;
1109}
1110
1111/**
1112 * Set priority
1113 * @arg link Link object of type bridge
1114 * @arg prio Bridge priority
1115 *
1116 * @see rtnl_link_bridge_get_priority()
1117 *
1118 * @return 0 on success or a negative error code.
1119 * @retval -NLE_OPNOTSUPP Link is not a bridge
1120 */
1121int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
1122{
1123 struct bridge_data *bd = bridge_data(link);
1124
1125 IS_BRIDGE_LINK_ASSERT(link);
1126
1127 bd->b_priority = prio;
1128 bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
1129
1130 return 0;
1131}
1132
1133/**
1134 * Get priority
1135 * @arg link Link object of type bridge
1136 *
1137 * @see rtnl_link_bridge_set_priority()
1138 *
1139 * @return 0 on success or a negative error code.
1140 * @retval -NLE_OPNOTSUPP Link is not a bridge
1141 */
1143{
1144 struct bridge_data *bd = bridge_data(link);
1145
1146 IS_BRIDGE_LINK_ASSERT(link);
1147
1148 return bd->b_priority;
1149}
1150
1151/**
1152 * Set Spanning Tree Protocol (STP) path cost
1153 * @arg link Link object of type bridge
1154 * @arg cost New STP path cost value
1155 *
1156 * @see rtnl_link_bridge_get_cost()
1157 *
1158 * @return The bridge priority or a negative error code.
1159 * @retval -NLE_OPNOTSUPP Link is not a bridge
1160 */
1161int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
1162{
1163 struct bridge_data *bd = bridge_data(link);
1164
1165 IS_BRIDGE_LINK_ASSERT(link);
1166
1167 bd->b_cost = cost;
1168 bd->ce_mask |= BRIDGE_ATTR_COST;
1169
1170 return 0;
1171}
1172
1173/**
1174 * Get Spanning Tree Protocol (STP) path cost
1175 * @arg link Link object of type bridge
1176 * @arg cost Pointer to store STP cost value
1177 *
1178 * @see rtnl_link_bridge_set_cost()
1179 *
1180 * @return 0 on success or a negative error code.
1181 * @retval -NLE_OPNOTSUPP Link is not a bridge
1182 * @retval -NLE_INVAL `cost` is not a valid pointer
1183 */
1184int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
1185{
1186 struct bridge_data *bd = bridge_data(link);
1187
1188 IS_BRIDGE_LINK_ASSERT(link);
1189
1190 if (!cost)
1191 return -NLE_INVAL;
1192
1193 *cost = bd->b_cost;
1194
1195 return 0;
1196}
1197
1198/**
1199 * Unset flags
1200 * @arg link Link object of type bridge
1201 * @arg flags Bridging flags to unset
1202 *
1203 * @see rtnl_link_bridge_set_flags()
1204 * @see rtnl_link_bridge_get_flags()
1205 *
1206 * @return 0 on success or a negative error code.
1207 * @retval -NLE_OPNOTSUPP Link is not a bridge
1208 */
1209int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
1210{
1211 struct bridge_data *bd = bridge_data(link);
1212
1213 IS_BRIDGE_LINK_ASSERT(link);
1214
1215 bd->b_flags_mask |= flags;
1216 bd->b_flags &= ~flags;
1217 bd->ce_mask |= BRIDGE_ATTR_FLAGS;
1218
1219 return 0;
1220}
1221
1222/**
1223 * Set flags
1224 * @arg link Link object of type bridge
1225 * @arg flags Bridging flags to set
1226 *
1227 * Valid flags are:
1228 * - RTNL_BRIDGE_HAIRPIN_MODE
1229 * - RTNL_BRIDGE_BPDU_GUARD
1230 * - RTNL_BRIDGE_ROOT_BLOCK
1231 * - RTNL_BRIDGE_FAST_LEAVE
1232 * - RTNL_BRIDGE_UNICAST_FLOOD
1233 * - RTNL_BRIDGE_LEARNING
1234 * - RTNL_BRIDGE_LEARNING_SYNC
1235 * - RTNL_BRIDGE_PROXYARP
1236 * - RTNL_BRIDGE_PROXYARP_WIFI
1237 * - RTNL_BRIDGE_MCAST_FLOOD
1238 * - RTNL_BRIDGE_MCAST_TO_UCAST
1239 * - RTNL_BRIDGE_VLAN_TUNNEL
1240 * - RTNL_BRIDGE_BCAST_FLOOD
1241 * - RTNL_BRIDGE_NEIGH_SUPPRESS
1242 * - RTNL_BRIDGE_ISOLATED
1243 * - RTNL_BRIDGE_LOCKED
1244 * - RTNL_BRIDGE_MAB
1245 * - RTNL_BRIDGE_NEIGH_VLAN_SUPPRESS
1246 *
1247 * @see rtnl_link_bridge_unset_flags()
1248 * @see rtnl_link_bridge_get_flags()
1249 *
1250 * @return 0 on success or a negative error code.
1251 * @retval -NLE_OPNOTSUPP Link is not a bridge
1252 */
1253int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
1254{
1255 struct bridge_data *bd = bridge_data(link);
1256
1257 IS_BRIDGE_LINK_ASSERT(link);
1258
1259 bd->b_flags_mask |= flags;
1260 bd->b_flags |= flags;
1261 bd->ce_mask |= BRIDGE_ATTR_FLAGS;
1262
1263 return 0;
1264}
1265
1266/**
1267 * Get flags
1268 * @arg link Link object of type bridge
1269 *
1270 * @see rtnl_link_bridge_set_flags()
1271 * @see rtnl_link_bridge_unset_flags()
1272 *
1273 * @return Flags or a negative error code.
1274 * @retval -NLE_OPNOTSUPP Link is not a bridge
1275 */
1277{
1278 struct bridge_data *bd = bridge_data(link);
1279
1280 IS_BRIDGE_LINK_ASSERT(link);
1281
1282 return bd->b_flags;
1283}
1284
1285/**
1286 * Set link change type to self
1287 * @arg link Link Object of type bridge
1288 *
1289 * This will set the bridge change flag to self, meaning that changes to
1290 * be applied with this link object will be applied directly to the physical
1291 * device in a bridge instead of the virtual device.
1292 *
1293 * @return 0 on success or negative error code
1294 * @return -NLE_OPNOTSUP Link is not a bridge
1295 */
1297{
1298 struct bridge_data *bd = bridge_data(link);
1299
1300 IS_BRIDGE_LINK_ASSERT(link);
1301
1302 bd->b_config_mode = BRIDGE_FLAGS_SELF;
1303 bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
1304
1305 return 0;
1306}
1307
1308/**
1309 * Set link change type to master
1310 * @arg link Link Object of type bridge
1311 *
1312 * This will set the bridge change flag to master, meaning that changes to
1313 * be applied with this link object will be applied directly to the virtual
1314 * device in a bridge instead of the physical device.
1315 *
1316 * @return 0 on success or negative error code
1317 * @return -NLE_OPNOTSUP Link is not a bridge
1318 */
1320{
1321 struct bridge_data *bd = bridge_data(link);
1322
1323 IS_BRIDGE_LINK_ASSERT(link);
1324
1325 bd->b_config_mode = BRIDGE_FLAGS_MASTER;
1326 bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
1327
1328 return 0;
1329}
1330
1331/**
1332 * Get hardware mode
1333 * @arg link Link object of type bridge
1334 * @arg hwmode Output argument.
1335 *
1336 * @see rtnl_link_bridge_set_hwmode()
1337 *
1338 * @return 0 if hardware mode is present and returned in hwmode
1339 * @return -NLE_NOATTR if hardware mode is not present
1340 * @return -NLE_OPNOTSUP Link is not a bridge
1341 */
1342int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
1343{
1344 struct bridge_data *bd = bridge_data(link);
1345
1346 IS_BRIDGE_LINK_ASSERT(link);
1347
1348 if (!(bd->ce_mask & BRIDGE_ATTR_HWMODE))
1349 return -NLE_NOATTR;
1350
1351 *hwmode = bd->b_hwmode;
1352 return 0;
1353}
1354
1355/**
1356 * Set hardware mode
1357 * @arg link Link object of type bridge
1358 * @arg hwmode Hardware mode to set on link
1359 *
1360 * This will set the hardware mode of a link when it supports hardware
1361 * offloads for bridging.
1362 * @see rtnl_link_bridge_get_hwmode()
1363 *
1364 * Valid modes are:
1365 * - RTNL_BRIDGE_HWMODE_VEB
1366 * - RTNL_BRIDGE_HWMODE_VEPA
1367 *
1368 * When setting hardware mode, the change type will be set to self.
1369 * @see rtnl_link_bridge_set_self()
1370 *
1371 * @return 0 on success or negative error code
1372 * @return -NLE_OPNOTSUP Link is not a bridge
1373 * @return -NLE_INVAL when specified hwmode is unsupported.
1374 */
1375int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
1376{
1377 int err;
1378 struct bridge_data *bd = bridge_data(link);
1379
1380 if (hwmode > RTNL_BRIDGE_HWMODE_MAX)
1381 return -NLE_INVAL;
1382
1383 if ((err = rtnl_link_bridge_set_self(link)) < 0)
1384 return err;
1385
1386 bd->b_hwmode = hwmode;
1387 bd->ce_mask |= BRIDGE_ATTR_HWMODE;
1388
1389 return 0;
1390}
1391
1392
1393static const struct trans_tbl bridge_flags[] = {
1394 __ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode),
1395 __ADD(RTNL_BRIDGE_BPDU_GUARD, bpdu_guard),
1396 __ADD(RTNL_BRIDGE_ROOT_BLOCK, root_block),
1397 __ADD(RTNL_BRIDGE_FAST_LEAVE, fast_leave),
1398 __ADD(RTNL_BRIDGE_UNICAST_FLOOD, flood),
1399 __ADD(RTNL_BRIDGE_LEARNING, learning),
1400 __ADD(RTNL_BRIDGE_LEARNING_SYNC, learning_sync),
1401 __ADD(RTNL_BRIDGE_PROXYARP, proxy_arp),
1402 __ADD(RTNL_BRIDGE_PROXYARP_WIFI, proxy_arp_wifi),
1403 __ADD(RTNL_BRIDGE_MCAST_FLOOD, mcast_flood),
1404 __ADD(RTNL_BRIDGE_MCAST_TO_UCAST, mcast_to_unicast),
1405 __ADD(RTNL_BRIDGE_VLAN_TUNNEL, vlan_tunnel),
1406 __ADD(RTNL_BRIDGE_BCAST_FLOOD, bcast_flood),
1407 __ADD(RTNL_BRIDGE_NEIGH_SUPPRESS, neigh_suppress),
1408 __ADD(RTNL_BRIDGE_ISOLATED, isolated),
1409 __ADD(RTNL_BRIDGE_LOCKED, locked),
1410 __ADD(RTNL_BRIDGE_MAB, mab),
1411 __ADD(RTNL_BRIDGE_NEIGH_VLAN_SUPPRESS, neigh_vlan_suppress),
1412};
1413
1414/**
1415 * @name Flag Translation
1416 * @{
1417 */
1418
1419char *rtnl_link_bridge_flags2str(int flags, char *buf, size_t len)
1420{
1421 return __flags2str(flags, buf, len, bridge_flags, ARRAY_SIZE(bridge_flags));
1422}
1423
1424int rtnl_link_bridge_str2flags(const char *name)
1425{
1426 return __str2flags(name, bridge_flags, ARRAY_SIZE(bridge_flags));
1427}
1428
1429/** @} */
1430
1431static const struct trans_tbl port_states[] = {
1432 __ADD(BR_STATE_DISABLED, disabled),
1433 __ADD(BR_STATE_LISTENING, listening),
1434 __ADD(BR_STATE_LEARNING, learning),
1435 __ADD(BR_STATE_FORWARDING, forwarding),
1436 __ADD(BR_STATE_BLOCKING, blocking),
1437};
1438
1439/**
1440 * @name Port State Translation
1441 * @{
1442 */
1443
1444char *rtnl_link_bridge_portstate2str(int st, char *buf, size_t len)
1445{
1446 return __type2str(st, buf, len, port_states, ARRAY_SIZE(port_states));
1447}
1448
1449int rtnl_link_bridge_str2portstate(const char *name)
1450{
1451 return __str2type(name, port_states, ARRAY_SIZE(port_states));
1452}
1453
1454/** @} */
1455
1456static const struct trans_tbl hw_modes[] = {
1457 __ADD(RTNL_BRIDGE_HWMODE_VEB, veb),
1458 __ADD(RTNL_BRIDGE_HWMODE_VEPA, vepa),
1459 __ADD(RTNL_BRIDGE_HWMODE_UNDEF, undef),
1460};
1461
1462/**
1463 * @name Hardware Mode Translation
1464 * @{
1465 */
1466
1467char *rtnl_link_bridge_hwmode2str(uint16_t st, char *buf, size_t len) {
1468 return __type2str(st, buf, len, hw_modes, ARRAY_SIZE(hw_modes));
1469}
1470
1471uint16_t rtnl_link_bridge_str2hwmode(const char *name)
1472{
1473 return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
1474}
1475
1476/** @} */
1477
1478/**
1479 * Enable the ability to set vlan info
1480 * @arg link Link object of type bridge
1481 *
1482 * @return 0 on success or negative error code
1483 * @return -NLE_OPNOTSUP Link is not a bridge
1484 */
1486{
1487 struct bridge_data *bd = bridge_data(link);
1488
1489 IS_BRIDGE_LINK_ASSERT(link);
1490
1491 bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
1492
1493 return 0;
1494}
1495
1496/**
1497 * @name Quality of Service
1498 * @{
1499 */
1500
1501/**
1502 * Set port vlan membership range
1503 * @arg link Link object of type bridge
1504 * @arg start Start of membership range.
1505 * @arg end End of membership range.
1506 * @arg untagged Set membership range to be untagged.
1507 *
1508 * This will set the vlan membership range for a bridge port.
1509 * This will unset the untagged membership if untagged is false.
1510 * Supported range is 1-4094
1511 *
1512 * @return 0 on success or negative error code
1513 * @return -NLE_NOATTR if port vlan attribute not present
1514 * @return -NLE_OPNOTSUP Link is not a bridge
1515 * @return -NLE_INVAL range is not in supported range.
1516 */
1517int rtnl_link_bridge_set_port_vlan_map_range (struct rtnl_link *link, uint16_t start, uint16_t end, int untagged)
1518{
1519 struct rtnl_link_bridge_vlan * vinfo;
1520
1521 IS_BRIDGE_LINK_ASSERT(link);
1522
1523 vinfo = rtnl_link_bridge_get_port_vlan(link);
1524
1525 if (!vinfo)
1526 return -NLE_NOATTR;
1527
1528 if (start == 0 || start > end || end >= VLAN_VID_MASK)
1529 return -NLE_INVAL;
1530
1531 for (uint16_t i = start; i <= end; i++)
1532 {
1533 set_bit(i,vinfo->vlan_bitmap);
1534 if (untagged) {
1535 set_bit(i,vinfo->untagged_bitmap);
1536 } else {
1537 unset_bit(i,vinfo->untagged_bitmap);
1538 }
1539 }
1540 return 0;
1541}
1542
1543/**
1544 * Unset port vlan membership range
1545 * @arg link Link object of type bridge
1546 * @arg start Start of membership range.
1547 * @arg end End of membership range.
1548 *
1549 * This will unset the vlan membership range for a bridge port
1550 * for both tagged and untagged membership.
1551 * Supported range is 1-4094
1552 *
1553 * @return 0 on success or negative error code
1554 * @return -NLE_NOATTR if port vlan attribute not present
1555 * @return -NLE_OPNOTSUP Link is not a bridge
1556 * @return -NLE_INVAL range is not in supported range.
1557 */
1558int rtnl_link_bridge_unset_port_vlan_map_range (struct rtnl_link *link, uint16_t start, uint16_t end)
1559{
1560 struct rtnl_link_bridge_vlan * vinfo;
1561
1562 IS_BRIDGE_LINK_ASSERT(link);
1563
1564 vinfo = rtnl_link_bridge_get_port_vlan(link);
1565
1566 if (!vinfo)
1567 return -NLE_NOATTR;
1568
1569 if (start == 0 || start > end || end >= VLAN_VID_MASK)
1570 return -NLE_INVAL;
1571
1572 for (uint16_t i = start; i <= end; i++)
1573 {
1574 unset_bit(i,vinfo->vlan_bitmap);
1575 unset_bit(i,vinfo->untagged_bitmap);
1576 }
1577 return 0;
1578}
1579
1580/**
1581 * Set port primary vlan id
1582 * @arg link Link object of type bridge
1583 * @arg pvid PVID to set.
1584 * @arg untagged Set vlan id to be untagged.
1585 *
1586 * This will set the primary vlan id for a bridge port.
1587 * Supported range is 0-4094, Setting pvid to 0 will unset it.
1588 * You will most likely want to set/unset pvid in the vlan map.
1589 * @see rtnl_link_bridge_set_port_vlan_map_range()
1590 * @see rtnl_link_bridge_unset_port_vlan_map_range()
1591 *
1592 * @return 0 on success or negative error code
1593 * @return -NLE_NOATTR if port vlan attribute not present
1594 * @return -NLE_OPNOTSUP Link is not a bridge
1595 * @return -NLE_INVAL PVID is above supported range.
1596 */
1597int rtnl_link_bridge_set_port_vlan_pvid (struct rtnl_link *link, uint16_t pvid)
1598{
1599 struct rtnl_link_bridge_vlan * vinfo;
1600
1601 IS_BRIDGE_LINK_ASSERT(link);
1602
1603 vinfo = rtnl_link_bridge_get_port_vlan(link);
1604
1605 if (!vinfo)
1606 return -NLE_NOATTR;
1607
1608 if (pvid >= VLAN_VID_MASK)
1609 return -NLE_INVAL;
1610
1611 vinfo->pvid = pvid;
1612
1613 return 0;
1614}
1615
1616/** @} */
1617
1618int rtnl_link_bridge_pvid(struct rtnl_link *link)
1619{
1620 struct bridge_data *bd;
1621
1622 IS_BRIDGE_LINK_ASSERT(link);
1623
1624 bd = link->l_af_data[AF_BRIDGE];
1625 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
1626 return (int) bd->vlan_info.pvid;
1627
1628 return -EINVAL;
1629}
1630
1631int rtnl_link_bridge_has_vlan(struct rtnl_link *link)
1632{
1633 struct bridge_data *bd;
1634 int i;
1635
1636 IS_BRIDGE_LINK_ASSERT(link);
1637
1638 bd = link->l_af_data[AF_BRIDGE];
1639 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
1640 if (bd->vlan_info.pvid)
1641 return 1;
1642
1643 for (i = 0; i < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; ++i) {
1644 if (bd->vlan_info.vlan_bitmap[i] ||
1645 bd->vlan_info.untagged_bitmap[i])
1646 return 1;
1647 }
1648 }
1649 return 0;
1650}
1651
1652struct rtnl_link_bridge_vlan *rtnl_link_bridge_get_port_vlan(struct rtnl_link *link)
1653{
1654 struct bridge_data *data;
1655
1656 if (!rtnl_link_is_bridge(link))
1657 return NULL;
1658
1659 data = link->l_af_data[AF_BRIDGE];
1660 if (data && (data->ce_mask & BRIDGE_ATTR_PORT_VLAN))
1661 return &data->vlan_info;
1662
1663 return NULL;
1664}
1665
1666/**
1667 * Set the Multiple Spanning Tree (MST) port state for a given MST instance
1668 * @arg link Link object of type bridge
1669 * @arg instance MST instance number
1670 * @arg state Port state to set (BR_STATE_*)
1671 *
1672 * @return 0 on success or a negative error code
1673 * @return -NLE_INVAL link is NULL
1674 * @return -NLE_OPNOTSUP Link is not a bridge
1675 * @return -NLE_NOMEM Memory allocation failed
1676 */
1678 uint16_t instance, uint8_t state)
1679{
1680 struct bridge_data *bd;
1681 struct mst_state_entry *existing_entry;
1682 struct mst_state_entry *new_entry;
1683
1684 if (link == NULL)
1685 return -NLE_INVAL;
1686
1687 IS_BRIDGE_LINK_ASSERT(link);
1688
1689 bd = bridge_data(link);
1690 if (bd == NULL)
1691 return -NLE_OPNOTSUPP;
1692
1693 existing_entry = find_mst_state_entry(bd, instance);
1694
1695 if (existing_entry != NULL) {
1696 existing_entry->state = state;
1697 return 0;
1698 }
1699
1700 new_entry = mst_state_entry_create(instance, state);
1701 if (new_entry == NULL)
1702 return -NLE_NOMEM;
1703
1704 nl_list_add_tail(&new_entry->list_node, &bd->mst_list);
1705 bd->ce_mask |= BRIDGE_ATTR_MST;
1706
1707 return 0;
1708}
1709
1710/**
1711 * Get the Multiple Spanning Tree (MST) port state for a given MST instance
1712 * @arg link Link object of type bridge
1713 * @arg instance MST instance number
1714 *
1715 * @return The state (BR_STATE_*) on success, or a negative error code
1716 * @return -NLE_INVAL link is NULL
1717 * @return -NLE_OPNOTSUP Link is not a bridge
1718 * @return -NLE_OBJ_NOTFOUND MST instance not found
1719 */
1721 uint16_t instance)
1722{
1723 struct bridge_data *bd;
1724 struct mst_state_entry *entry;
1725
1726 if (link == NULL)
1727 return -NLE_INVAL;
1728
1729 IS_BRIDGE_LINK_ASSERT(link);
1730
1731 bd = bridge_data(link);
1732 if (bd == NULL)
1733 return -NLE_OPNOTSUPP;
1734
1735 entry = find_mst_state_entry(bd, instance);
1736
1737 if (entry == NULL)
1738 return -NLE_OBJ_NOTFOUND;
1739
1740 return entry->state;
1741}
1742
1743/**
1744 * Delete the Multiple Spanning Tree (MST) port state for a given MST instance
1745 * @arg link Link object of type bridge
1746 * @arg instance MST instance number
1747 *
1748 * @return 0 on success or a negative error code
1749 * @return -NLE_INVAL link is NULL
1750 * @return -NLE_OPNOTSUP Link is not a bridge
1751 * @return -NLE_OBJ_NOTFOUND MST instance not found
1752 */
1754 uint16_t instance)
1755{
1756 struct bridge_data *bd;
1757 struct mst_state_entry *entry;
1758
1759 if (link == NULL)
1760 return -NLE_INVAL;
1761
1762 IS_BRIDGE_LINK_ASSERT(link);
1763
1764 bd = bridge_data(link);
1765 if (bd == NULL)
1766 return -NLE_OPNOTSUPP;
1767
1768 entry = find_mst_state_entry(bd, instance);
1769
1770 if (entry == NULL)
1771 return -NLE_OBJ_NOTFOUND;
1772
1773 mst_state_entry_del(entry);
1774
1775 if (nl_list_empty(&bd->mst_list))
1776 bd->ce_mask &= ~BRIDGE_ATTR_MST;
1777
1778 return 0;
1779}
1780
1781/**
1782 * Delete all Multiple Spanning Tree (MST) port state information
1783 * @arg link Link object of type bridge
1784 *
1785 * @return 0 on success or a negative error code
1786 * @return -NLE_INVAL link is NULL
1787 * @return -NLE_OPNOTSUP Link is not a bridge
1788 */
1790{
1791 struct bridge_data *bd;
1792
1793 if (link == NULL)
1794 return -NLE_INVAL;
1795
1796 IS_BRIDGE_LINK_ASSERT(link);
1797
1798 bd = bridge_data(link);
1799 if (bd == NULL)
1800 return -NLE_OPNOTSUPP;
1801
1802 mst_list_clear(&bd->mst_list);
1803 bd->ce_mask &= ~BRIDGE_ATTR_MST;
1804
1805 return 0;
1806}
1807
1808/**
1809 * Iterate over all Multiple Spanning Tree (MST) port state entries
1810 * @arg link Link object of type bridge
1811 * @arg cb Callback function
1812 * @arg arg User provided data argument to pass to the callback
1813 * function
1814 *
1815 * The callback function is called for each MST entry. It is passed the MST
1816 * instance ID, state (BR_STATE_*), and an optional user provided data argument.
1817 * MST entries should not be added or removed by the callback function.
1818 *
1819 * @return 0 on success or a negative error code
1820 * @return -NLE_INVAL link or cb is NULL
1821 * @return -NLE_OPNOTSUP Link is not a bridge
1822 */
1824 struct rtnl_link *link,
1825 void (*cb)(uint16_t instance, uint8_t state, void *arg), void *arg)
1826{
1827 struct bridge_data *bd;
1828 struct mst_state_entry *entry;
1829
1830 if (link == NULL || cb == NULL)
1831 return -NLE_INVAL;
1832
1833 IS_BRIDGE_LINK_ASSERT(link);
1834
1835 bd = bridge_data(link);
1836 if (bd == NULL)
1837 return -NLE_OPNOTSUPP;
1838
1839 nl_list_for_each_entry(entry, &bd->mst_list, list_node) {
1840 cb(entry->msti, entry->state, arg);
1841 }
1842
1843 return 0;
1844}
1845
1846static struct rtnl_link_af_ops bridge_ops = {
1847 .ao_family = AF_BRIDGE,
1848 .ao_alloc = &bridge_alloc,
1849 .ao_clone = &bridge_clone,
1850 .ao_free = &bridge_free,
1851 .ao_parse_protinfo = &bridge_parse_protinfo,
1852 .ao_dump[NL_DUMP_DETAILS] = &bridge_dump_details,
1853 .ao_compare = &bridge_compare,
1854 .ao_parse_af_full = &bridge_parse_af_full,
1855 .ao_get_af = &bridge_get_af,
1856 .ao_fill_af = &bridge_fill_af,
1857 .ao_fill_pi = &bridge_fill_pi,
1858 .ao_fill_pi_flags = NLA_F_NESTED,
1859 .ao_override_rtm = &bridge_override_rtm,
1860 .ao_fill_af_no_nest = 1,
1861};
1862
1863static void _nl_init bridge_init(void)
1864{
1865 rtnl_link_af_register(&bridge_ops);
1866}
1867
1868static void _nl_exit bridge_exit(void)
1869{
1870 rtnl_link_af_unregister(&bridge_ops);
1871}
1872
1873/** @} */
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition attr.c:714
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition attr.c:664
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
Definition attr.h:219
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition attr.h:201
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:1113
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
Definition attr.h:166
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition attr.h:237
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition attr.c:614
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition attr.c:974
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:1101
void nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr)
Cancel the addition of a nested attribute.
Definition attr.c:1066
#define nla_for_each_nested(pos, nla, rem)
Iterate over a stream of nested attributes.
Definition attr.h:331
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition attr.c:130
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition attr.c:1037
@ 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_mst_port_state(struct rtnl_link *link, uint16_t instance, uint8_t state)
Set the Multiple Spanning Tree (MST) port state for a given MST instance.
Definition bridge.c:1677
int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
Set Spanning Tree Protocol (STP) path cost.
Definition bridge.c:1161
int rtnl_link_bridge_get_port_state(struct rtnl_link *link)
Get Spanning Tree Protocol (STP) port state.
Definition bridge.c:1102
int rtnl_link_bridge_get_mst_port_state(struct rtnl_link *link, uint16_t instance)
Get the Multiple Spanning Tree (MST) port state for a given MST instance.
Definition bridge.c:1720
int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
Set hardware mode.
Definition bridge.c:1375
int rtnl_link_bridge_has_ext_info(struct rtnl_link *link)
Check if bridge has extended information.
Definition bridge.c:1049
int rtnl_link_bridge_set_master(struct rtnl_link *link)
Set link change type to master.
Definition bridge.c:1319
int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
Create a new kernel bridge device.
Definition bridge.c:1007
int rtnl_link_bridge_set_port_vlan_map_range(struct rtnl_link *link, uint16_t start, uint16_t end, int untagged)
Set port vlan membership range.
Definition bridge.c:1517
int rtnl_link_is_bridge(struct rtnl_link *link)
Check if a link is a bridge.
Definition bridge.c:1030
int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
Set Spanning Tree Protocol (STP) port state.
Definition bridge.c:1078
int rtnl_link_bridge_foreach_mst_entry(struct rtnl_link *link, void(*cb)(uint16_t instance, uint8_t state, void *arg), void *arg)
Iterate over all Multiple Spanning Tree (MST) port state entries.
Definition bridge.c:1823
int rtnl_link_bridge_enable_vlan(struct rtnl_link *link)
Enable the ability to set vlan info.
Definition bridge.c:1485
int rtnl_link_bridge_del_mst_port_state(struct rtnl_link *link, uint16_t instance)
Delete the Multiple Spanning Tree (MST) port state for a given MST instance.
Definition bridge.c:1753
int rtnl_link_bridge_set_self(struct rtnl_link *link)
Set link change type to self.
Definition bridge.c:1296
int rtnl_link_bridge_set_port_vlan_pvid(struct rtnl_link *link, uint16_t pvid)
Set port primary vlan id.
Definition bridge.c:1597
struct rtnl_link * rtnl_link_bridge_alloc(void)
Allocate link object of type bridge.
Definition bridge.c:981
int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
Get hardware mode.
Definition bridge.c:1342
int rtnl_link_bridge_clear_mst_port_state_info(struct rtnl_link *link)
Delete all Multiple Spanning Tree (MST) port state information.
Definition bridge.c:1789
int rtnl_link_bridge_get_flags(struct rtnl_link *link)
Get flags.
Definition bridge.c:1276
int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
Get Spanning Tree Protocol (STP) path cost.
Definition bridge.c:1184
int rtnl_link_bridge_get_priority(struct rtnl_link *link)
Get priority.
Definition bridge.c:1142
int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
Unset flags.
Definition bridge.c:1209
int rtnl_link_bridge_unset_port_vlan_map_range(struct rtnl_link *link, uint16_t start, uint16_t end)
Unset port vlan membership range.
Definition bridge.c:1558
int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
Set priority.
Definition bridge.c:1121
int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
Set flags.
Definition bridge.c:1253
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition utils.c:1015
@ 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:66
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition attr.h:68