40
40
#include <linux/skbuff.h>
41
41
#include <linux/netlink.h>
42
42
#include <linux/init.h>
43
+ #include <linux/list.h>
44
+ #include <linux/rcupdate.h>
43
45
44
46
#include <net/ip.h>
45
47
#include <net/protocol.h>
52
54
53
55
struct fib_rule
54
56
{
55
- struct fib_rule * r_next ;
57
+ struct hlist_node hlist ;
56
58
atomic_t r_clntref ;
57
59
u32 r_preference ;
58
60
unsigned char r_table ;
@@ -75,6 +77,7 @@ struct fib_rule
75
77
#endif
76
78
char r_ifname [IFNAMSIZ ];
77
79
int r_dead ;
80
+ struct rcu_head rcu ;
78
81
};
79
82
80
83
static struct fib_rule default_rule = {
@@ -85,31 +88,31 @@ static struct fib_rule default_rule = {
85
88
};
86
89
87
90
static struct fib_rule main_rule = {
88
- .r_next = & default_rule ,
89
91
.r_clntref = ATOMIC_INIT (2 ),
90
92
.r_preference = 0x7FFE ,
91
93
.r_table = RT_TABLE_MAIN ,
92
94
.r_action = RTN_UNICAST ,
93
95
};
94
96
95
97
static struct fib_rule local_rule = {
96
- .r_next = & main_rule ,
97
98
.r_clntref = ATOMIC_INIT (2 ),
98
99
.r_table = RT_TABLE_LOCAL ,
99
100
.r_action = RTN_UNICAST ,
100
101
};
101
102
102
- static struct fib_rule * fib_rules = & local_rule ;
103
- static DEFINE_RWLOCK (fib_rules_lock );
103
+ struct hlist_head fib_rules ;
104
+
105
+ /* writer func called from netlink -- rtnl_sem hold*/
104
106
105
107
int inet_rtm_delrule (struct sk_buff * skb , struct nlmsghdr * nlh , void * arg )
106
108
{
107
109
struct rtattr * * rta = arg ;
108
110
struct rtmsg * rtm = NLMSG_DATA (nlh );
109
- struct fib_rule * r , * * rp ;
111
+ struct fib_rule * r ;
112
+ struct hlist_node * node ;
110
113
int err = - ESRCH ;
111
114
112
- for ( rp = & fib_rules ; ( r = * rp ) != NULL ; rp = & r -> r_next ) {
115
+ hlist_for_each_entry ( r , node , & fib_rules , hlist ) {
113
116
if ((!rta [RTA_SRC - 1 ] || memcmp (RTA_DATA (rta [RTA_SRC - 1 ]), & r -> r_src , 4 ) == 0 ) &&
114
117
rtm -> rtm_src_len == r -> r_src_len &&
115
118
rtm -> rtm_dst_len == r -> r_dst_len &&
@@ -126,10 +129,8 @@ int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
126
129
if (r == & local_rule )
127
130
break ;
128
131
129
- write_lock_bh (& fib_rules_lock );
130
- * rp = r -> r_next ;
132
+ hlist_del_rcu (& r -> hlist );
131
133
r -> r_dead = 1 ;
132
- write_unlock_bh (& fib_rules_lock );
133
134
fib_rule_put (r );
134
135
err = 0 ;
135
136
break ;
@@ -150,21 +151,30 @@ static struct fib_table *fib_empty_table(void)
150
151
return NULL ;
151
152
}
152
153
154
+ static inline void fib_rule_put_rcu (struct rcu_head * head )
155
+ {
156
+ struct fib_rule * r = container_of (head , struct fib_rule , rcu );
157
+ kfree (r );
158
+ }
159
+
153
160
void fib_rule_put (struct fib_rule * r )
154
161
{
155
162
if (atomic_dec_and_test (& r -> r_clntref )) {
156
163
if (r -> r_dead )
157
- kfree ( r );
164
+ call_rcu ( & r -> rcu , fib_rule_put_rcu );
158
165
else
159
166
printk ("Freeing alive rule %p\n" , r );
160
167
}
161
168
}
162
169
170
+ /* writer func called from netlink -- rtnl_sem hold*/
171
+
163
172
int inet_rtm_newrule (struct sk_buff * skb , struct nlmsghdr * nlh , void * arg )
164
173
{
165
174
struct rtattr * * rta = arg ;
166
175
struct rtmsg * rtm = NLMSG_DATA (nlh );
167
- struct fib_rule * r , * new_r , * * rp ;
176
+ struct fib_rule * r , * new_r , * last = NULL ;
177
+ struct hlist_node * node = NULL ;
168
178
unsigned char table_id ;
169
179
170
180
if (rtm -> rtm_src_len > 32 || rtm -> rtm_dst_len > 32 ||
@@ -188,6 +198,7 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
188
198
if (!new_r )
189
199
return - ENOMEM ;
190
200
memset (new_r , 0 , sizeof (* new_r ));
201
+
191
202
if (rta [RTA_SRC - 1 ])
192
203
memcpy (& new_r -> r_src , RTA_DATA (rta [RTA_SRC - 1 ]), 4 );
193
204
if (rta [RTA_DST - 1 ])
@@ -220,28 +231,28 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
220
231
if (rta [RTA_FLOW - 1 ])
221
232
memcpy (& new_r -> r_tclassid , RTA_DATA (rta [RTA_FLOW - 1 ]), 4 );
222
233
#endif
234
+ r = container_of (fib_rules .first , struct fib_rule , hlist );
223
235
224
- rp = & fib_rules ;
225
236
if (!new_r -> r_preference ) {
226
- r = fib_rules ;
227
- if (r && (r = r -> r_next ) != NULL ) {
228
- rp = & fib_rules -> r_next ;
237
+ if (r && r -> hlist .next != NULL ) {
238
+ r = container_of (r -> hlist .next , struct fib_rule , hlist );
229
239
if (r -> r_preference )
230
240
new_r -> r_preference = r -> r_preference - 1 ;
231
241
}
232
242
}
233
243
234
- while ( ( r = * rp ) != NULL ) {
244
+ hlist_for_each_entry ( r , node , & fib_rules , hlist ) {
235
245
if (r -> r_preference > new_r -> r_preference )
236
246
break ;
237
- rp = & r -> r_next ;
247
+ last = r ;
238
248
}
239
-
240
- new_r -> r_next = r ;
241
249
atomic_inc (& new_r -> r_clntref );
242
- write_lock_bh (& fib_rules_lock );
243
- * rp = new_r ;
244
- write_unlock_bh (& fib_rules_lock );
250
+
251
+ if (last )
252
+ hlist_add_after_rcu (& last -> hlist , & new_r -> hlist );
253
+ else
254
+ hlist_add_before_rcu (& new_r -> hlist , & r -> hlist );
255
+
245
256
return 0 ;
246
257
}
247
258
@@ -254,30 +265,30 @@ u32 fib_rules_tclass(struct fib_result *res)
254
265
}
255
266
#endif
256
267
268
+ /* callers should hold rtnl semaphore */
257
269
258
270
static void fib_rules_detach (struct net_device * dev )
259
271
{
272
+ struct hlist_node * node ;
260
273
struct fib_rule * r ;
261
274
262
- for (r = fib_rules ; r ; r = r -> r_next ) {
263
- if (r -> r_ifindex == dev -> ifindex ) {
264
- write_lock_bh (& fib_rules_lock );
275
+ hlist_for_each_entry (r , node , & fib_rules , hlist ) {
276
+ if (r -> r_ifindex == dev -> ifindex )
265
277
r -> r_ifindex = -1 ;
266
- write_unlock_bh (& fib_rules_lock );
267
- }
278
+
268
279
}
269
280
}
270
281
282
+ /* callers should hold rtnl semaphore */
283
+
271
284
static void fib_rules_attach (struct net_device * dev )
272
285
{
286
+ struct hlist_node * node ;
273
287
struct fib_rule * r ;
274
288
275
- for (r = fib_rules ; r ; r = r -> r_next ) {
276
- if (r -> r_ifindex == -1 && strcmp (dev -> name , r -> r_ifname ) == 0 ) {
277
- write_lock_bh (& fib_rules_lock );
289
+ hlist_for_each_entry (r , node , & fib_rules , hlist ) {
290
+ if (r -> r_ifindex == -1 && strcmp (dev -> name , r -> r_ifname ) == 0 )
278
291
r -> r_ifindex = dev -> ifindex ;
279
- write_unlock_bh (& fib_rules_lock );
280
- }
281
292
}
282
293
}
283
294
@@ -286,14 +297,17 @@ int fib_lookup(const struct flowi *flp, struct fib_result *res)
286
297
int err ;
287
298
struct fib_rule * r , * policy ;
288
299
struct fib_table * tb ;
300
+ struct hlist_node * node ;
289
301
290
302
u32 daddr = flp -> fl4_dst ;
291
303
u32 saddr = flp -> fl4_src ;
292
304
293
305
FRprintk ("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u " ,
294
306
NIPQUAD (flp -> fl4_dst ), NIPQUAD (flp -> fl4_src ));
295
- read_lock (& fib_rules_lock );
296
- for (r = fib_rules ; r ; r = r -> r_next ) {
307
+
308
+ rcu_read_lock ();
309
+
310
+ hlist_for_each_entry_rcu (r , node , & fib_rules , hlist ) {
297
311
if (((saddr ^r -> r_src ) & r -> r_srcmask ) ||
298
312
((daddr ^r -> r_dst ) & r -> r_dstmask ) ||
299
313
(r -> r_tos && r -> r_tos != flp -> fl4_tos ) ||
@@ -309,14 +323,14 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action);
309
323
policy = r ;
310
324
break ;
311
325
case RTN_UNREACHABLE :
312
- read_unlock ( & fib_rules_lock );
326
+ rcu_read_unlock ( );
313
327
return - ENETUNREACH ;
314
328
default :
315
329
case RTN_BLACKHOLE :
316
- read_unlock ( & fib_rules_lock );
330
+ rcu_read_unlock ( );
317
331
return - EINVAL ;
318
332
case RTN_PROHIBIT :
319
- read_unlock ( & fib_rules_lock );
333
+ rcu_read_unlock ( );
320
334
return - EACCES ;
321
335
}
322
336
@@ -327,16 +341,16 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action);
327
341
res -> r = policy ;
328
342
if (policy )
329
343
atomic_inc (& policy -> r_clntref );
330
- read_unlock ( & fib_rules_lock );
344
+ rcu_read_unlock ( );
331
345
return 0 ;
332
346
}
333
347
if (err < 0 && err != - EAGAIN ) {
334
- read_unlock ( & fib_rules_lock );
348
+ rcu_read_unlock ( );
335
349
return err ;
336
350
}
337
351
}
338
352
FRprintk ("FAILURE\n" );
339
- read_unlock ( & fib_rules_lock );
353
+ rcu_read_unlock ( );
340
354
return - ENETUNREACH ;
341
355
}
342
356
@@ -414,26 +428,35 @@ static __inline__ int inet_fill_rule(struct sk_buff *skb,
414
428
return -1 ;
415
429
}
416
430
431
+ /* callers should hold rtnl semaphore */
432
+
417
433
int inet_dump_rules (struct sk_buff * skb , struct netlink_callback * cb )
418
434
{
419
- int idx ;
435
+ int idx = 0 ;
420
436
int s_idx = cb -> args [0 ];
421
437
struct fib_rule * r ;
438
+ struct hlist_node * node ;
439
+
440
+ rcu_read_lock ();
441
+ hlist_for_each_entry (r , node , & fib_rules , hlist ) {
422
442
423
- read_lock (& fib_rules_lock );
424
- for (r = fib_rules , idx = 0 ; r ; r = r -> r_next , idx ++ ) {
425
443
if (idx < s_idx )
426
444
continue ;
427
445
if (inet_fill_rule (skb , r , cb , NLM_F_MULTI ) < 0 )
428
446
break ;
447
+ idx ++ ;
429
448
}
430
- read_unlock ( & fib_rules_lock );
449
+ rcu_read_unlock ( );
431
450
cb -> args [0 ] = idx ;
432
451
433
452
return skb -> len ;
434
453
}
435
454
436
455
void __init fib_rules_init (void )
437
456
{
457
+ INIT_HLIST_HEAD (& fib_rules );
458
+ hlist_add_head (& local_rule .hlist , & fib_rules );
459
+ hlist_add_after (& local_rule .hlist , & main_rule .hlist );
460
+ hlist_add_after (& main_rule .hlist , & default_rule .hlist );
438
461
register_netdevice_notifier (& fib_rules_notifier );
439
462
}
0 commit comments