Commit a7854037 authored by Nikolay Aleksandrov's avatar Nikolay Aleksandrov Committed by David S. Miller

bridge: netlink: add support for vlan_filtering attribute

This patch adds the ability to toggle the vlan filtering support via
netlink. Since we're already running with rtnl in .changelink() we don't
need to take any additional locks.
Signed-off-by: default avatarNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e72ee3ed
...@@ -230,6 +230,7 @@ enum { ...@@ -230,6 +230,7 @@ enum {
IFLA_BR_AGEING_TIME, IFLA_BR_AGEING_TIME,
IFLA_BR_STP_STATE, IFLA_BR_STP_STATE,
IFLA_BR_PRIORITY, IFLA_BR_PRIORITY,
IFLA_BR_VLAN_FILTERING,
__IFLA_BR_MAX, __IFLA_BR_MAX,
}; };
......
...@@ -724,6 +724,7 @@ static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = { ...@@ -724,6 +724,7 @@ static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = {
[IFLA_BR_AGEING_TIME] = { .type = NLA_U32 }, [IFLA_BR_AGEING_TIME] = { .type = NLA_U32 },
[IFLA_BR_STP_STATE] = { .type = NLA_U32 }, [IFLA_BR_STP_STATE] = { .type = NLA_U32 },
[IFLA_BR_PRIORITY] = { .type = NLA_U16 }, [IFLA_BR_PRIORITY] = { .type = NLA_U16 },
[IFLA_BR_VLAN_FILTERING] = { .type = NLA_U8 },
}; };
static int br_changelink(struct net_device *brdev, struct nlattr *tb[], static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
...@@ -771,6 +772,14 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], ...@@ -771,6 +772,14 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
br_stp_set_bridge_priority(br, priority); br_stp_set_bridge_priority(br, priority);
} }
if (data[IFLA_BR_VLAN_FILTERING]) {
u8 vlan_filter = nla_get_u8(data[IFLA_BR_VLAN_FILTERING]);
err = __br_vlan_filter_toggle(br, vlan_filter);
if (err)
return err;
}
return 0; return 0;
} }
...@@ -782,6 +791,7 @@ static size_t br_get_size(const struct net_device *brdev) ...@@ -782,6 +791,7 @@ static size_t br_get_size(const struct net_device *brdev)
nla_total_size(sizeof(u32)) + /* IFLA_BR_AGEING_TIME */ nla_total_size(sizeof(u32)) + /* IFLA_BR_AGEING_TIME */
nla_total_size(sizeof(u32)) + /* IFLA_BR_STP_STATE */ nla_total_size(sizeof(u32)) + /* IFLA_BR_STP_STATE */
nla_total_size(sizeof(u16)) + /* IFLA_BR_PRIORITY */ nla_total_size(sizeof(u16)) + /* IFLA_BR_PRIORITY */
nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_FILTERING */
0; 0;
} }
...@@ -794,13 +804,15 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev) ...@@ -794,13 +804,15 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev)
u32 ageing_time = jiffies_to_clock_t(br->ageing_time); u32 ageing_time = jiffies_to_clock_t(br->ageing_time);
u32 stp_enabled = br->stp_enabled; u32 stp_enabled = br->stp_enabled;
u16 priority = (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]; u16 priority = (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1];
u8 vlan_enabled = br_vlan_enabled(br);
if (nla_put_u32(skb, IFLA_BR_FORWARD_DELAY, forward_delay) || if (nla_put_u32(skb, IFLA_BR_FORWARD_DELAY, forward_delay) ||
nla_put_u32(skb, IFLA_BR_HELLO_TIME, hello_time) || nla_put_u32(skb, IFLA_BR_HELLO_TIME, hello_time) ||
nla_put_u32(skb, IFLA_BR_MAX_AGE, age_time) || nla_put_u32(skb, IFLA_BR_MAX_AGE, age_time) ||
nla_put_u32(skb, IFLA_BR_AGEING_TIME, ageing_time) || nla_put_u32(skb, IFLA_BR_AGEING_TIME, ageing_time) ||
nla_put_u32(skb, IFLA_BR_STP_STATE, stp_enabled) || nla_put_u32(skb, IFLA_BR_STP_STATE, stp_enabled) ||
nla_put_u16(skb, IFLA_BR_PRIORITY, priority)) nla_put_u16(skb, IFLA_BR_PRIORITY, priority) ||
nla_put_u8(skb, IFLA_BR_VLAN_FILTERING, vlan_enabled))
return -EMSGSIZE; return -EMSGSIZE;
return 0; return 0;
......
...@@ -614,6 +614,7 @@ int br_vlan_delete(struct net_bridge *br, u16 vid); ...@@ -614,6 +614,7 @@ int br_vlan_delete(struct net_bridge *br, u16 vid);
void br_vlan_flush(struct net_bridge *br); void br_vlan_flush(struct net_bridge *br);
bool br_vlan_find(struct net_bridge *br, u16 vid); bool br_vlan_find(struct net_bridge *br, u16 vid);
void br_recalculate_fwd_mask(struct net_bridge *br); void br_recalculate_fwd_mask(struct net_bridge *br);
int __br_vlan_filter_toggle(struct net_bridge *br, unsigned long val);
int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val);
int br_vlan_set_proto(struct net_bridge *br, unsigned long val); int br_vlan_set_proto(struct net_bridge *br, unsigned long val);
int br_vlan_init(struct net_bridge *br); int br_vlan_init(struct net_bridge *br);
...@@ -771,6 +772,12 @@ static inline int br_vlan_enabled(struct net_bridge *br) ...@@ -771,6 +772,12 @@ static inline int br_vlan_enabled(struct net_bridge *br)
{ {
return 0; return 0;
} }
static inline int __br_vlan_filter_toggle(struct net_bridge *br,
unsigned long val)
{
return -EOPNOTSUPP;
}
#endif #endif
struct nf_br_ops { struct nf_br_ops {
......
...@@ -468,21 +468,27 @@ void br_recalculate_fwd_mask(struct net_bridge *br) ...@@ -468,21 +468,27 @@ void br_recalculate_fwd_mask(struct net_bridge *br)
~(1u << br->group_addr[5]); ~(1u << br->group_addr[5]);
} }
int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) int __br_vlan_filter_toggle(struct net_bridge *br, unsigned long val)
{ {
if (!rtnl_trylock())
return restart_syscall();
if (br->vlan_enabled == val) if (br->vlan_enabled == val)
goto unlock; return 0;
br->vlan_enabled = val; br->vlan_enabled = val;
br_manage_promisc(br); br_manage_promisc(br);
recalculate_group_addr(br); recalculate_group_addr(br);
br_recalculate_fwd_mask(br); br_recalculate_fwd_mask(br);
unlock: return 0;
}
int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val)
{
if (!rtnl_trylock())
return restart_syscall();
__br_vlan_filter_toggle(br, val);
rtnl_unlock(); rtnl_unlock();
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment