bridge: mdb: notify on router port add and del
Send notifications on router port add and del/expire, re-use the already existing MDBA_ROUTER and send NEWMDB/DELMDB netlink notifications respectively. Signed-off-by: Satish Ashok <sashok@cumulusnetworks.com> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
597798e438
commit
949f1e39a6
3 changed files with 77 additions and 2 deletions
|
@ -247,6 +247,73 @@ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
|
||||||
__br_mdb_notify(dev, &entry, type);
|
__br_mdb_notify(dev, &entry, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nlmsg_populate_rtr_fill(struct sk_buff *skb,
|
||||||
|
struct net_device *dev,
|
||||||
|
int ifindex, u32 pid,
|
||||||
|
u32 seq, int type, unsigned int flags)
|
||||||
|
{
|
||||||
|
struct br_port_msg *bpm;
|
||||||
|
struct nlmsghdr *nlh;
|
||||||
|
struct nlattr *nest;
|
||||||
|
|
||||||
|
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), NLM_F_MULTI);
|
||||||
|
if (!nlh)
|
||||||
|
return -EMSGSIZE;
|
||||||
|
|
||||||
|
bpm = nlmsg_data(nlh);
|
||||||
|
memset(bpm, 0, sizeof(*bpm));
|
||||||
|
bpm->family = AF_BRIDGE;
|
||||||
|
bpm->ifindex = dev->ifindex;
|
||||||
|
nest = nla_nest_start(skb, MDBA_ROUTER);
|
||||||
|
if (!nest)
|
||||||
|
goto cancel;
|
||||||
|
|
||||||
|
if (nla_put_u32(skb, MDBA_ROUTER_PORT, ifindex))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
nla_nest_end(skb, nest);
|
||||||
|
nlmsg_end(skb, nlh);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
nla_nest_end(skb, nest);
|
||||||
|
cancel:
|
||||||
|
nlmsg_cancel(skb, nlh);
|
||||||
|
return -EMSGSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t rtnl_rtr_nlmsg_size(void)
|
||||||
|
{
|
||||||
|
return NLMSG_ALIGN(sizeof(struct br_port_msg))
|
||||||
|
+ nla_total_size(sizeof(__u32));
|
||||||
|
}
|
||||||
|
|
||||||
|
void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port,
|
||||||
|
int type)
|
||||||
|
{
|
||||||
|
struct net *net = dev_net(dev);
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int err = -ENOBUFS;
|
||||||
|
int ifindex;
|
||||||
|
|
||||||
|
ifindex = port ? port->dev->ifindex : 0;
|
||||||
|
skb = nlmsg_new(rtnl_rtr_nlmsg_size(), GFP_ATOMIC);
|
||||||
|
if (!skb)
|
||||||
|
goto errout;
|
||||||
|
|
||||||
|
err = nlmsg_populate_rtr_fill(skb, dev, ifindex, 0, 0, type, NTF_SELF);
|
||||||
|
if (err < 0) {
|
||||||
|
kfree_skb(skb);
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtnl_notify(skb, net, 0, RTNLGRP_MDB, NULL, GFP_ATOMIC);
|
||||||
|
return;
|
||||||
|
|
||||||
|
errout:
|
||||||
|
rtnl_set_sk_err(net, RTNLGRP_MDB, err);
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_valid_mdb_entry(struct br_mdb_entry *entry)
|
static bool is_valid_mdb_entry(struct br_mdb_entry *entry)
|
||||||
{
|
{
|
||||||
if (entry->ifindex == 0)
|
if (entry->ifindex == 0)
|
||||||
|
|
|
@ -766,6 +766,7 @@ static void br_multicast_router_expired(unsigned long data)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hlist_del_init_rcu(&port->rlist);
|
hlist_del_init_rcu(&port->rlist);
|
||||||
|
br_rtr_notify(br->dev, port, RTM_DELMDB);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock(&br->multicast_lock);
|
spin_unlock(&br->multicast_lock);
|
||||||
|
@ -977,8 +978,10 @@ void br_multicast_disable_port(struct net_bridge_port *port)
|
||||||
if (pg->state == MDB_TEMPORARY)
|
if (pg->state == MDB_TEMPORARY)
|
||||||
br_multicast_del_pg(br, pg);
|
br_multicast_del_pg(br, pg);
|
||||||
|
|
||||||
if (!hlist_unhashed(&port->rlist))
|
if (!hlist_unhashed(&port->rlist)) {
|
||||||
hlist_del_init_rcu(&port->rlist);
|
hlist_del_init_rcu(&port->rlist);
|
||||||
|
br_rtr_notify(br->dev, port, RTM_DELMDB);
|
||||||
|
}
|
||||||
del_timer(&port->multicast_router_timer);
|
del_timer(&port->multicast_router_timer);
|
||||||
del_timer(&port->ip4_own_query.timer);
|
del_timer(&port->ip4_own_query.timer);
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
@ -1216,6 +1219,7 @@ static void br_multicast_add_router(struct net_bridge *br,
|
||||||
hlist_add_behind_rcu(&port->rlist, slot);
|
hlist_add_behind_rcu(&port->rlist, slot);
|
||||||
else
|
else
|
||||||
hlist_add_head_rcu(&port->rlist, &br->router_list);
|
hlist_add_head_rcu(&port->rlist, &br->router_list);
|
||||||
|
br_rtr_notify(br->dev, port, RTM_NEWMDB);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void br_multicast_mark_router(struct net_bridge *br,
|
static void br_multicast_mark_router(struct net_bridge *br,
|
||||||
|
@ -1848,8 +1852,10 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
|
||||||
p->multicast_router = val;
|
p->multicast_router = val;
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
if (val < 2 && !hlist_unhashed(&p->rlist))
|
if (val < 2 && !hlist_unhashed(&p->rlist)) {
|
||||||
hlist_del_init_rcu(&p->rlist);
|
hlist_del_init_rcu(&p->rlist);
|
||||||
|
br_rtr_notify(br->dev, p, RTM_DELMDB);
|
||||||
|
}
|
||||||
|
|
||||||
if (val == 1)
|
if (val == 1)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -490,6 +490,8 @@ void br_mdb_init(void);
|
||||||
void br_mdb_uninit(void);
|
void br_mdb_uninit(void);
|
||||||
void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
|
void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
|
||||||
struct br_ip *group, int type, u8 state);
|
struct br_ip *group, int type, u8 state);
|
||||||
|
void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port,
|
||||||
|
int type);
|
||||||
|
|
||||||
#define mlock_dereference(X, br) \
|
#define mlock_dereference(X, br) \
|
||||||
rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
|
rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
|
||||||
|
|
Loading…
Add table
Reference in a new issue