diff options
author | David S. Miller | 2018-12-06 02:01:51 +0100 |
---|---|---|
committer | David S. Miller | 2018-12-06 02:01:51 +0100 |
commit | 932c4417077958fe486e6d8a64a06e65d664cb85 (patch) | |
tree | f78b107ea4b36adf481fbe3ca32cc89bb084f6bb /net/bridge/br_mdb.c | |
parent | Merge tag 'mlx5e-updates-2018-12-04' of git://git.kernel.org/pub/scm/linux/ke... (diff) | |
parent | net: bridge: increase multicast's default maximum number of entries (diff) | |
download | kernel-qcow2-linux-932c4417077958fe486e6d8a64a06e65d664cb85.tar.gz kernel-qcow2-linux-932c4417077958fe486e6d8a64a06e65d664cb85.tar.xz kernel-qcow2-linux-932c4417077958fe486e6d8a64a06e65d664cb85.zip |
Merge branch 'net-bridge-convert-multicast-to-generic-rhashtable'
Nikolay Aleksandrov says:
====================
net: bridge: convert multicast to generic rhashtable
The current bridge multicast code uses a custom rhashtable
implementation which predates the generic rhashtable API. Patch 01
converts it to use the generic kernel rhashtable which simplifies the
code a lot and removes duplicated functionality. The convert also makes
hash_elasticity obsolete as the generic rhashtable already has such
checks and has a fixed elasticity of RHT_ELASTICITY (16 currently) so we
emit a warning whenever elasticity is set and return RHT_ELASTICITY when
read (patch 03). Patch 02 converts the multicast code to use non-bh RCU
flavor as it was mixing bh and non-bh. Since now we have the generic
rhashtable which autoshrinks we can be more liberal with the default
hash maximum so patch 04 increases it to 4096 and moves it to a define in
br_private.h.
v3: add non-rcu br_mdb_get variant and use it where we have
multicast_lock, drop special hash_max handling and just set it where
needed and use non-bh RCU consistently (patch 02, new)
v2: send the latest version of the set which handles when IGMP snooping
is not defined, changes are in patch 01
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_mdb.c')
-rw-r--r-- | net/bridge/br_mdb.c | 122 |
1 files changed, 52 insertions, 70 deletions
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index a7ea2d431714..79d4c9d253e0 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -78,82 +78,72 @@ static void __mdb_entry_to_br_ip(struct br_mdb_entry *entry, struct br_ip *ip) static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev) { + int idx = 0, s_idx = cb->args[1], err = 0; struct net_bridge *br = netdev_priv(dev); - struct net_bridge_mdb_htable *mdb; + struct net_bridge_mdb_entry *mp; struct nlattr *nest, *nest2; - int i, err = 0; - int idx = 0, s_idx = cb->args[1]; if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) return 0; - mdb = rcu_dereference(br->mdb); - if (!mdb) - return 0; - nest = nla_nest_start(skb, MDBA_MDB); if (nest == NULL) return -EMSGSIZE; - for (i = 0; i < mdb->max; i++) { - struct net_bridge_mdb_entry *mp; + hlist_for_each_entry_rcu(mp, &br->mdb_list, mdb_node) { struct net_bridge_port_group *p; struct net_bridge_port_group __rcu **pp; struct net_bridge_port *port; - hlist_for_each_entry_rcu(mp, &mdb->mhash[i], hlist[mdb->ver]) { - if (idx < s_idx) - goto skip; + if (idx < s_idx) + goto skip; - nest2 = nla_nest_start(skb, MDBA_MDB_ENTRY); - if (nest2 == NULL) { - err = -EMSGSIZE; - goto out; - } + nest2 = nla_nest_start(skb, MDBA_MDB_ENTRY); + if (!nest2) { + err = -EMSGSIZE; + break; + } - for (pp = &mp->ports; - (p = rcu_dereference(*pp)) != NULL; - pp = &p->next) { - struct nlattr *nest_ent; - struct br_mdb_entry e; - - port = p->port; - if (!port) - continue; - - memset(&e, 0, sizeof(e)); - e.ifindex = port->dev->ifindex; - e.vid = p->addr.vid; - __mdb_entry_fill_flags(&e, p->flags); - if (p->addr.proto == htons(ETH_P_IP)) - e.addr.u.ip4 = p->addr.u.ip4; + for (pp = &mp->ports; (p = rcu_dereference(*pp)) != NULL; + pp = &p->next) { + struct nlattr *nest_ent; + struct br_mdb_entry e; + + port = p->port; + if (!port) + continue; + + memset(&e, 0, sizeof(e)); + e.ifindex = port->dev->ifindex; + e.vid = p->addr.vid; + __mdb_entry_fill_flags(&e, p->flags); + if (p->addr.proto == htons(ETH_P_IP)) + e.addr.u.ip4 = p->addr.u.ip4; #if IS_ENABLED(CONFIG_IPV6) - if (p->addr.proto == htons(ETH_P_IPV6)) - e.addr.u.ip6 = p->addr.u.ip6; + if (p->addr.proto == htons(ETH_P_IPV6)) + e.addr.u.ip6 = p->addr.u.ip6; #endif - e.addr.proto = p->addr.proto; - nest_ent = nla_nest_start(skb, - MDBA_MDB_ENTRY_INFO); - if (!nest_ent) { - nla_nest_cancel(skb, nest2); - err = -EMSGSIZE; - goto out; - } - if (nla_put_nohdr(skb, sizeof(e), &e) || - nla_put_u32(skb, - MDBA_MDB_EATTR_TIMER, - br_timer_value(&p->timer))) { - nla_nest_cancel(skb, nest_ent); - nla_nest_cancel(skb, nest2); - err = -EMSGSIZE; - goto out; - } - nla_nest_end(skb, nest_ent); + e.addr.proto = p->addr.proto; + nest_ent = nla_nest_start(skb, MDBA_MDB_ENTRY_INFO); + if (!nest_ent) { + nla_nest_cancel(skb, nest2); + err = -EMSGSIZE; + goto out; } - nla_nest_end(skb, nest2); - skip: - idx++; + if (nla_put_nohdr(skb, sizeof(e), &e) || + nla_put_u32(skb, + MDBA_MDB_EATTR_TIMER, + br_timer_value(&p->timer))) { + nla_nest_cancel(skb, nest_ent); + nla_nest_cancel(skb, nest2); + err = -EMSGSIZE; + goto out; + } + nla_nest_end(skb, nest_ent); } + nla_nest_end(skb, nest2); +skip: + idx++; } out: @@ -203,8 +193,7 @@ static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock(); - /* In theory this could be wrapped to 0... */ - cb->seq = net->dev_base_seq + br_mdb_rehash_seq; + cb->seq = net->dev_base_seq; for_each_netdev_rcu(net, dev) { if (dev->priv_flags & IFF_EBRIDGE) { @@ -297,7 +286,6 @@ static void br_mdb_complete(struct net_device *dev, int err, void *priv) struct br_mdb_complete_info *data = priv; struct net_bridge_port_group __rcu **pp; struct net_bridge_port_group *p; - struct net_bridge_mdb_htable *mdb; struct net_bridge_mdb_entry *mp; struct net_bridge_port *port = data->port; struct net_bridge *br = port->br; @@ -306,8 +294,7 @@ static void br_mdb_complete(struct net_device *dev, int err, void *priv) goto err; spin_lock_bh(&br->multicast_lock); - mdb = mlock_dereference(br->mdb, br); - mp = br_mdb_ip_get(mdb, &data->ip); + mp = br_mdb_ip_get(br, &data->ip); if (!mp) goto out; for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL; @@ -588,14 +575,12 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port, struct net_bridge_mdb_entry *mp; struct net_bridge_port_group *p; struct net_bridge_port_group __rcu **pp; - struct net_bridge_mdb_htable *mdb; unsigned long now = jiffies; int err; - mdb = mlock_dereference(br->mdb, br); - mp = br_mdb_ip_get(mdb, group); + mp = br_mdb_ip_get(br, group); if (!mp) { - mp = br_multicast_new_group(br, port, group); + mp = br_multicast_new_group(br, group); err = PTR_ERR_OR_ZERO(mp); if (err) return err; @@ -696,7 +681,6 @@ static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) { - struct net_bridge_mdb_htable *mdb; struct net_bridge_mdb_entry *mp; struct net_bridge_port_group *p; struct net_bridge_port_group __rcu **pp; @@ -709,9 +693,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) __mdb_entry_to_br_ip(entry, &ip); spin_lock_bh(&br->multicast_lock); - mdb = mlock_dereference(br->mdb, br); - - mp = br_mdb_ip_get(mdb, &ip); + mp = br_mdb_ip_get(br, &ip); if (!mp) goto unlock; @@ -728,7 +710,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) rcu_assign_pointer(*pp, p->next); hlist_del_init(&p->mglist); del_timer(&p->timer); - call_rcu_bh(&p->rcu, br_multicast_free_pg); + kfree_rcu(p, rcu); err = 0; if (!mp->ports && !mp->host_joined && |