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

net: bridge: vlan: account for router port lists when notifying

When sending a global vlan notification we should account for the number
of router ports when allocating the skb, otherwise we might end up
losing notifications.

Fixes: dc002875 ("net: bridge: vlan: use br_rports_fill_info() to export mcast router ports")
Signed-off-by: default avatarNikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b92dace3
...@@ -37,6 +37,36 @@ br_ip6_rports_get_timer(struct net_bridge_mcast_port *pmctx, ...@@ -37,6 +37,36 @@ br_ip6_rports_get_timer(struct net_bridge_mcast_port *pmctx,
#endif #endif
} }
static size_t __br_rports_one_size(void)
{
return nla_total_size(sizeof(u32)) + /* MDBA_ROUTER_PORT */
nla_total_size(sizeof(u32)) + /* MDBA_ROUTER_PATTR_TIMER */
nla_total_size(sizeof(u8)) + /* MDBA_ROUTER_PATTR_TYPE */
nla_total_size(sizeof(u32)) + /* MDBA_ROUTER_PATTR_INET_TIMER */
nla_total_size(sizeof(u32)) + /* MDBA_ROUTER_PATTR_INET6_TIMER */
nla_total_size(sizeof(u32)); /* MDBA_ROUTER_PATTR_VID */
}
size_t br_rports_size(const struct net_bridge_mcast *brmctx)
{
struct net_bridge_mcast_port *pmctx;
size_t size = nla_total_size(0); /* MDBA_ROUTER */
rcu_read_lock();
hlist_for_each_entry_rcu(pmctx, &brmctx->ip4_mc_router_list,
ip4_rlist)
size += __br_rports_one_size();
#if IS_ENABLED(CONFIG_IPV6)
hlist_for_each_entry_rcu(pmctx, &brmctx->ip6_mc_router_list,
ip6_rlist)
size += __br_rports_one_size();
#endif
rcu_read_unlock();
return size;
}
int br_rports_fill_info(struct sk_buff *skb, int br_rports_fill_info(struct sk_buff *skb,
const struct net_bridge_mcast *brmctx) const struct net_bridge_mcast *brmctx)
{ {
......
...@@ -952,6 +952,7 @@ int br_multicast_dump_querier_state(struct sk_buff *skb, ...@@ -952,6 +952,7 @@ int br_multicast_dump_querier_state(struct sk_buff *skb,
const struct net_bridge_mcast *brmctx, const struct net_bridge_mcast *brmctx,
int nest_attr); int nest_attr);
size_t br_multicast_querier_state_size(void); size_t br_multicast_querier_state_size(void);
size_t br_rports_size(const struct net_bridge_mcast *brmctx);
static inline bool br_group_is_l2(const struct br_ip *group) static inline bool br_group_is_l2(const struct br_ip *group)
{ {
......
...@@ -362,7 +362,7 @@ bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 vid, u16 vid_range, ...@@ -362,7 +362,7 @@ bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 vid, u16 vid_range,
return false; return false;
} }
static size_t rtnl_vlan_global_opts_nlmsg_size(void) static size_t rtnl_vlan_global_opts_nlmsg_size(const struct net_bridge_vlan *v)
{ {
return NLMSG_ALIGN(sizeof(struct br_vlan_msg)) return NLMSG_ALIGN(sizeof(struct br_vlan_msg))
+ nla_total_size(0) /* BRIDGE_VLANDB_GLOBAL_OPTIONS */ + nla_total_size(0) /* BRIDGE_VLANDB_GLOBAL_OPTIONS */
...@@ -382,6 +382,8 @@ static size_t rtnl_vlan_global_opts_nlmsg_size(void) ...@@ -382,6 +382,8 @@ static size_t rtnl_vlan_global_opts_nlmsg_size(void)
+ nla_total_size(sizeof(u8)) /* BRIDGE_VLANDB_GOPTS_MCAST_QUERIER */ + nla_total_size(sizeof(u8)) /* BRIDGE_VLANDB_GOPTS_MCAST_QUERIER */
+ nla_total_size(sizeof(u8)) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER */ + nla_total_size(sizeof(u8)) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER */
+ br_multicast_querier_state_size() /* BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_STATE */ + br_multicast_querier_state_size() /* BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_STATE */
+ nla_total_size(0) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS */
+ br_rports_size(&v->br_mcast_ctx) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS */
#endif #endif
+ nla_total_size(sizeof(u16)); /* BRIDGE_VLANDB_GOPTS_RANGE */ + nla_total_size(sizeof(u16)); /* BRIDGE_VLANDB_GOPTS_RANGE */
} }
...@@ -398,7 +400,12 @@ static void br_vlan_global_opts_notify(const struct net_bridge *br, ...@@ -398,7 +400,12 @@ static void br_vlan_global_opts_notify(const struct net_bridge *br,
/* right now notifications are done only with rtnl held */ /* right now notifications are done only with rtnl held */
ASSERT_RTNL(); ASSERT_RTNL();
skb = nlmsg_new(rtnl_vlan_global_opts_nlmsg_size(), GFP_KERNEL); /* need to find the vlan due to flags/options */
v = br_vlan_find(br_vlan_group(br), vid);
if (!v)
return;
skb = nlmsg_new(rtnl_vlan_global_opts_nlmsg_size(v), GFP_KERNEL);
if (!skb) if (!skb)
goto out_err; goto out_err;
...@@ -411,11 +418,6 @@ static void br_vlan_global_opts_notify(const struct net_bridge *br, ...@@ -411,11 +418,6 @@ static void br_vlan_global_opts_notify(const struct net_bridge *br,
bvm->family = AF_BRIDGE; bvm->family = AF_BRIDGE;
bvm->ifindex = br->dev->ifindex; bvm->ifindex = br->dev->ifindex;
/* need to find the vlan due to flags/options */
v = br_vlan_find(br_vlan_group(br), vid);
if (!v)
goto out_kfree;
if (!br_vlan_global_opts_fill(skb, vid, vid_range, v)) if (!br_vlan_global_opts_fill(skb, vid, vid_range, v))
goto out_err; goto out_err;
...@@ -425,7 +427,6 @@ static void br_vlan_global_opts_notify(const struct net_bridge *br, ...@@ -425,7 +427,6 @@ static void br_vlan_global_opts_notify(const struct net_bridge *br,
out_err: out_err:
rtnl_set_sk_err(dev_net(br->dev), RTNLGRP_BRVLAN, err); rtnl_set_sk_err(dev_net(br->dev), RTNLGRP_BRVLAN, err);
out_kfree:
kfree_skb(skb); kfree_skb(skb);
} }
......
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