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

Commit a1b486ae authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bridge-mdb-entry-offload-flag'



Jiri Pirko says:

====================
bridge: mdb: flag offloaded mdb entries

This patchset extends uapi to let the user know if an mdb entry is offloaded.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d66bd905 9e8430f8
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -183,6 +183,8 @@ struct br_mdb_entry {
#define MDB_TEMPORARY 0
#define MDB_TEMPORARY 0
#define MDB_PERMANENT 1
#define MDB_PERMANENT 1
	__u8 state;
	__u8 state;
#define MDB_FLAGS_OFFLOAD	(1 << 0)
	__u8 flags;
	__u16 vid;
	__u16 vid;
	struct {
	struct {
		union {
		union {
+39 −24
Original line number Original line Diff line number Diff line
@@ -41,6 +41,14 @@ static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
	return -EMSGSIZE;
	return -EMSGSIZE;
}
}


static void __mdb_entry_fill_flags(struct br_mdb_entry *e, unsigned char flags)
{
	e->state = flags & MDB_PG_FLAGS_PERMANENT;
	e->flags = 0;
	if (flags & MDB_PG_FLAGS_OFFLOAD)
		e->flags |= MDB_FLAGS_OFFLOAD;
}

static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
			    struct net_device *dev)
			    struct net_device *dev)
{
{
@@ -85,8 +93,8 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
					struct br_mdb_entry e;
					struct br_mdb_entry e;
					memset(&e, 0, sizeof(e));
					memset(&e, 0, sizeof(e));
					e.ifindex = port->dev->ifindex;
					e.ifindex = port->dev->ifindex;
					e.state = p->state;
					e.vid = p->addr.vid;
					e.vid = p->addr.vid;
					__mdb_entry_fill_flags(&e, p->flags);
					if (p->addr.proto == htons(ETH_P_IP))
					if (p->addr.proto == htons(ETH_P_IP))
						e.addr.u.ip4 = p->addr.u.ip4;
						e.addr.u.ip4 = p->addr.u.ip4;
#if IS_ENABLED(CONFIG_IPV6)
#if IS_ENABLED(CONFIG_IPV6)
@@ -209,7 +217,7 @@ static inline size_t rtnl_mdb_nlmsg_size(void)
}
}


static void __br_mdb_notify(struct net_device *dev, struct br_mdb_entry *entry,
static void __br_mdb_notify(struct net_device *dev, struct br_mdb_entry *entry,
			    int type)
			    int type, struct net_bridge_port_group *pg)
{
{
	struct switchdev_obj_port_mdb mdb = {
	struct switchdev_obj_port_mdb mdb = {
		.obj = {
		.obj = {
@@ -232,10 +240,13 @@ static void __br_mdb_notify(struct net_device *dev, struct br_mdb_entry *entry,
#endif
#endif


	mdb.obj.orig_dev = port_dev;
	mdb.obj.orig_dev = port_dev;
	if (port_dev && type == RTM_NEWMDB)
	if (port_dev && type == RTM_NEWMDB) {
		switchdev_port_obj_add(port_dev, &mdb.obj);
		err = switchdev_port_obj_add(port_dev, &mdb.obj);
	else if (port_dev && type == RTM_DELMDB)
		if (!err && pg)
			pg->flags |= MDB_PG_FLAGS_OFFLOAD;
	} else if (port_dev && type == RTM_DELMDB) {
		switchdev_port_obj_del(port_dev, &mdb.obj);
		switchdev_port_obj_del(port_dev, &mdb.obj);
	}


	skb = nlmsg_new(rtnl_mdb_nlmsg_size(), GFP_ATOMIC);
	skb = nlmsg_new(rtnl_mdb_nlmsg_size(), GFP_ATOMIC);
	if (!skb)
	if (!skb)
@@ -253,21 +264,21 @@ static void __br_mdb_notify(struct net_device *dev, struct br_mdb_entry *entry,
	rtnl_set_sk_err(net, RTNLGRP_MDB, err);
	rtnl_set_sk_err(net, RTNLGRP_MDB, err);
}
}


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_group *pg,
		   struct br_ip *group, int type, u8 state)
		   int type)
{
{
	struct br_mdb_entry entry;
	struct br_mdb_entry entry;


	memset(&entry, 0, sizeof(entry));
	memset(&entry, 0, sizeof(entry));
	entry.ifindex = port->dev->ifindex;
	entry.ifindex = pg->port->dev->ifindex;
	entry.addr.proto = group->proto;
	entry.addr.proto = pg->addr.proto;
	entry.addr.u.ip4 = group->u.ip4;
	entry.addr.u.ip4 = pg->addr.u.ip4;
#if IS_ENABLED(CONFIG_IPV6)
#if IS_ENABLED(CONFIG_IPV6)
	entry.addr.u.ip6 = group->u.ip6;
	entry.addr.u.ip6 = pg->addr.u.ip6;
#endif
#endif
	entry.state = state;
	entry.vid = pg->addr.vid;
	entry.vid = group->vid;
	__mdb_entry_fill_flags(&entry, pg->flags);
	__br_mdb_notify(dev, &entry, type);
	__br_mdb_notify(dev, &entry, type, pg);
}
}


static int nlmsg_populate_rtr_fill(struct sk_buff *skb,
static int nlmsg_populate_rtr_fill(struct sk_buff *skb,
@@ -412,7 +423,8 @@ static int br_mdb_parse(struct sk_buff *skb, struct nlmsghdr *nlh,
}
}


static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
			    struct br_ip *group, unsigned char state)
			    struct br_ip *group, unsigned char state,
			    struct net_bridge_port_group **pg)
{
{
	struct net_bridge_mdb_entry *mp;
	struct net_bridge_mdb_entry *mp;
	struct net_bridge_port_group *p;
	struct net_bridge_port_group *p;
@@ -443,6 +455,7 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
	if (unlikely(!p))
	if (unlikely(!p))
		return -ENOMEM;
		return -ENOMEM;
	rcu_assign_pointer(*pp, p);
	rcu_assign_pointer(*pp, p);
	*pg = p;
	if (state == MDB_TEMPORARY)
	if (state == MDB_TEMPORARY)
		mod_timer(&p->timer, now + br->multicast_membership_interval);
		mod_timer(&p->timer, now + br->multicast_membership_interval);


@@ -450,7 +463,8 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
}
}


static int __br_mdb_add(struct net *net, struct net_bridge *br,
static int __br_mdb_add(struct net *net, struct net_bridge *br,
			struct br_mdb_entry *entry)
			struct br_mdb_entry *entry,
			struct net_bridge_port_group **pg)
{
{
	struct br_ip ip;
	struct br_ip ip;
	struct net_device *dev;
	struct net_device *dev;
@@ -479,7 +493,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
#endif
#endif


	spin_lock_bh(&br->multicast_lock);
	spin_lock_bh(&br->multicast_lock);
	ret = br_mdb_add_group(br, p, &ip, entry->state);
	ret = br_mdb_add_group(br, p, &ip, entry->state, pg);
	spin_unlock_bh(&br->multicast_lock);
	spin_unlock_bh(&br->multicast_lock);
	return ret;
	return ret;
}
}
@@ -487,6 +501,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
{
{
	struct net *net = sock_net(skb->sk);
	struct net *net = sock_net(skb->sk);
	struct net_bridge_port_group *pg;
	struct net_bridge_vlan_group *vg;
	struct net_bridge_vlan_group *vg;
	struct net_device *dev, *pdev;
	struct net_device *dev, *pdev;
	struct br_mdb_entry *entry;
	struct br_mdb_entry *entry;
@@ -516,15 +531,15 @@ static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
	if (br_vlan_enabled(br) && vg && entry->vid == 0) {
	if (br_vlan_enabled(br) && vg && entry->vid == 0) {
		list_for_each_entry(v, &vg->vlan_list, vlist) {
		list_for_each_entry(v, &vg->vlan_list, vlist) {
			entry->vid = v->vid;
			entry->vid = v->vid;
			err = __br_mdb_add(net, br, entry);
			err = __br_mdb_add(net, br, entry, &pg);
			if (err)
			if (err)
				break;
				break;
			__br_mdb_notify(dev, entry, RTM_NEWMDB);
			__br_mdb_notify(dev, entry, RTM_NEWMDB, pg);
		}
		}
	} else {
	} else {
		err = __br_mdb_add(net, br, entry);
		err = __br_mdb_add(net, br, entry, &pg);
		if (!err)
		if (!err)
			__br_mdb_notify(dev, entry, RTM_NEWMDB);
			__br_mdb_notify(dev, entry, RTM_NEWMDB, pg);
	}
	}


	return err;
	return err;
@@ -568,7 +583,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
		if (p->port->state == BR_STATE_DISABLED)
		if (p->port->state == BR_STATE_DISABLED)
			goto unlock;
			goto unlock;


		entry->state = p->state;
		__mdb_entry_fill_flags(entry, p->flags);
		rcu_assign_pointer(*pp, p->next);
		rcu_assign_pointer(*pp, p->next);
		hlist_del_init(&p->mglist);
		hlist_del_init(&p->mglist);
		del_timer(&p->timer);
		del_timer(&p->timer);
@@ -620,12 +635,12 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
			entry->vid = v->vid;
			entry->vid = v->vid;
			err = __br_mdb_del(br, entry);
			err = __br_mdb_del(br, entry);
			if (!err)
			if (!err)
				__br_mdb_notify(dev, entry, RTM_DELMDB);
				__br_mdb_notify(dev, entry, RTM_DELMDB, NULL);
		}
		}
	} else {
	} else {
		err = __br_mdb_del(br, entry);
		err = __br_mdb_del(br, entry);
		if (!err)
		if (!err)
			__br_mdb_notify(dev, entry, RTM_DELMDB);
			__br_mdb_notify(dev, entry, RTM_DELMDB, NULL);
	}
	}


	return err;
	return err;
+8 −10
Original line number Original line Diff line number Diff line
@@ -283,8 +283,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
		rcu_assign_pointer(*pp, p->next);
		rcu_assign_pointer(*pp, p->next);
		hlist_del_init(&p->mglist);
		hlist_del_init(&p->mglist);
		del_timer(&p->timer);
		del_timer(&p->timer);
		br_mdb_notify(br->dev, p->port, &pg->addr, RTM_DELMDB,
		br_mdb_notify(br->dev, p, RTM_DELMDB);
			      p->state);
		call_rcu_bh(&p->rcu, br_multicast_free_pg);
		call_rcu_bh(&p->rcu, br_multicast_free_pg);


		if (!mp->ports && !mp->mglist &&
		if (!mp->ports && !mp->mglist &&
@@ -304,7 +303,7 @@ static void br_multicast_port_group_expired(unsigned long data)


	spin_lock(&br->multicast_lock);
	spin_lock(&br->multicast_lock);
	if (!netif_running(br->dev) || timer_pending(&pg->timer) ||
	if (!netif_running(br->dev) || timer_pending(&pg->timer) ||
	    hlist_unhashed(&pg->mglist) || pg->state & MDB_PERMANENT)
	    hlist_unhashed(&pg->mglist) || pg->flags & MDB_PG_FLAGS_PERMANENT)
		goto out;
		goto out;


	br_multicast_del_pg(br, pg);
	br_multicast_del_pg(br, pg);
@@ -649,7 +648,7 @@ struct net_bridge_port_group *br_multicast_new_port_group(
			struct net_bridge_port *port,
			struct net_bridge_port *port,
			struct br_ip *group,
			struct br_ip *group,
			struct net_bridge_port_group __rcu *next,
			struct net_bridge_port_group __rcu *next,
			unsigned char state)
			unsigned char flags)
{
{
	struct net_bridge_port_group *p;
	struct net_bridge_port_group *p;


@@ -659,7 +658,7 @@ struct net_bridge_port_group *br_multicast_new_port_group(


	p->addr = *group;
	p->addr = *group;
	p->port = port;
	p->port = port;
	p->state = state;
	p->flags = flags;
	rcu_assign_pointer(p->next, next);
	rcu_assign_pointer(p->next, next);
	hlist_add_head(&p->mglist, &port->mglist);
	hlist_add_head(&p->mglist, &port->mglist);
	setup_timer(&p->timer, br_multicast_port_group_expired,
	setup_timer(&p->timer, br_multicast_port_group_expired,
@@ -702,11 +701,11 @@ static int br_multicast_add_group(struct net_bridge *br,
			break;
			break;
	}
	}


	p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY);
	p = br_multicast_new_port_group(port, group, *pp, 0);
	if (unlikely(!p))
	if (unlikely(!p))
		goto err;
		goto err;
	rcu_assign_pointer(*pp, p);
	rcu_assign_pointer(*pp, p);
	br_mdb_notify(br->dev, port, group, RTM_NEWMDB, MDB_TEMPORARY);
	br_mdb_notify(br->dev, p, RTM_NEWMDB);


found:
found:
	mod_timer(&p->timer, now + br->multicast_membership_interval);
	mod_timer(&p->timer, now + br->multicast_membership_interval);
@@ -975,7 +974,7 @@ void br_multicast_disable_port(struct net_bridge_port *port)


	spin_lock(&br->multicast_lock);
	spin_lock(&br->multicast_lock);
	hlist_for_each_entry_safe(pg, n, &port->mglist, mglist)
	hlist_for_each_entry_safe(pg, n, &port->mglist, mglist)
		if (pg->state == MDB_TEMPORARY)
		if (!(pg->flags & MDB_PG_FLAGS_PERMANENT))
			br_multicast_del_pg(br, pg);
			br_multicast_del_pg(br, pg);


	if (!hlist_unhashed(&port->rlist)) {
	if (!hlist_unhashed(&port->rlist)) {
@@ -1453,8 +1452,7 @@ br_multicast_leave_group(struct net_bridge *br,
			hlist_del_init(&p->mglist);
			hlist_del_init(&p->mglist);
			del_timer(&p->timer);
			del_timer(&p->timer);
			call_rcu_bh(&p->rcu, br_multicast_free_pg);
			call_rcu_bh(&p->rcu, br_multicast_free_pg);
			br_mdb_notify(br->dev, port, group, RTM_DELMDB,
			br_mdb_notify(br->dev, p, RTM_DELMDB);
				      p->state);


			if (!mp->ports && !mp->mglist &&
			if (!mp->ports && !mp->mglist &&
			    netif_running(br->dev))
			    netif_running(br->dev))
+7 −4
Original line number Original line Diff line number Diff line
@@ -150,6 +150,9 @@ struct net_bridge_fdb_entry
	struct rcu_head			rcu;
	struct rcu_head			rcu;
};
};


#define MDB_PG_FLAGS_PERMANENT	BIT(0)
#define MDB_PG_FLAGS_OFFLOAD	BIT(1)

struct net_bridge_port_group {
struct net_bridge_port_group {
	struct net_bridge_port		*port;
	struct net_bridge_port		*port;
	struct net_bridge_port_group __rcu *next;
	struct net_bridge_port_group __rcu *next;
@@ -157,7 +160,7 @@ struct net_bridge_port_group {
	struct rcu_head			rcu;
	struct rcu_head			rcu;
	struct timer_list		timer;
	struct timer_list		timer;
	struct br_ip			addr;
	struct br_ip			addr;
	unsigned char			state;
	unsigned char			flags;
};
};


struct net_bridge_mdb_entry
struct net_bridge_mdb_entry
@@ -554,11 +557,11 @@ void br_multicast_free_pg(struct rcu_head *head);
struct net_bridge_port_group *
struct net_bridge_port_group *
br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group,
br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group,
			    struct net_bridge_port_group __rcu *next,
			    struct net_bridge_port_group __rcu *next,
			    unsigned char state);
			    unsigned char flags);
void br_mdb_init(void);
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_group *pg,
		   struct br_ip *group, int type, u8 state);
		   int type);
void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port,
void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port,
		   int type);
		   int type);