net: bridge: mst: Support setting and reporting MST port states
Make it possible to change the port state in a given MSTI by extending
the bridge port netlink interface (RTM_SETLINK on PF_BRIDGE).The
proposed iproute2 interface would be:
bridge mst set dev <PORT> msti <MSTI> state <STATE>
Current states in all applicable MSTIs can also be dumped via a
corresponding RTM_GETLINK. The proposed iproute interface looks like
this:
$ bridge mst
port msti
vb1 0
state forwarding
100
state disabled
vb2 0
state forwarding
100
state forwarding
The preexisting per-VLAN states are still valid in the MST
mode (although they are read-only), and can be queried as usual if one
is interested in knowing a particular VLAN's state without having to
care about the VID to MSTI mapping (in this example VLAN 20 and 30 are
bound to MSTI 100):
$ bridge -d vlan
port vlan-id
vb1 10
state forwarding mcast_router 1
20
state disabled mcast_router 1
30
state disabled mcast_router 1
40
state forwarding mcast_router 1
vb2 10
state forwarding mcast_router 1
20
state forwarding mcast_router 1
30
state forwarding mcast_router 1
40
state forwarding mcast_router 1
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
8c678d6056
commit
122c29486e
@@ -127,3 +127,129 @@ int br_mst_set_enabled(struct net_bridge *br, bool on,
|
||||
br_opt_toggle(br, BROPT_MST_ENABLED, on);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t br_mst_info_size(const struct net_bridge_vlan_group *vg)
|
||||
{
|
||||
DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
|
||||
const struct net_bridge_vlan *v;
|
||||
size_t sz;
|
||||
|
||||
/* IFLA_BRIDGE_MST */
|
||||
sz = nla_total_size(0);
|
||||
|
||||
list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
|
||||
if (test_bit(v->brvlan->msti, seen))
|
||||
continue;
|
||||
|
||||
/* IFLA_BRIDGE_MST_ENTRY */
|
||||
sz += nla_total_size(0) +
|
||||
/* IFLA_BRIDGE_MST_ENTRY_MSTI */
|
||||
nla_total_size(sizeof(u16)) +
|
||||
/* IFLA_BRIDGE_MST_ENTRY_STATE */
|
||||
nla_total_size(sizeof(u8));
|
||||
|
||||
__set_bit(v->brvlan->msti, seen);
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
int br_mst_fill_info(struct sk_buff *skb,
|
||||
const struct net_bridge_vlan_group *vg)
|
||||
{
|
||||
DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
|
||||
const struct net_bridge_vlan *v;
|
||||
struct nlattr *nest;
|
||||
int err = 0;
|
||||
|
||||
list_for_each_entry(v, &vg->vlan_list, vlist) {
|
||||
if (test_bit(v->brvlan->msti, seen))
|
||||
continue;
|
||||
|
||||
nest = nla_nest_start_noflag(skb, IFLA_BRIDGE_MST_ENTRY);
|
||||
if (!nest ||
|
||||
nla_put_u16(skb, IFLA_BRIDGE_MST_ENTRY_MSTI, v->brvlan->msti) ||
|
||||
nla_put_u8(skb, IFLA_BRIDGE_MST_ENTRY_STATE, v->state)) {
|
||||
err = -EMSGSIZE;
|
||||
break;
|
||||
}
|
||||
nla_nest_end(skb, nest);
|
||||
|
||||
__set_bit(v->brvlan->msti, seen);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct nla_policy br_mst_nl_policy[IFLA_BRIDGE_MST_ENTRY_MAX + 1] = {
|
||||
[IFLA_BRIDGE_MST_ENTRY_MSTI] = NLA_POLICY_RANGE(NLA_U16,
|
||||
1, /* 0 reserved for CST */
|
||||
VLAN_N_VID - 1),
|
||||
[IFLA_BRIDGE_MST_ENTRY_STATE] = NLA_POLICY_RANGE(NLA_U8,
|
||||
BR_STATE_DISABLED,
|
||||
BR_STATE_BLOCKING),
|
||||
};
|
||||
|
||||
static int br_mst_process_one(struct net_bridge_port *p,
|
||||
const struct nlattr *attr,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nlattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
|
||||
u16 msti;
|
||||
u8 state;
|
||||
int err;
|
||||
|
||||
err = nla_parse_nested(tb, IFLA_BRIDGE_MST_ENTRY_MAX, attr,
|
||||
br_mst_nl_policy, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!tb[IFLA_BRIDGE_MST_ENTRY_MSTI]) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "MSTI not specified");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!tb[IFLA_BRIDGE_MST_ENTRY_STATE]) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "State not specified");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msti = nla_get_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
|
||||
state = nla_get_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
|
||||
|
||||
return br_mst_set_state(p, msti, state, extack);
|
||||
}
|
||||
|
||||
int br_mst_process(struct net_bridge_port *p, const struct nlattr *mst_attr,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nlattr *attr;
|
||||
int err, msts = 0;
|
||||
int rem;
|
||||
|
||||
if (!br_opt_get(p->br, BROPT_MST_ENABLED)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Can't modify MST state when MST is disabled");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
nla_for_each_nested(attr, mst_attr, rem) {
|
||||
switch (nla_type(attr)) {
|
||||
case IFLA_BRIDGE_MST_ENTRY:
|
||||
err = br_mst_process_one(p, attr, extack);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
msts++;
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!msts) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Found no MST entries to process");
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user