@@ -111,12 +111,12 @@ static void __vlan_add_list(struct net_bridge_vlan *v)
111
111
else
112
112
break ;
113
113
}
114
- list_add (& v -> vlist , hpos );
114
+ list_add_rcu (& v -> vlist , hpos );
115
115
}
116
116
117
117
static void __vlan_del_list (struct net_bridge_vlan * v )
118
118
{
119
- list_del (& v -> vlist );
119
+ list_del_rcu (& v -> vlist );
120
120
}
121
121
122
122
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,
146
146
return err ;
147
147
}
148
148
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
+
149
183
/* This is the shared VLAN add function which works for both ports and bridge
150
184
* devices. There are four possible calls to this function in terms of the
151
185
* vlan entry type:
@@ -161,25 +195,23 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
161
195
{
162
196
struct net_bridge_vlan * masterv = NULL ;
163
197
struct net_bridge_port * p = NULL ;
164
- struct rhashtable * tbl ;
198
+ struct net_bridge_vlan_group * vg ;
165
199
struct net_device * dev ;
166
200
struct net_bridge * br ;
167
201
int err ;
168
202
169
203
if (br_vlan_is_master (v )) {
170
204
br = v -> br ;
171
205
dev = br -> dev ;
172
- tbl = & br -> vlgrp -> vlan_hash ;
206
+ vg = br -> vlgrp ;
173
207
} else {
174
208
p = v -> port ;
175
209
br = p -> br ;
176
210
dev = p -> dev ;
177
- tbl = & p -> vlgrp -> vlan_hash ;
211
+ vg = p -> vlgrp ;
178
212
}
179
213
180
214
if (p ) {
181
- u16 master_flags = flags ;
182
-
183
215
/* Add VLAN to the device filter if it is supported.
184
216
* This ensures tagged traffic enters the bridge when
185
217
* promiscuous mode is disabled by br_manage_promisc().
@@ -190,57 +222,49 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
190
222
191
223
/* need to work on the master vlan too */
192
224
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 );
195
227
if (err )
196
228
goto out_filt ;
197
229
}
198
230
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 ;
209
234
v -> brvlan = masterv ;
210
235
}
211
236
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 */
213
238
if (br_vlan_should_use (v )) {
214
239
err = br_fdb_insert (br , p , dev -> dev_addr , v -> vid );
215
240
if (err ) {
216
241
br_err (br , "failed insert local address into bridge forwarding table\n" );
217
242
goto out_filt ;
218
243
}
244
+ vg -> num_vlans ++ ;
219
245
}
220
246
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 );
222
249
if (err )
223
250
goto out_fdb_insert ;
224
251
225
252
__vlan_add_list (v );
226
253
__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
- }
233
254
out :
234
255
return err ;
235
256
236
257
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
+ }
238
262
239
263
out_filt :
240
264
if (p ) {
241
265
__vlan_vid_del (dev , br , v -> vid );
242
266
if (masterv ) {
243
- atomic_dec ( & masterv -> refcnt );
267
+ br_vlan_put_master ( masterv );
244
268
v -> brvlan = NULL ;
245
269
}
246
270
}
@@ -253,15 +277,12 @@ static int __vlan_del(struct net_bridge_vlan *v)
253
277
struct net_bridge_vlan * masterv = v ;
254
278
struct net_bridge_vlan_group * vg ;
255
279
struct net_bridge_port * p = NULL ;
256
- struct net_bridge * br ;
257
280
int err = 0 ;
258
281
259
282
if (br_vlan_is_master (v )) {
260
- br = v -> br ;
261
283
vg = v -> br -> vlgrp ;
262
284
} else {
263
285
p = v -> port ;
264
- br = p -> br ;
265
286
vg = v -> port -> vlgrp ;
266
287
masterv = v -> brvlan ;
267
288
}
@@ -273,13 +294,9 @@ static int __vlan_del(struct net_bridge_vlan *v)
273
294
goto out ;
274
295
}
275
296
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 -- ;
283
300
}
284
301
285
302
if (masterv != v ) {
@@ -289,12 +306,7 @@ static int __vlan_del(struct net_bridge_vlan *v)
289
306
kfree_rcu (v , rcu );
290
307
}
291
308
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 );
298
310
out :
299
311
return err ;
300
312
}
0 commit comments