Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 949f1e39 authored by Satish Ashok's avatar Satish Ashok Committed by David S. Miller
Browse files

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: default avatarSatish Ashok <sashok@cumulusnetworks.com>
Signed-off-by: default avatarNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 597798e4
Loading
Loading
Loading
Loading
+67 −0
Original line number Diff line number Diff line
@@ -247,6 +247,73 @@ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
	__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)
{
	if (entry->ifindex == 0)
+8 −2
Original line number Diff line number Diff line
@@ -766,6 +766,7 @@ static void br_multicast_router_expired(unsigned long data)
		goto out;

	hlist_del_init_rcu(&port->rlist);
	br_rtr_notify(br->dev, port, RTM_DELMDB);

out:
	spin_unlock(&br->multicast_lock);
@@ -977,8 +978,10 @@ void br_multicast_disable_port(struct net_bridge_port *port)
		if (pg->state == MDB_TEMPORARY)
			br_multicast_del_pg(br, pg);

	if (!hlist_unhashed(&port->rlist))
	if (!hlist_unhashed(&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->ip4_own_query.timer);
#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);
	else
		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,
@@ -1848,8 +1852,10 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
		p->multicast_router = val;
		err = 0;

		if (val < 2 && !hlist_unhashed(&p->rlist))
		if (val < 2 && !hlist_unhashed(&p->rlist)) {
			hlist_del_init_rcu(&p->rlist);
			br_rtr_notify(br->dev, p, RTM_DELMDB);
		}

		if (val == 1)
			break;
+2 −0
Original line number Diff line number Diff line
@@ -490,6 +490,8 @@ void br_mdb_init(void);
void br_mdb_uninit(void);
void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
		   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) \
	rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))