Commit 085b53c8 authored by Nikolay Aleksandrov's avatar Nikolay Aleksandrov Committed by David S. Miller

net: bridge: mcast: add sg_port rhashtable

To speedup S,G forward handling we need to be able to quickly find out
if a port is a member of an S,G group. To do that add a global S,G port
rhashtable with key: source addr, group addr, protocol, vid (all br_ip
fields) and port pointer.
Signed-off-by: default avatarNikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8f8cb77e
...@@ -281,7 +281,7 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst, ...@@ -281,7 +281,7 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
while (p || rp) { while (p || rp) {
struct net_bridge_port *port, *lport, *rport; struct net_bridge_port *port, *lport, *rport;
lport = p ? p->port : NULL; lport = p ? p->key.port : NULL;
rport = hlist_entry_safe(rp, struct net_bridge_port, rlist); rport = hlist_entry_safe(rp, struct net_bridge_port, rlist);
if ((unsigned long)lport > (unsigned long)rport) { if ((unsigned long)lport > (unsigned long)rport) {
......
...@@ -101,7 +101,7 @@ static int __mdb_fill_srcs(struct sk_buff *skb, ...@@ -101,7 +101,7 @@ static int __mdb_fill_srcs(struct sk_buff *skb,
return -EMSGSIZE; return -EMSGSIZE;
hlist_for_each_entry_rcu(ent, &p->src_list, node, hlist_for_each_entry_rcu(ent, &p->src_list, node,
lockdep_is_held(&p->port->br->multicast_lock)) { lockdep_is_held(&p->key.port->br->multicast_lock)) {
nest_ent = nla_nest_start(skb, MDBA_MDB_SRCLIST_ENTRY); nest_ent = nla_nest_start(skb, MDBA_MDB_SRCLIST_ENTRY);
if (!nest_ent) if (!nest_ent)
goto out_cancel_err; goto out_cancel_err;
...@@ -156,7 +156,7 @@ static int __mdb_fill_info(struct sk_buff *skb, ...@@ -156,7 +156,7 @@ static int __mdb_fill_info(struct sk_buff *skb,
memset(&e, 0, sizeof(e)); memset(&e, 0, sizeof(e));
if (p) { if (p) {
ifindex = p->port->dev->ifindex; ifindex = p->key.port->dev->ifindex;
mtimer = &p->timer; mtimer = &p->timer;
flags = p->flags; flags = p->flags;
} else { } else {
...@@ -263,7 +263,7 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb, ...@@ -263,7 +263,7 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
for (pp = &mp->ports; (p = rcu_dereference(*pp)) != NULL; for (pp = &mp->ports; (p = rcu_dereference(*pp)) != NULL;
pp = &p->next) { pp = &p->next) {
if (!p->port) if (!p->key.port)
continue; continue;
if (pidx < s_pidx) if (pidx < s_pidx)
goto skip_pg; goto skip_pg;
...@@ -423,21 +423,21 @@ static size_t rtnl_mdb_nlmsg_size(struct net_bridge_port_group *pg) ...@@ -423,21 +423,21 @@ static size_t rtnl_mdb_nlmsg_size(struct net_bridge_port_group *pg)
/* MDBA_MDB_EATTR_RTPROT */ /* MDBA_MDB_EATTR_RTPROT */
nlmsg_size += nla_total_size(sizeof(u8)); nlmsg_size += nla_total_size(sizeof(u8));
switch (pg->addr.proto) { switch (pg->key.addr.proto) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
/* MDBA_MDB_EATTR_SOURCE */ /* MDBA_MDB_EATTR_SOURCE */
if (pg->addr.src.ip4) if (pg->key.addr.src.ip4)
nlmsg_size += nla_total_size(sizeof(__be32)); nlmsg_size += nla_total_size(sizeof(__be32));
if (pg->port->br->multicast_igmp_version == 2) if (pg->key.port->br->multicast_igmp_version == 2)
goto out; goto out;
addr_size = sizeof(__be32); addr_size = sizeof(__be32);
break; break;
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6): case htons(ETH_P_IPV6):
/* MDBA_MDB_EATTR_SOURCE */ /* MDBA_MDB_EATTR_SOURCE */
if (!ipv6_addr_any(&pg->addr.src.ip6)) if (!ipv6_addr_any(&pg->key.addr.src.ip6))
nlmsg_size += nla_total_size(sizeof(struct in6_addr)); nlmsg_size += nla_total_size(sizeof(struct in6_addr));
if (pg->port->br->multicast_mld_version == 1) if (pg->key.port->br->multicast_mld_version == 1)
goto out; goto out;
addr_size = sizeof(struct in6_addr); addr_size = sizeof(struct in6_addr);
break; break;
...@@ -486,7 +486,7 @@ static void br_mdb_complete(struct net_device *dev, int err, void *priv) ...@@ -486,7 +486,7 @@ static void br_mdb_complete(struct net_device *dev, int err, void *priv)
goto out; goto out;
for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL; for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL;
pp = &p->next) { pp = &p->next) {
if (p->port != port) if (p->key.port != port)
continue; continue;
p->flags |= MDB_PG_FLAGS_OFFLOAD; p->flags |= MDB_PG_FLAGS_OFFLOAD;
} }
...@@ -561,21 +561,21 @@ void br_mdb_notify(struct net_device *dev, ...@@ -561,21 +561,21 @@ void br_mdb_notify(struct net_device *dev,
else else
ipv6_eth_mc_map(&mp->addr.dst.ip6, mdb.addr); ipv6_eth_mc_map(&mp->addr.dst.ip6, mdb.addr);
#endif #endif
mdb.obj.orig_dev = pg->port->dev; mdb.obj.orig_dev = pg->key.port->dev;
switch (type) { switch (type) {
case RTM_NEWMDB: case RTM_NEWMDB:
complete_info = kmalloc(sizeof(*complete_info), GFP_ATOMIC); complete_info = kmalloc(sizeof(*complete_info), GFP_ATOMIC);
if (!complete_info) if (!complete_info)
break; break;
complete_info->port = pg->port; complete_info->port = pg->key.port;
complete_info->ip = mp->addr; complete_info->ip = mp->addr;
mdb.obj.complete_priv = complete_info; mdb.obj.complete_priv = complete_info;
mdb.obj.complete = br_mdb_complete; mdb.obj.complete = br_mdb_complete;
if (switchdev_port_obj_add(pg->port->dev, &mdb.obj, NULL)) if (switchdev_port_obj_add(pg->key.port->dev, &mdb.obj, NULL))
kfree(complete_info); kfree(complete_info);
break; break;
case RTM_DELMDB: case RTM_DELMDB:
switchdev_port_obj_del(pg->port->dev, &mdb.obj); switchdev_port_obj_del(pg->key.port->dev, &mdb.obj);
break; break;
} }
} else { } else {
...@@ -869,11 +869,11 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port, ...@@ -869,11 +869,11 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
for (pp = &mp->ports; for (pp = &mp->ports;
(p = mlock_dereference(*pp, br)) != NULL; (p = mlock_dereference(*pp, br)) != NULL;
pp = &p->next) { pp = &p->next) {
if (p->port == port) { if (p->key.port == port) {
NL_SET_ERR_MSG_MOD(extack, "Group is already joined by port"); NL_SET_ERR_MSG_MOD(extack, "Group is already joined by port");
return -EEXIST; return -EEXIST;
} }
if ((unsigned long)p->port < (unsigned long)port) if ((unsigned long)p->key.port < (unsigned long)port)
break; break;
} }
...@@ -1013,10 +1013,10 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry, ...@@ -1013,10 +1013,10 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry,
for (pp = &mp->ports; for (pp = &mp->ports;
(p = mlock_dereference(*pp, br)) != NULL; (p = mlock_dereference(*pp, br)) != NULL;
pp = &p->next) { pp = &p->next) {
if (!p->port || p->port->dev->ifindex != entry->ifindex) if (!p->key.port || p->key.port->dev->ifindex != entry->ifindex)
continue; continue;
if (p->port->state == BR_STATE_DISABLED) if (p->key.port->state == BR_STATE_DISABLED)
goto unlock; goto unlock;
br_multicast_del_pg(mp, p, pp); br_multicast_del_pg(mp, p, pp);
......
This diff is collapsed.
...@@ -238,10 +238,14 @@ struct net_bridge_group_src { ...@@ -238,10 +238,14 @@ struct net_bridge_group_src {
struct rcu_head rcu; struct rcu_head rcu;
}; };
struct net_bridge_port_group { struct net_bridge_port_group_sg_key {
struct net_bridge_port *port; struct net_bridge_port *port;
struct net_bridge_port_group __rcu *next;
struct br_ip addr; struct br_ip addr;
};
struct net_bridge_port_group {
struct net_bridge_port_group __rcu *next;
struct net_bridge_port_group_sg_key key;
unsigned char eth_addr[ETH_ALEN] __aligned(2); unsigned char eth_addr[ETH_ALEN] __aligned(2);
unsigned char flags; unsigned char flags;
unsigned char filter_mode; unsigned char filter_mode;
...@@ -254,6 +258,7 @@ struct net_bridge_port_group { ...@@ -254,6 +258,7 @@ struct net_bridge_port_group {
struct timer_list rexmit_timer; struct timer_list rexmit_timer;
struct hlist_node mglist; struct hlist_node mglist;
struct rhash_head rhnode;
struct net_bridge_mcast_gc mcast_gc; struct net_bridge_mcast_gc mcast_gc;
struct rcu_head rcu; struct rcu_head rcu;
}; };
...@@ -441,6 +446,7 @@ struct net_bridge { ...@@ -441,6 +446,7 @@ struct net_bridge {
unsigned long multicast_startup_query_interval; unsigned long multicast_startup_query_interval;
struct rhashtable mdb_hash_tbl; struct rhashtable mdb_hash_tbl;
struct rhashtable sg_port_tbl;
struct hlist_head mcast_gc_list; struct hlist_head mcast_gc_list;
struct hlist_head mdb_list; struct hlist_head mdb_list;
......
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