14#include "nl-default.h"
16#include <linux/if_bridge.h>
18#include <netlink/netlink.h>
19#include <netlink/attr.h>
20#include <netlink/route/rtnl.h>
21#include <netlink/route/link/bridge.h>
25#include "nl-priv-dynamic-core/nl-core.h"
27#define VLAN_VID_MASK 0x0fff
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)
38#define PRIV_FLAG_NEW_ATTRS (1 << 0)
49 uint32_t b_flags_mask;
54static void set_bit(
unsigned nr, uint32_t *addr)
56 if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
57 addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
60static int find_next_bit(
int i, uint32_t x)
69 return __builtin_ffs(x);
72 j = __builtin_ffs(x >> i);
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; \
84static inline struct bridge_data *bridge_data(
struct rtnl_link *link)
89static void *bridge_alloc(
struct rtnl_link *link)
91 return calloc(1,
sizeof(
struct bridge_data));
94static void *bridge_clone(
struct rtnl_link *link,
void *data)
96 struct bridge_data *bd;
98 if ((bd = bridge_alloc(link)))
99 memcpy(bd, data,
sizeof(*bd));
104static void bridge_free(
struct rtnl_link *link,
void *data)
109static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = {
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 },
122static void check_flag(
struct rtnl_link *link,
struct nlattr *attrs[],
129static int bridge_parse_protinfo(
struct rtnl_link *link,
struct nlattr *attr,
132 struct bridge_data *bd = data;
133 struct nlattr *br_attrs[IFLA_BRPORT_MAX+1];
142 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
148 br_attrs_policy)) < 0)
151 bd->b_priv_flags |= PRIV_FLAG_NEW_ATTRS;
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;
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;
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;
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);
181static int bridge_parse_af_full(
struct rtnl_link *link,
struct nlattr *attr_full,
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;
194 if (
nla_type(attr) == IFLA_BRIDGE_MODE) {
196 bd->ce_mask |= BRIDGE_ATTR_HWMODE;
198 }
else if (
nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
201 if (
nla_len(attr) !=
sizeof(
struct bridge_vlan_info))
205 if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
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);
215 if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) {
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");
222 vid_range_start = vinfo->vid;
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;
229 if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
230 set_bit(vid_range_start, bd->vlan_info.untagged_bitmap);
232 set_bit(vid_range_start, bd->vlan_info.vlan_bitmap);
233 bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
236 vid_range_flags = -1;
242static int bridge_fill_af(
struct rtnl_link *link,
struct nl_msg *msg,
245 struct bridge_data *bd = data;
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);
250 if (bd->ce_mask & BRIDGE_ATTR_HWMODE)
259static int bridge_fill_pi(
struct rtnl_link *link,
struct nl_msg *msg,
262 struct bridge_data *bd = data;
264 if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
265 if (bd->b_flags_mask & RTNL_BRIDGE_BPDU_GUARD) {
267 bd->b_flags & RTNL_BRIDGE_BPDU_GUARD);
269 if (bd->b_flags_mask & RTNL_BRIDGE_HAIRPIN_MODE) {
271 bd->b_flags & RTNL_BRIDGE_HAIRPIN_MODE);
273 if (bd->b_flags_mask & RTNL_BRIDGE_FAST_LEAVE) {
275 bd->b_flags & RTNL_BRIDGE_FAST_LEAVE);
277 if (bd->b_flags_mask & RTNL_BRIDGE_ROOT_BLOCK) {
279 bd->b_flags & RTNL_BRIDGE_ROOT_BLOCK);
281 if (bd->b_flags_mask & RTNL_BRIDGE_UNICAST_FLOOD) {
283 bd->b_flags & RTNL_BRIDGE_UNICAST_FLOOD);
285 if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING) {
287 bd->b_flags & RTNL_BRIDGE_LEARNING);
289 if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING_SYNC) {
291 bd->b_flags & RTNL_BRIDGE_LEARNING_SYNC);
295 if (bd->ce_mask & BRIDGE_ATTR_COST)
298 if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
299 NLA_PUT_U16(msg, IFLA_BRPORT_PRIORITY, bd->b_priority);
301 if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
302 NLA_PUT_U8(msg, IFLA_BRPORT_STATE, bd->b_port_state);
310static int bridge_override_rtm(
struct rtnl_link *link) {
311 struct bridge_data *bd;
316 bd = bridge_data(link);
318 if (bd->ce_mask & BRIDGE_ATTR_FLAGS)
324static int bridge_get_af(
struct nl_msg *msg, uint32_t *ext_filter_mask)
326 *ext_filter_mask |= RTEXT_FILTER_BRVLAN;
330static void dump_bitmap(
struct nl_dump_params *p,
const uint32_t *b)
333 int start = -1, prev = -1;
336 for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
344 j = find_next_bit(i, a);
347 if (start < 0 && prev < 0) {
348 start = prev = j - 1 + base_bit;
352 if (j - 2 + base_bit == prev) {
361 if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
372 start = prev = j - 1 + base_bit;
384 struct bridge_data *bd)
386 nl_dump(p,
"pvid %u", bd->vlan_info.pvid);
389 dump_bitmap(p, bd->vlan_info.vlan_bitmap);
391 nl_dump(p,
" untagged vlans:");
392 dump_bitmap(p, bd->vlan_info.untagged_bitmap);
395static void bridge_dump_details(
struct rtnl_link *link,
398 struct bridge_data *bd = data;
400 nl_dump_line(p,
" bridge: ");
402 if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
403 nl_dump(p,
"port-state %u ", bd->b_port_state);
405 if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
406 nl_dump(p,
"prio %u ", bd->b_priority);
408 if (bd->ce_mask & BRIDGE_ATTR_COST)
409 nl_dump(p,
"cost %u ", bd->b_cost);
411 if (bd->ce_mask & BRIDGE_ATTR_HWMODE) {
414 rtnl_link_bridge_hwmode2str(bd->b_hwmode, hbuf,
sizeof(hbuf));
418 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
419 rtnl_link_bridge_dump_vlans(p, bd);
421 if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
424 rtnl_link_bridge_flags2str(bd->b_flags & bd->b_flags_mask,
433 int family, uint32_t attrs,
int flags)
435 struct bridge_data *a = bridge_data(_a);
436 struct bridge_data *b = bridge_data(_b);
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,
447 diff |= _DIFF(BRIDGE_ATTR_HWMODE, a->b_hwmode != b->b_hwmode);
448 diff |= _DIFF(BRIDGE_ATTR_SELF, a->b_self != b->b_self);
450 if (flags & LOOSE_COMPARISON)
451 diff |= _DIFF(BRIDGE_ATTR_FLAGS,
452 (a->b_flags ^ b->b_flags) & b->b_flags_mask);
454 diff |= _DIFF(BRIDGE_ATTR_FLAGS, a->b_flags != b->b_flags);
517 return link->l_family == AF_BRIDGE &&
518 link->l_af_ops == &bridge_ops;
536 struct bridge_data *bd;
541 bd = bridge_data(link);
542 return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS);
565 struct bridge_data *bd = bridge_data(link);
567 IS_BRIDGE_LINK_ASSERT(link);
569 if (state > BR_STATE_BLOCKING)
572 bd->b_port_state = state;
573 bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
589 struct bridge_data *bd = bridge_data(link);
591 IS_BRIDGE_LINK_ASSERT(link);
593 return bd->b_port_state;
608 struct bridge_data *bd = bridge_data(link);
610 IS_BRIDGE_LINK_ASSERT(link);
612 bd->b_priority = prio;
613 bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
629 struct bridge_data *bd = bridge_data(link);
631 IS_BRIDGE_LINK_ASSERT(link);
633 return bd->b_priority;
648 struct bridge_data *bd = bridge_data(link);
650 IS_BRIDGE_LINK_ASSERT(link);
653 bd->ce_mask |= BRIDGE_ATTR_COST;
671 struct bridge_data *bd = bridge_data(link);
673 IS_BRIDGE_LINK_ASSERT(link);
696 struct bridge_data *bd = bridge_data(link);
698 IS_BRIDGE_LINK_ASSERT(link);
700 bd->b_flags_mask |= flags;
701 bd->b_flags &= ~flags;
702 bd->ce_mask |= BRIDGE_ATTR_FLAGS;
729 struct bridge_data *bd = bridge_data(link);
731 IS_BRIDGE_LINK_ASSERT(link);
733 bd->b_flags_mask |= flags;
734 bd->b_flags |= flags;
735 bd->ce_mask |= BRIDGE_ATTR_FLAGS;
752 struct bridge_data *bd = bridge_data(link);
754 IS_BRIDGE_LINK_ASSERT(link);
772 struct bridge_data *bd = bridge_data(link);
774 IS_BRIDGE_LINK_ASSERT(link);
777 bd->ce_mask |= BRIDGE_ATTR_SELF;
795 struct bridge_data *bd = bridge_data(link);
797 IS_BRIDGE_LINK_ASSERT(link);
799 if (!(bd->ce_mask & BRIDGE_ATTR_HWMODE))
802 *hwmode = bd->b_hwmode;
829 struct bridge_data *bd = bridge_data(link);
831 if (hwmode > RTNL_BRIDGE_HWMODE_MAX)
837 bd->b_hwmode = hwmode;
838 bd->ce_mask |= BRIDGE_ATTR_HWMODE;
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),
859char *rtnl_link_bridge_flags2str(
int flags,
char *buf,
size_t len)
861 return __flags2str(flags, buf, len, bridge_flags, ARRAY_SIZE(bridge_flags));
864int rtnl_link_bridge_str2flags(
const char *name)
866 return __str2flags(name, bridge_flags, ARRAY_SIZE(bridge_flags));
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),
884char *rtnl_link_bridge_portstate2str(
int st,
char *buf,
size_t len)
886 return __type2str(st, buf, len, port_states, ARRAY_SIZE(port_states));
889int rtnl_link_bridge_str2portstate(
const char *name)
891 return __str2type(name, port_states, ARRAY_SIZE(port_states));
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),
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));
911uint16_t rtnl_link_bridge_str2hwmode(
const char *name)
913 return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
918int rtnl_link_bridge_pvid(
struct rtnl_link *link)
920 struct bridge_data *bd;
922 IS_BRIDGE_LINK_ASSERT(link);
924 bd = link->l_af_data[AF_BRIDGE];
925 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
926 return (
int) bd->vlan_info.pvid;
931int rtnl_link_bridge_has_vlan(
struct rtnl_link *link)
933 struct bridge_data *bd;
936 IS_BRIDGE_LINK_ASSERT(link);
938 bd = link->l_af_data[AF_BRIDGE];
939 if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
940 if (bd->vlan_info.pvid)
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])
954 struct bridge_data *data;
959 data = link->l_af_data[AF_BRIDGE];
960 if (data && (data->ce_mask & BRIDGE_ATTR_PORT_VLAN))
961 return &data->vlan_info;
968 .ao_alloc = &bridge_alloc,
969 .ao_clone = &bridge_clone,
970 .ao_free = &bridge_free,
971 .ao_parse_protinfo = &bridge_parse_protinfo,
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,
983static void _nl_init bridge_init(
void)
988static void _nl_exit bridge_exit(
void)
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
int nla_type(const struct nlattr *nla)
Return type of the attribute.
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
int nla_is_nested(const struct nlattr *attr)
Return true if attribute has NLA_F_NESTED flag set.
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
#define nla_for_each_nested(pos, nla, rem)
Iterate over a stream of nested attributes.
int nla_len(const struct nlattr *nla)
Return length of the payload .
int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
Set Spanning Tree Protocol (STP) path cost.
int rtnl_link_bridge_get_port_state(struct rtnl_link *link)
Get Spanning Tree Protocol (STP) port state.
int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
Set hardware mode.
int rtnl_link_bridge_has_ext_info(struct rtnl_link *link)
Check if bridge has extended information.
int rtnl_link_bridge_add(struct nl_sock *sk, const char *name)
Create a new kernel bridge device.
int rtnl_link_is_bridge(struct rtnl_link *link)
Check if a link is a bridge.
int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
Set Spanning Tree Protocol (STP) port state.
int rtnl_link_bridge_set_self(struct rtnl_link *link)
Set link change type to self.
struct rtnl_link * rtnl_link_bridge_alloc(void)
Allocate link object of type bridge.
int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
Get hardware mode.
int rtnl_link_bridge_get_flags(struct rtnl_link *link)
Get flags.
int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
Get Spanning Tree Protocol (STP) path cost.
int rtnl_link_bridge_get_priority(struct rtnl_link *link)
Get priority.
int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
Unset flags.
int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
Set priority.
int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
Set flags.
int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
Unregister operations for a link address family.
int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
Register operations for a link address family.
void * rtnl_link_af_data(const struct rtnl_link *link, const struct rtnl_link_af_ops *ops)
Return data buffer for link address family modules.
int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags)
Add virtual link.
struct rtnl_link * rtnl_link_alloc(void)
Allocate link object.
void rtnl_link_set_name(struct rtnl_link *link, const char *name)
Set name of link object.
void rtnl_link_put(struct rtnl_link *link)
Release a link object reference.
int rtnl_link_set_type(struct rtnl_link *link, const char *type)
Set type of link object.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Attribute validation policy.
uint16_t type
Type of attribute or NLA_UNSPEC.
Available operations to modules implementing a link address family.
const unsigned int ao_family
The address family this operations set implements.