Skip to content

Commit 932c441

Browse files
committed
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>
2 parents ba5dfaf + d08c6bc commit 932c441

File tree

6 files changed

+177
-470
lines changed

6 files changed

+177
-470
lines changed

net/bridge/br_device.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,17 @@ static int br_dev_init(struct net_device *dev)
131131
return err;
132132
}
133133

134+
err = br_mdb_hash_init(br);
135+
if (err) {
136+
free_percpu(br->stats);
137+
br_fdb_hash_fini(br);
138+
return err;
139+
}
140+
134141
err = br_vlan_init(br);
135142
if (err) {
136143
free_percpu(br->stats);
144+
br_mdb_hash_fini(br);
137145
br_fdb_hash_fini(br);
138146
return err;
139147
}
@@ -142,6 +150,7 @@ static int br_dev_init(struct net_device *dev)
142150
if (err) {
143151
free_percpu(br->stats);
144152
br_vlan_flush(br);
153+
br_mdb_hash_fini(br);
145154
br_fdb_hash_fini(br);
146155
}
147156
br_set_lockdep_class(dev);
@@ -156,6 +165,7 @@ static void br_dev_uninit(struct net_device *dev)
156165
br_multicast_dev_del(br);
157166
br_multicast_uninit_stats(br);
158167
br_vlan_flush(br);
168+
br_mdb_hash_fini(br);
159169
br_fdb_hash_fini(br);
160170
free_percpu(br->stats);
161171
}

net/bridge/br_mdb.c

Lines changed: 52 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -78,82 +78,72 @@ static void __mdb_entry_to_br_ip(struct br_mdb_entry *entry, struct br_ip *ip)
7878
static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
7979
struct net_device *dev)
8080
{
81+
int idx = 0, s_idx = cb->args[1], err = 0;
8182
struct net_bridge *br = netdev_priv(dev);
82-
struct net_bridge_mdb_htable *mdb;
83+
struct net_bridge_mdb_entry *mp;
8384
struct nlattr *nest, *nest2;
84-
int i, err = 0;
85-
int idx = 0, s_idx = cb->args[1];
8685

8786
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
8887
return 0;
8988

90-
mdb = rcu_dereference(br->mdb);
91-
if (!mdb)
92-
return 0;
93-
9489
nest = nla_nest_start(skb, MDBA_MDB);
9590
if (nest == NULL)
9691
return -EMSGSIZE;
9792

98-
for (i = 0; i < mdb->max; i++) {
99-
struct net_bridge_mdb_entry *mp;
93+
hlist_for_each_entry_rcu(mp, &br->mdb_list, mdb_node) {
10094
struct net_bridge_port_group *p;
10195
struct net_bridge_port_group __rcu **pp;
10296
struct net_bridge_port *port;
10397

104-
hlist_for_each_entry_rcu(mp, &mdb->mhash[i], hlist[mdb->ver]) {
105-
if (idx < s_idx)
106-
goto skip;
98+
if (idx < s_idx)
99+
goto skip;
107100

108-
nest2 = nla_nest_start(skb, MDBA_MDB_ENTRY);
109-
if (nest2 == NULL) {
110-
err = -EMSGSIZE;
111-
goto out;
112-
}
101+
nest2 = nla_nest_start(skb, MDBA_MDB_ENTRY);
102+
if (!nest2) {
103+
err = -EMSGSIZE;
104+
break;
105+
}
113106

114-
for (pp = &mp->ports;
115-
(p = rcu_dereference(*pp)) != NULL;
116-
pp = &p->next) {
117-
struct nlattr *nest_ent;
118-
struct br_mdb_entry e;
119-
120-
port = p->port;
121-
if (!port)
122-
continue;
123-
124-
memset(&e, 0, sizeof(e));
125-
e.ifindex = port->dev->ifindex;
126-
e.vid = p->addr.vid;
127-
__mdb_entry_fill_flags(&e, p->flags);
128-
if (p->addr.proto == htons(ETH_P_IP))
129-
e.addr.u.ip4 = p->addr.u.ip4;
107+
for (pp = &mp->ports; (p = rcu_dereference(*pp)) != NULL;
108+
pp = &p->next) {
109+
struct nlattr *nest_ent;
110+
struct br_mdb_entry e;
111+
112+
port = p->port;
113+
if (!port)
114+
continue;
115+
116+
memset(&e, 0, sizeof(e));
117+
e.ifindex = port->dev->ifindex;
118+
e.vid = p->addr.vid;
119+
__mdb_entry_fill_flags(&e, p->flags);
120+
if (p->addr.proto == htons(ETH_P_IP))
121+
e.addr.u.ip4 = p->addr.u.ip4;
130122
#if IS_ENABLED(CONFIG_IPV6)
131-
if (p->addr.proto == htons(ETH_P_IPV6))
132-
e.addr.u.ip6 = p->addr.u.ip6;
123+
if (p->addr.proto == htons(ETH_P_IPV6))
124+
e.addr.u.ip6 = p->addr.u.ip6;
133125
#endif
134-
e.addr.proto = p->addr.proto;
135-
nest_ent = nla_nest_start(skb,
136-
MDBA_MDB_ENTRY_INFO);
137-
if (!nest_ent) {
138-
nla_nest_cancel(skb, nest2);
139-
err = -EMSGSIZE;
140-
goto out;
141-
}
142-
if (nla_put_nohdr(skb, sizeof(e), &e) ||
143-
nla_put_u32(skb,
144-
MDBA_MDB_EATTR_TIMER,
145-
br_timer_value(&p->timer))) {
146-
nla_nest_cancel(skb, nest_ent);
147-
nla_nest_cancel(skb, nest2);
148-
err = -EMSGSIZE;
149-
goto out;
150-
}
151-
nla_nest_end(skb, nest_ent);
126+
e.addr.proto = p->addr.proto;
127+
nest_ent = nla_nest_start(skb, MDBA_MDB_ENTRY_INFO);
128+
if (!nest_ent) {
129+
nla_nest_cancel(skb, nest2);
130+
err = -EMSGSIZE;
131+
goto out;
152132
}
153-
nla_nest_end(skb, nest2);
154-
skip:
155-
idx++;
133+
if (nla_put_nohdr(skb, sizeof(e), &e) ||
134+
nla_put_u32(skb,
135+
MDBA_MDB_EATTR_TIMER,
136+
br_timer_value(&p->timer))) {
137+
nla_nest_cancel(skb, nest_ent);
138+
nla_nest_cancel(skb, nest2);
139+
err = -EMSGSIZE;
140+
goto out;
141+
}
142+
nla_nest_end(skb, nest_ent);
156143
}
144+
nla_nest_end(skb, nest2);
145+
skip:
146+
idx++;
157147
}
158148

159149
out:
@@ -203,8 +193,7 @@ static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
203193

204194
rcu_read_lock();
205195

206-
/* In theory this could be wrapped to 0... */
207-
cb->seq = net->dev_base_seq + br_mdb_rehash_seq;
196+
cb->seq = net->dev_base_seq;
208197

209198
for_each_netdev_rcu(net, dev) {
210199
if (dev->priv_flags & IFF_EBRIDGE) {
@@ -297,7 +286,6 @@ static void br_mdb_complete(struct net_device *dev, int err, void *priv)
297286
struct br_mdb_complete_info *data = priv;
298287
struct net_bridge_port_group __rcu **pp;
299288
struct net_bridge_port_group *p;
300-
struct net_bridge_mdb_htable *mdb;
301289
struct net_bridge_mdb_entry *mp;
302290
struct net_bridge_port *port = data->port;
303291
struct net_bridge *br = port->br;
@@ -306,8 +294,7 @@ static void br_mdb_complete(struct net_device *dev, int err, void *priv)
306294
goto err;
307295

308296
spin_lock_bh(&br->multicast_lock);
309-
mdb = mlock_dereference(br->mdb, br);
310-
mp = br_mdb_ip_get(mdb, &data->ip);
297+
mp = br_mdb_ip_get(br, &data->ip);
311298
if (!mp)
312299
goto out;
313300
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,
588575
struct net_bridge_mdb_entry *mp;
589576
struct net_bridge_port_group *p;
590577
struct net_bridge_port_group __rcu **pp;
591-
struct net_bridge_mdb_htable *mdb;
592578
unsigned long now = jiffies;
593579
int err;
594580

595-
mdb = mlock_dereference(br->mdb, br);
596-
mp = br_mdb_ip_get(mdb, group);
581+
mp = br_mdb_ip_get(br, group);
597582
if (!mp) {
598-
mp = br_multicast_new_group(br, port, group);
583+
mp = br_multicast_new_group(br, group);
599584
err = PTR_ERR_OR_ZERO(mp);
600585
if (err)
601586
return err;
@@ -696,7 +681,6 @@ static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
696681

697682
static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
698683
{
699-
struct net_bridge_mdb_htable *mdb;
700684
struct net_bridge_mdb_entry *mp;
701685
struct net_bridge_port_group *p;
702686
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)
709693
__mdb_entry_to_br_ip(entry, &ip);
710694

711695
spin_lock_bh(&br->multicast_lock);
712-
mdb = mlock_dereference(br->mdb, br);
713-
714-
mp = br_mdb_ip_get(mdb, &ip);
696+
mp = br_mdb_ip_get(br, &ip);
715697
if (!mp)
716698
goto unlock;
717699

@@ -728,7 +710,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
728710
rcu_assign_pointer(*pp, p->next);
729711
hlist_del_init(&p->mglist);
730712
del_timer(&p->timer);
731-
call_rcu_bh(&p->rcu, br_multicast_free_pg);
713+
kfree_rcu(p, rcu);
732714
err = 0;
733715

734716
if (!mp->ports && !mp->host_joined &&

0 commit comments

Comments
 (0)