RTNL_BRIDGE_LEARNING_SYNC = 0x0040,
};
+#define RTNL_BRIDGE_HWMODE_VEB BRIDGE_MODE_VEB
+#define RTNL_BRIDGE_HWMODE_VEPA BRIDGE_MODE_VEPA
+#define RTNL_BRIDGE_HWMODE_MAX BRIDGE_MODE_VEPA
+#define RTNL_BRIDGE_HWMODE_UNDEF BRIDGE_MODE_UNDEF
+
extern struct rtnl_link *rtnl_link_bridge_alloc(void);
extern int rtnl_link_is_bridge(struct rtnl_link *);
extern int rtnl_link_bridge_set_flags(struct rtnl_link *, unsigned int);
extern int rtnl_link_bridge_get_flags(struct rtnl_link *);
+extern int rtnl_link_bridge_set_self(struct rtnl_link *);
+
+extern int rtnl_link_bridge_get_hwmode(struct rtnl_link *, uint16_t *);
+extern int rtnl_link_bridge_set_hwmode(struct rtnl_link *, uint16_t);
+
extern char * rtnl_link_bridge_flags2str(int, char *, size_t);
extern int rtnl_link_bridge_str2flags(const char *);
extern char * rtnl_link_bridge_portstate2str(int, char *, size_t);
extern int rtnl_link_bridge_str2portstate(const char *);
+extern char * rtnl_link_bridge_hwmode2str(uint16_t, char *, size_t);
+extern uint16_t rtnl_link_bridge_str2hwmode(const char *);
+
extern int rtnl_link_bridge_add(struct nl_sock *sk, const char *name);
extern int rtnl_link_bridge_pvid(struct rtnl_link *link);
#define BRIDGE_ATTR_COST (1 << 2)
#define BRIDGE_ATTR_FLAGS (1 << 3)
#define BRIDGE_ATTR_PORT_VLAN (1 << 4)
+#define BRIDGE_ATTR_HWMODE (1 << 5)
+#define BRIDGE_ATTR_SELF (1 << 6)
#define PRIV_FLAG_NEW_ATTRS (1 << 0)
{
uint8_t b_port_state;
uint8_t b_priv_flags; /* internal flags */
+ uint16_t b_hwmode;
uint16_t b_priority;
+ uint16_t b_self; /* here for comparison reasons */
uint32_t b_cost;
uint32_t b_flags;
uint32_t b_flags_mask;
nla_for_each_nested(attr, attr_full, remaining) {
- if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
+ if (nla_type(attr) == IFLA_BRIDGE_MODE) {
+ bd->b_hwmode = nla_get_u16(attr);
+ bd->ce_mask |= BRIDGE_ATTR_HWMODE;
+ } else if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
continue;
if (nla_len(attr) != sizeof(struct bridge_vlan_info))
return 0;
}
+static int bridge_fill_af(struct rtnl_link *link, struct nl_msg *msg,
+ void *data)
+{
+ struct bridge_data *bd = data;
+
+ if ((bd->ce_mask & BRIDGE_ATTR_SELF)||(bd->ce_mask & BRIDGE_ATTR_HWMODE))
+ NLA_PUT_U16(msg, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
+
+ if (bd->ce_mask & BRIDGE_ATTR_HWMODE)
+ NLA_PUT_U16(msg, IFLA_BRIDGE_MODE, bd->b_hwmode);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
static int bridge_fill_pi(struct rtnl_link *link, struct nl_msg *msg,
void *data)
{
if (bd->ce_mask & BRIDGE_ATTR_COST)
nl_dump(p, "cost %u ", bd->b_cost);
+ if (bd->ce_mask & BRIDGE_ATTR_HWMODE) {
+ char hbuf[32];
+
+ rtnl_link_bridge_hwmode2str(bd->b_hwmode, hbuf, sizeof(hbuf));
+ nl_dump(p, "hwmode %s", hbuf);
+ }
+
if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
rtnl_link_bridge_dump_vlans(p, bd);
diff |= BRIDGE_DIFF(COST, a->b_cost != b->b_cost);
diff |= BRIDGE_DIFF(PORT_VLAN, memcmp(&a->vlan_info, &b->vlan_info,
sizeof(struct rtnl_link_bridge_vlan)));
+ diff |= BRIDGE_DIFF(HWMODE, a->b_hwmode != b->b_hwmode);
+ diff |= BRIDGE_DIFF(SELF, a->b_self != b->b_self);
if (flags & LOOSE_COMPARISON)
diff |= BRIDGE_DIFF(FLAGS,
return bd->b_flags;
}
+/**
+ * Set link change type to self
+ * @arg link Link Object of type bridge
+ *
+ * This will set the bridge change flag to self, meaning that changes to
+ * be applied with this link object will be applied directly to the physical
+ * device in a bridge instead of the virtual device.
+ *
+ * @return 0 on success or negative error code
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ */
+int rtnl_link_bridge_set_self(struct rtnl_link *link) {
+ struct bridge_data *bd = bridge_data(link);
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ bd->b_self |= 1;
+ bd->ce_mask |= BRIDGE_ATTR_SELF;
+
+ return 0;
+}
+
+/**
+ * Get hardware mode
+ * @arg link Link object of type bridge
+ *
+ * @see rtnl_link_bridge_set_hwmode()
+ *
+ * @return 1 and set hwmode if hardware mode is present
+ * @return 0 if hardware mode is not present
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ */
+int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
+{
+ struct bridge_data *bd = bridge_data(link);
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ if (bd->ce_mask & BRIDGE_ATTR_HWMODE) {
+ *hwmode = bd->b_hwmode;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/**
+ * Set hardware mode
+ * @arg link Link object of type bridge
+ * @arg hwmode Hardware mode to set on link
+ *
+ * This will set the hardware mode of a link when it supports hardware
+ * offloads for bridging.
+ * @see rtnl_link_bridge_get_hwmode()
+ *
+ * Valid modes are:
+ * - RTNL_BRIDGE_HWMODE_VEB
+ * - RTNL_BRIDGE_HWMODE_VEPA
+ *
+ * When setting hardware mode, the change type will be set to self.
+ * @see rtnl_link_bridge_set_self()
+ *
+ * @return 0 on success or negative error code
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ * @return -NLE_INVAL when specified hwmode is unsupported.
+ */
+int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
+{
+ int err;
+ struct bridge_data *bd = bridge_data(link);
+
+ if (hwmode > RTNL_BRIDGE_HWMODE_MAX)
+ return -NLE_INVAL;
+
+ if ((err = rtnl_link_bridge_set_self(link)) < 0)
+ return err;
+
+ bd->b_hwmode = hwmode;
+ bd->ce_mask |= BRIDGE_ATTR_HWMODE;
+
+ return 0;
+}
+
+
static const struct trans_tbl bridge_flags[] = {
__ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode),
__ADD(RTNL_BRIDGE_BPDU_GUARD, bpdu_guard),
/** @} */
+static const struct trans_tbl hw_modes[] = {
+ __ADD(RTNL_BRIDGE_HWMODE_VEB, veb),
+ __ADD(RTNL_BRIDGE_HWMODE_VEPA, vepa),
+ __ADD(RTNL_BRIDGE_HWMODE_UNDEF, undef),
+};
+
+/**
+ * @name Hardware Mode Translation
+ * @{
+ */
+
+char *rtnl_link_bridge_hwmode2str(uint16_t st, char *buf, size_t len) {
+ return __type2str(st, buf, len, hw_modes, ARRAY_SIZE(hw_modes));
+}
+
+uint16_t rtnl_link_bridge_str2hwmode(const char *name)
+{
+ return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
+}
+
+/** @} */
+
int rtnl_link_bridge_pvid(struct rtnl_link *link)
{
struct bridge_data *bd;
.ao_compare = &bridge_compare,
.ao_parse_af_full = &bridge_parse_af_full,
.ao_get_af = &bridge_get_af,
+ .ao_fill_af = &bridge_fill_af,
.ao_fill_pi = &bridge_fill_pi,
.ao_fill_pi_flags = NLA_F_NESTED,
.ao_override_rtm = 1,
+ .ao_fill_af_no_nest = 1,
};
static void __init bridge_init(void)