Skip to content

Commit

Permalink
bridge: netlink: add support for vlan_filtering attribute
Browse files Browse the repository at this point in the history
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: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Nikolay Aleksandrov authored and davem330 committed Aug 10, 2015
1 parent e72ee3e commit a785403
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 7 deletions.
1 change: 1 addition & 0 deletions include/uapi/linux/if_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ enum {
IFLA_BR_AGEING_TIME,
IFLA_BR_STP_STATE,
IFLA_BR_PRIORITY,
IFLA_BR_VLAN_FILTERING,
__IFLA_BR_MAX,
};

Expand Down
14 changes: 13 additions & 1 deletion net/bridge/br_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = {
[IFLA_BR_AGEING_TIME] = { .type = NLA_U32 },
[IFLA_BR_STP_STATE] = { .type = NLA_U32 },
[IFLA_BR_PRIORITY] = { .type = NLA_U16 },
[IFLA_BR_VLAN_FILTERING] = { .type = NLA_U8 },
};

static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
Expand Down Expand Up @@ -771,6 +772,14 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
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;
}

Expand All @@ -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_STP_STATE */
nla_total_size(sizeof(u16)) + /* IFLA_BR_PRIORITY */
nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_FILTERING */
0;
}

Expand All @@ -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 stp_enabled = br->stp_enabled;
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) ||
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_AGEING_TIME, ageing_time) ||
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 0;
Expand Down
7 changes: 7 additions & 0 deletions net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ int br_vlan_delete(struct net_bridge *br, u16 vid);
void br_vlan_flush(struct net_bridge *br);
bool br_vlan_find(struct net_bridge *br, u16 vid);
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_set_proto(struct net_bridge *br, unsigned long val);
int br_vlan_init(struct net_bridge *br);
Expand Down Expand Up @@ -771,6 +772,12 @@ static inline int br_vlan_enabled(struct net_bridge *br)
{
return 0;
}

static inline int __br_vlan_filter_toggle(struct net_bridge *br,
unsigned long val)
{
return -EOPNOTSUPP;
}
#endif

struct nf_br_ops {
Expand Down
18 changes: 12 additions & 6 deletions net/bridge/br_vlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,21 +468,27 @@ void br_recalculate_fwd_mask(struct net_bridge *br)
~(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)
goto unlock;
return 0;

br->vlan_enabled = val;
br_manage_promisc(br);
recalculate_group_addr(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();

return 0;
}

Expand Down

0 comments on commit a785403

Please sign in to comment.