Skip to content

Commit 68d4e52

Browse files
committed
Merge branch 'bridge-vlan'
Nikolay Aleksandrov says: ==================== bridge: vlan: cleanups & fixes (part 2) This is the second follow-up set with one fix (patch 01) and more cleanups (patches 02,03 and 04). These are minor compared to the previous ones and should be the last before taking on the optimization changes on the fast-path. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents e96f78a + 6be144f commit 68d4e52

File tree

3 files changed

+66
-48
lines changed

3 files changed

+66
-48
lines changed

net/bridge/br_netlink.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg,
3434

3535
pvid = br_get_pvid(vg);
3636
/* Count number of vlan infos */
37-
list_for_each_entry(v, &vg->vlan_list, vlist) {
37+
list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
3838
flags = 0;
3939
/* only a context, bridge vlan not activated */
4040
if (!br_vlan_should_use(v))
@@ -76,13 +76,19 @@ static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg,
7676
static int br_get_num_vlan_infos(struct net_bridge_vlan_group *vg,
7777
u32 filter_mask)
7878
{
79+
int num_vlans;
80+
7981
if (!vg)
8082
return 0;
8183

8284
if (filter_mask & RTEXT_FILTER_BRVLAN)
8385
return vg->num_vlans;
8486

85-
return __get_num_vlan_infos(vg, filter_mask);
87+
rcu_read_lock();
88+
num_vlans = __get_num_vlan_infos(vg, filter_mask);
89+
rcu_read_unlock();
90+
91+
return num_vlans;
8692
}
8793

8894
static size_t br_get_link_af_size_filtered(const struct net_device *dev,

net/bridge/br_private.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ static inline bool br_vlan_is_brentry(const struct net_bridge_vlan *v)
400400
return v->flags & BRIDGE_VLAN_INFO_BRENTRY;
401401
}
402402

403-
/* check if we should use the vlan entry is usable */
403+
/* check if we should use the vlan entry, returns false if it's only context */
404404
static inline bool br_vlan_should_use(const struct net_bridge_vlan *v)
405405
{
406406
if (br_vlan_is_master(v)) {

net/bridge/br_vlan.c

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@ static void __vlan_add_list(struct net_bridge_vlan *v)
111111
else
112112
break;
113113
}
114-
list_add(&v->vlist, hpos);
114+
list_add_rcu(&v->vlist, hpos);
115115
}
116116

117117
static void __vlan_del_list(struct net_bridge_vlan *v)
118118
{
119-
list_del(&v->vlist);
119+
list_del_rcu(&v->vlist);
120120
}
121121

122122
static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br,
@@ -146,6 +146,40 @@ static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br,
146146
return err;
147147
}
148148

149+
/* Returns a master vlan, if it didn't exist it gets created. In all cases a
150+
* a reference is taken to the master vlan before returning.
151+
*/
152+
static struct net_bridge_vlan *br_vlan_get_master(struct net_bridge *br, u16 vid)
153+
{
154+
struct net_bridge_vlan *masterv;
155+
156+
masterv = br_vlan_find(br->vlgrp, vid);
157+
if (!masterv) {
158+
/* missing global ctx, create it now */
159+
if (br_vlan_add(br, vid, 0))
160+
return NULL;
161+
masterv = br_vlan_find(br->vlgrp, vid);
162+
if (WARN_ON(!masterv))
163+
return NULL;
164+
}
165+
atomic_inc(&masterv->refcnt);
166+
167+
return masterv;
168+
}
169+
170+
static void br_vlan_put_master(struct net_bridge_vlan *masterv)
171+
{
172+
if (!br_vlan_is_master(masterv))
173+
return;
174+
175+
if (atomic_dec_and_test(&masterv->refcnt)) {
176+
rhashtable_remove_fast(&masterv->br->vlgrp->vlan_hash,
177+
&masterv->vnode, br_vlan_rht_params);
178+
__vlan_del_list(masterv);
179+
kfree_rcu(masterv, rcu);
180+
}
181+
}
182+
149183
/* This is the shared VLAN add function which works for both ports and bridge
150184
* devices. There are four possible calls to this function in terms of the
151185
* vlan entry type:
@@ -161,25 +195,23 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
161195
{
162196
struct net_bridge_vlan *masterv = NULL;
163197
struct net_bridge_port *p = NULL;
164-
struct rhashtable *tbl;
198+
struct net_bridge_vlan_group *vg;
165199
struct net_device *dev;
166200
struct net_bridge *br;
167201
int err;
168202

169203
if (br_vlan_is_master(v)) {
170204
br = v->br;
171205
dev = br->dev;
172-
tbl = &br->vlgrp->vlan_hash;
206+
vg = br->vlgrp;
173207
} else {
174208
p = v->port;
175209
br = p->br;
176210
dev = p->dev;
177-
tbl = &p->vlgrp->vlan_hash;
211+
vg = p->vlgrp;
178212
}
179213

180214
if (p) {
181-
u16 master_flags = flags;
182-
183215
/* Add VLAN to the device filter if it is supported.
184216
* This ensures tagged traffic enters the bridge when
185217
* promiscuous mode is disabled by br_manage_promisc().
@@ -190,57 +222,49 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
190222

191223
/* need to work on the master vlan too */
192224
if (flags & BRIDGE_VLAN_INFO_MASTER) {
193-
master_flags |= BRIDGE_VLAN_INFO_BRENTRY;
194-
err = br_vlan_add(br, v->vid, master_flags);
225+
err = br_vlan_add(br, v->vid, flags |
226+
BRIDGE_VLAN_INFO_BRENTRY);
195227
if (err)
196228
goto out_filt;
197229
}
198230

199-
masterv = br_vlan_find(br->vlgrp, v->vid);
200-
if (!masterv) {
201-
/* missing global ctx, create it now */
202-
err = br_vlan_add(br, v->vid, 0);
203-
if (err)
204-
goto out_filt;
205-
masterv = br_vlan_find(br->vlgrp, v->vid);
206-
WARN_ON(!masterv);
207-
}
208-
atomic_inc(&masterv->refcnt);
231+
masterv = br_vlan_get_master(br, v->vid);
232+
if (!masterv)
233+
goto out_filt;
209234
v->brvlan = masterv;
210235
}
211236

212-
/* Add the dev mac only if it's a usable vlan */
237+
/* Add the dev mac and count the vlan only if it's usable */
213238
if (br_vlan_should_use(v)) {
214239
err = br_fdb_insert(br, p, dev->dev_addr, v->vid);
215240
if (err) {
216241
br_err(br, "failed insert local address into bridge forwarding table\n");
217242
goto out_filt;
218243
}
244+
vg->num_vlans++;
219245
}
220246

221-
err = rhashtable_lookup_insert_fast(tbl, &v->vnode, br_vlan_rht_params);
247+
err = rhashtable_lookup_insert_fast(&vg->vlan_hash, &v->vnode,
248+
br_vlan_rht_params);
222249
if (err)
223250
goto out_fdb_insert;
224251

225252
__vlan_add_list(v);
226253
__vlan_add_flags(v, flags);
227-
if (br_vlan_is_master(v)) {
228-
if (br_vlan_is_brentry(v))
229-
br->vlgrp->num_vlans++;
230-
} else {
231-
p->vlgrp->num_vlans++;
232-
}
233254
out:
234255
return err;
235256

236257
out_fdb_insert:
237-
br_fdb_find_delete_local(br, p, br->dev->dev_addr, v->vid);
258+
if (br_vlan_should_use(v)) {
259+
br_fdb_find_delete_local(br, p, dev->dev_addr, v->vid);
260+
vg->num_vlans--;
261+
}
238262

239263
out_filt:
240264
if (p) {
241265
__vlan_vid_del(dev, br, v->vid);
242266
if (masterv) {
243-
atomic_dec(&masterv->refcnt);
267+
br_vlan_put_master(masterv);
244268
v->brvlan = NULL;
245269
}
246270
}
@@ -253,15 +277,12 @@ static int __vlan_del(struct net_bridge_vlan *v)
253277
struct net_bridge_vlan *masterv = v;
254278
struct net_bridge_vlan_group *vg;
255279
struct net_bridge_port *p = NULL;
256-
struct net_bridge *br;
257280
int err = 0;
258281

259282
if (br_vlan_is_master(v)) {
260-
br = v->br;
261283
vg = v->br->vlgrp;
262284
} else {
263285
p = v->port;
264-
br = p->br;
265286
vg = v->port->vlgrp;
266287
masterv = v->brvlan;
267288
}
@@ -273,13 +294,9 @@ static int __vlan_del(struct net_bridge_vlan *v)
273294
goto out;
274295
}
275296

276-
if (br_vlan_is_master(v)) {
277-
if (br_vlan_is_brentry(v)) {
278-
v->flags &= ~BRIDGE_VLAN_INFO_BRENTRY;
279-
br->vlgrp->num_vlans--;
280-
}
281-
} else {
282-
p->vlgrp->num_vlans--;
297+
if (br_vlan_should_use(v)) {
298+
v->flags &= ~BRIDGE_VLAN_INFO_BRENTRY;
299+
vg->num_vlans--;
283300
}
284301

285302
if (masterv != v) {
@@ -289,12 +306,7 @@ static int __vlan_del(struct net_bridge_vlan *v)
289306
kfree_rcu(v, rcu);
290307
}
291308

292-
if (atomic_dec_and_test(&masterv->refcnt)) {
293-
rhashtable_remove_fast(&masterv->br->vlgrp->vlan_hash,
294-
&masterv->vnode, br_vlan_rht_params);
295-
__vlan_del_list(masterv);
296-
kfree_rcu(masterv, rcu);
297-
}
309+
br_vlan_put_master(masterv);
298310
out:
299311
return err;
300312
}

0 commit comments

Comments
 (0)