00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
#include <linux/config.h>
00019
#include <asm/uaccess.h>
00020
#include <asm/system.h>
00021
#include <asm/bitops.h>
00022
#include <linux/types.h>
00023
#include <linux/kernel.h>
00024
#include <linux/sched.h>
00025
#include <linux/mm.h>
00026
#include <linux/string.h>
00027
#include <linux/socket.h>
00028
#include <linux/sockios.h>
00029
#include <linux/errno.h>
00030
#include <linux/in.h>
00031
#include <linux/inet.h>
00032
#include <linux/netdevice.h>
00033
#include <linux/if_arp.h>
00034
#include <linux/proc_fs.h>
00035
#include <linux/skbuff.h>
00036
#include <linux/netlink.h>
00037
#include <linux/init.h>
00038
00039
#include <net/ip.h>
00040
#include <net/protocol.h>
00041
#include <net/route.h>
00042
#include <net/tcp.h>
00043
#include <net/sock.h>
00044
#include <net/ip_fib.h>
00045
00046 #define FTprint(a...)
00047
00048
00049
00050
00051 static kmem_cache_t *
fn_hash_kmem;
00052
00053
00054
00055
00056
00057
00058
00059
00060 typedef struct {
00061 u32 datum;
00062 }
fn_key_t;
00063
00064 typedef struct {
00065 u32 datum;
00066 }
fn_hash_idx_t;
00067
00072 struct fib_node
00073 {
00074 struct fib_node *
fn_next;
00075 struct fib_info *
fn_info;
00076 #define FIB_INFO(f) ((f)->fn_info)
00077 fn_key_t fn_key;
00078 u8
fn_tos;
00079 u8
fn_type;
00080 u8
fn_scope;
00081 u8
fn_state;
00082 };
00083
00084 #define FN_S_ZOMBIE 1
00085 #define FN_S_ACCESSED 2
00086
00087 static int fib_hash_zombies;
00088
00099 struct fn_zone
00100 {
00101 struct fn_zone *
fz_next;
00102 struct fib_node **
fz_hash;
00103 int fz_nent;
00104
00105 int fz_divisor;
00106 u32
fz_hashmask;
00107 #define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
00108
00109 int fz_order;
00110 u32
fz_mask;
00111 #define FZ_MASK(fz) ((fz)->fz_mask)
00112
};
00113
00114
00115
00116
00117
00118 struct fn_hash
00119 {
00120 struct fn_zone *
fn_zones[33];
00121 struct fn_zone *
fn_zone_list;
00122 };
00123
00124 static __inline__
fn_hash_idx_t fn_hash(
fn_key_t key,
struct fn_zone *fz)
00125 {
00126 u32 h = ntohl(key.
datum)>>(32 - fz->
fz_order);
00127 h ^= (h>>20);
00128 h ^= (h>>10);
00129 h ^= (h>>5);
00130 h &=
FZ_HASHMASK(fz);
00131
return *(
fn_hash_idx_t*)&h;
00132 }
00133
00134 #define fz_key_0(key) ((key).datum = 0)
00135 #define fz_prefix(key,fz) ((key).datum)
00136
00137 static __inline__
fn_key_t fz_key(u32 dst,
struct fn_zone *fz)
00138 {
00139
fn_key_t k;
00140 k.
datum = dst &
FZ_MASK(fz);
00141
return k;
00142 }
00143
00144 static __inline__
struct fib_node **
fz_chain_p(
fn_key_t key,
struct fn_zone *fz)
00145 {
00146
return &fz->
fz_hash[
fn_hash(key, fz).
datum];
00147 }
00148
00149 static __inline__
struct fib_node *
fz_chain(
fn_key_t key,
struct fn_zone *fz)
00150 {
00151
return fz->
fz_hash[
fn_hash(key, fz).
datum];
00152 }
00153
00154 extern __inline__
int fn_key_eq(
fn_key_t a,
fn_key_t b)
00155 {
00156
return a.
datum == b.
datum;
00157 }
00158
00159 extern __inline__
int fn_key_leq(
fn_key_t a,
fn_key_t b)
00160 {
00161
return a.
datum <= b.
datum;
00162 }
00163
00164 static rwlock_t
fib_hash_lock = RW_LOCK_UNLOCKED;
00165
00166 #define FZ_MAX_DIVISOR ((PAGE_SIZE<<MAX_ORDER) / sizeof(struct fib_node *))
00167
00168 static struct fib_node **
fz_hash_alloc(
int divisor)
00169 {
00170
unsigned long size = divisor *
sizeof(
struct fib_node *);
00171
00172
if (divisor <= 1024) {
00173
return kmalloc(size, GFP_KERNEL);
00174 }
else {
00175
return (
struct fib_node **)
00176 __get_free_pages(GFP_KERNEL, get_order(size));
00177 }
00178 }
00179
00180
00181 static __inline__
void fn_rebuild_zone(
struct fn_zone *fz,
00182
struct fib_node **old_ht,
00183
int old_divisor)
00184 {
00185
int i;
00186
struct fib_node *f, **fp, *next;
00187
00188
for (i=0; i<old_divisor; i++) {
00189
for (f=old_ht[i]; f; f=next) {
00190 next = f->fn_next;
00191
for (fp =
fz_chain_p(f->fn_key, fz);
00192 *fp &&
fn_key_leq((*fp)->fn_key, f->fn_key);
00193 fp = &(*fp)->fn_next)
00194 ;
00195 f->fn_next = *fp;
00196 *fp = f;
00197 }
00198 }
00199 }
00200
00201 static void fz_hash_free(
struct fib_node **hash,
int divisor)
00202 {
00203
if (divisor <= 1024)
00204 kfree(hash);
00205
else
00206 free_pages((
unsigned long) hash,
00207 get_order(divisor *
sizeof(
struct fib_node *)));
00208 }
00209
00210 static void fn_rehash_zone(
struct fn_zone *fz)
00211 {
00212
struct fib_node **ht, **old_ht;
00213
int old_divisor, new_divisor;
00214 u32 new_hashmask;
00215
00216 old_divisor = fz->
fz_divisor;
00217
00218
switch (old_divisor) {
00219
case 16:
00220 new_divisor = 256;
00221
break;
00222
case 256:
00223 new_divisor = 1024;
00224
break;
00225
default:
00226
if ((old_divisor << 1) >
FZ_MAX_DIVISOR) {
00227 printk(KERN_CRIT
"route.c: bad divisor %d!\n", old_divisor);
00228
return;
00229 }
00230 new_divisor = (old_divisor << 1);
00231
break;
00232 }
00233
00234 new_hashmask = (new_divisor - 1);
00235
00236
#if RT_CACHE_DEBUG >= 2
00237
printk(
"fn_rehash_zone: hash for zone %d grows from %d\n", fz->
fz_order, old_divisor);
00238
#endif
00239
00240 ht =
fz_hash_alloc(new_divisor);
00241
00242
if (ht) {
00243 memset(ht, 0, new_divisor*
sizeof(
struct fib_node*));
00244
00245 write_lock_bh(&
fib_hash_lock);
00246 old_ht = fz->
fz_hash;
00247 fz->
fz_hash = ht;
00248 fz->
fz_hashmask = new_hashmask;
00249 fz->
fz_divisor = new_divisor;
00250
fn_rebuild_zone(fz, old_ht, old_divisor);
00251 write_unlock_bh(&
fib_hash_lock);
00252
00253
fz_hash_free(old_ht, old_divisor);
00254 }
00255 }
00256
00257 static void fn_free_node(
struct fib_node * f)
00258 {
00259
fib_release_info(
FIB_INFO(f));
00260 kmem_cache_free(
fn_hash_kmem, f);
00261 }
00262
00263
00264
static struct fn_zone *
00265 fn_new_zone(
struct fn_hash *table,
int z)
00266 {
00267
int i;
00268
struct fn_zone *fz = kmalloc(
sizeof(
struct fn_zone), GFP_KERNEL);
00269
if (!fz)
00270
return NULL;
00271
00272 memset(fz, 0,
sizeof(
struct fn_zone));
00273
if (z) {
00274 fz->fz_divisor = 16;
00275 }
else {
00276 fz->fz_divisor = 1;
00277 }
00278 fz->fz_hashmask = (fz->fz_divisor - 1);
00279 fz->fz_hash =
fz_hash_alloc(fz->fz_divisor);
00280
if (!fz->fz_hash) {
00281 kfree(fz);
00282
return NULL;
00283 }
00284 memset(fz->fz_hash, 0, fz->fz_divisor*
sizeof(
struct fib_node*));
00285 fz->fz_order = z;
00286 fz->fz_mask =
inet_make_mask(z);
00287
00288
00289
for (i=z+1; i<=32; i++)
00290
if (table->
fn_zones[i])
00291
break;
00292 write_lock_bh(&
fib_hash_lock);
00293
if (i>32) {
00294
00295 fz->fz_next = table->
fn_zone_list;
00296 table->
fn_zone_list = fz;
00297 }
else {
00298 fz->
fz_next = table->
fn_zones[i]->
fz_next;
00299 table->
fn_zones[i]->
fz_next = fz;
00300 }
00301 table->
fn_zones[z] = fz;
00302 write_unlock_bh(&
fib_hash_lock);
00303
return fz;
00304 }
00305
00306
static int
00307 fn_hash_lookup(
struct fib_table *tb,
const struct rt_key *key,
struct fib_result *res)
00308 {
00309
int err;
00310
struct fn_zone *fz;
00311
struct fn_hash *t = (
struct fn_hash*)tb->
tb_data;
00312
00313 read_lock(&
fib_hash_lock);
00314
for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
00315
struct fib_node *f;
00316
fn_key_t k =
fz_key(key->
dst, fz);
00317
00318
for (f =
fz_chain(k, fz); f; f = f->fn_next) {
00319
if (!
fn_key_eq(k, f->fn_key)) {
00320
if (
fn_key_leq(k, f->fn_key))
00321
break;
00322
else
00323
continue;
00324 }
00325
#ifdef CONFIG_IP_ROUTE_TOS
00326
if (f->fn_tos && f->fn_tos != key->
tos)
00327
continue;
00328
#endif
00329
f->fn_state |=
FN_S_ACCESSED;
00330
00331
if (f->fn_state&
FN_S_ZOMBIE)
00332
continue;
00333
if (f->fn_scope < key->
scope)
00334
continue;
00335
00336 err =
fib_semantic_match(f->fn_type,
FIB_INFO(f), key, res);
00337
if (err == 0) {
00338 res->
type = f->fn_type;
00339 res->
scope = f->fn_scope;
00340 res->
prefixlen = fz->fz_order;
00341
goto out;
00342 }
00343
if (err < 0)
00344
goto out;
00345 }
00346 }
00347 err = 1;
00348 out:
00349 read_unlock(&
fib_hash_lock);
00350
return err;
00351 }
00352
00353 static int fn_hash_last_dflt=-1;
00354
00355 static int fib_detect_death(
struct fib_info *fi,
int order,
00356
struct fib_info **last_resort,
int *last_idx)
00357 {
00358
struct neighbour *n;
00359
int state =
NUD_NONE;
00360
00361 n =
neigh_lookup(&
arp_tbl, &fi->
fib_nh[0].
nh_gw, fi->fib_dev);
00362
if (n) {
00363 state = n->nud_state;
00364
neigh_release(n);
00365 }
00366
if (state==
NUD_REACHABLE)
00367
return 0;
00368
if ((state&
NUD_VALID) && order !=
fn_hash_last_dflt)
00369
return 0;
00370
if ((state&
NUD_VALID) ||
00371 (*last_idx<0 && order >
fn_hash_last_dflt)) {
00372 *last_resort = fi;
00373 *last_idx = order;
00374 }
00375
return 1;
00376 }
00377
00378
static void
00379 fn_hash_select_default(
struct fib_table *tb,
const struct rt_key *key,
struct fib_result *res)
00380 {
00381
int order, last_idx;
00382
struct fib_node *f;
00383
struct fib_info *fi = NULL;
00384
struct fib_info *last_resort;
00385
struct fn_hash *t = (
struct fn_hash*)tb->
tb_data;
00386
struct fn_zone *fz = t->fn_zones[0];
00387
00388
if (fz == NULL)
00389
return;
00390
00391 last_idx = -1;
00392 last_resort = NULL;
00393 order = -1;
00394
00395 read_lock(&
fib_hash_lock);
00396
for (f = fz->fz_hash[0]; f; f = f->fn_next) {
00397
struct fib_info *next_fi =
FIB_INFO(f);
00398
00399
if ((f->fn_state&
FN_S_ZOMBIE) ||
00400 f->fn_scope != res->
scope ||
00401 f->fn_type != RTN_UNICAST)
00402
continue;
00403
00404
if (next_fi->fib_priority > res->
fi->
fib_priority)
00405
break;
00406
if (!next_fi->fib_nh[0].nh_gw || next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
00407
continue;
00408 f->fn_state |=
FN_S_ACCESSED;
00409
00410
if (fi == NULL) {
00411
if (next_fi != res->
fi)
00412
break;
00413 }
else if (!
fib_detect_death(fi, order, &last_resort, &last_idx)) {
00414
if (res->
fi)
00415
fib_info_put(res->
fi);
00416 res->
fi = fi;
00417 atomic_inc(&fi->fib_clntref);
00418
fn_hash_last_dflt = order;
00419
goto out;
00420 }
00421 fi = next_fi;
00422 order++;
00423 }
00424
00425
if (order<=0 || fi==NULL) {
00426
fn_hash_last_dflt = -1;
00427
goto out;
00428 }
00429
00430
if (!
fib_detect_death(fi, order, &last_resort, &last_idx)) {
00431
if (res->
fi)
00432
fib_info_put(res->
fi);
00433 res->
fi = fi;
00434 atomic_inc(&fi->fib_clntref);
00435
fn_hash_last_dflt = order;
00436
goto out;
00437 }
00438
00439
if (last_idx >= 0) {
00440
if (res->
fi)
00441
fib_info_put(res->
fi);
00442 res->
fi = last_resort;
00443
if (last_resort)
00444 atomic_inc(&last_resort->fib_clntref);
00445 }
00446
fn_hash_last_dflt = last_idx;
00447 out:
00448 read_unlock(&
fib_hash_lock);
00449 }
00450
00451 #define FIB_SCAN(f, fp) \
00452
for ( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
00453
00454 #define FIB_SCAN_KEY(f, fp, key) \
00455
for ( ; ((f) = *(fp)) != NULL && fn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
00456
00457
#ifndef CONFIG_IP_ROUTE_TOS
00458 #define FIB_SCAN_TOS(f, fp, key, tos) FIB_SCAN_KEY(f, fp, key)
00459
#else
00460
#define FIB_SCAN_TOS(f, fp, key, tos) \
00461
for ( ; ((f) = *(fp)) != NULL && fn_key_eq((f)->fn_key, (key)) && \
00462
(f)->fn_tos == (tos) ; (fp) = &(f)->fn_next)
00463
#endif
00464
00465
00466
static void rtmsg_fib(
int,
struct fib_node*,
int,
int,
00467
struct nlmsghdr *n,
00468
struct netlink_skb_parms *);
00469
00470
static int
00471 fn_hash_insert(
struct fib_table *tb,
struct rtmsg *r,
struct kern_rta *rta,
00472
struct nlmsghdr *n,
struct netlink_skb_parms *req)
00473 {
00474
struct fn_hash *table = (
struct fn_hash*)tb->
tb_data;
00475
struct fib_node *new_f, *f, **fp, **del_fp;
00476
struct fn_zone *fz;
00477
struct fib_info *fi;
00478
00479
int z = r->rtm_dst_len;
00480
int type = r->rtm_type;
00481
#ifdef CONFIG_IP_ROUTE_TOS
00482
u8 tos = r->rtm_tos;
00483
#endif
00484
fn_key_t key;
00485
int err;
00486
00487
FTprint(
"tb(%d)_insert: %d %08x/%d %d %08x\n", tb->
tb_id, r->rtm_type, rta->
rta_dst ?
00488 *(u32*)rta->
rta_dst : 0, z, rta->
rta_oif ? *rta->
rta_oif : -1,
00489 rta->
rta_prefsrc ? *(u32*)rta->
rta_prefsrc : 0);
00490
if (z > 32)
00491
return -EINVAL;
00492 fz = table->fn_zones[z];
00493
if (!fz && !(fz =
fn_new_zone(table, z)))
00494
return -ENOBUFS;
00495
00496
fz_key_0(key);
00497
if (rta->
rta_dst) {
00498 u32 dst;
00499 memcpy(&dst, rta->
rta_dst, 4);
00500
if (dst & ~
FZ_MASK(fz))
00501
return -EINVAL;
00502 key =
fz_key(dst, fz);
00503 }
00504
00505
if ((fi =
fib_create_info(r, rta, n, &err)) == NULL)
00506
return err;
00507
00508
if (fz->fz_nent > (fz->fz_divisor<<1) &&
00509 fz->fz_divisor <
FZ_MAX_DIVISOR &&
00510 (z==32 || (1<<z) > fz->fz_divisor))
00511
fn_rehash_zone(fz);
00512
00513 fp =
fz_chain_p(key, fz);
00514
00515
00516
00517
00518
00519
FIB_SCAN(f, fp) {
00520
if (
fn_key_leq(key,f->fn_key))
00521
break;
00522 }
00523
00524
#ifdef CONFIG_IP_ROUTE_TOS
00525
00526
00527
00528
FIB_SCAN_KEY(f, fp, key) {
00529
if (f->fn_tos <= tos)
00530
break;
00531 }
00532
#endif
00533
00534 del_fp = NULL;
00535
00536
if (f && (f->fn_state&
FN_S_ZOMBIE) &&
00537
#ifdef CONFIG_IP_ROUTE_TOS
00538
f->fn_tos == tos &&
00539
#endif
00540
fn_key_eq(f->fn_key, key)) {
00541 del_fp = fp;
00542 fp = &f->fn_next;
00543 f = *fp;
00544
goto create;
00545 }
00546
00547
FIB_SCAN_TOS(f, fp, key, tos) {
00548
if (fi->fib_priority <=
FIB_INFO(f)->fib_priority)
00549
break;
00550 }
00551
00552
00553
00554
00555
00556
00557
if (f &&
00558
#ifdef CONFIG_IP_ROUTE_TOS
00559
f->fn_tos == tos &&
00560
#endif
00561
fn_key_eq(f->fn_key, key) &&
00562 fi->fib_priority ==
FIB_INFO(f)->fib_priority) {
00563
struct fib_node **ins_fp;
00564
00565 err = -EEXIST;
00566
if (n->
nlmsg_flags&
NLM_F_EXCL)
00567
goto out;
00568
00569
if (n->
nlmsg_flags&
NLM_F_REPLACE) {
00570 del_fp = fp;
00571 fp = &f->fn_next;
00572 f = *fp;
00573
goto replace;
00574 }
00575
00576 ins_fp = fp;
00577 err = -EEXIST;
00578
00579
FIB_SCAN_TOS(f, fp, key, tos) {
00580
if (fi->fib_priority !=
FIB_INFO(f)->fib_priority)
00581
break;
00582
if (f->fn_type == type && f->fn_scope == r->rtm_scope
00583 &&
FIB_INFO(f) == fi)
00584
goto out;
00585 }
00586
00587
if (!(n->
nlmsg_flags&
NLM_F_APPEND)) {
00588 fp = ins_fp;
00589 f = *fp;
00590 }
00591 }
00592
00593 create:
00594 err = -ENOENT;
00595
if (!(n->
nlmsg_flags&
NLM_F_CREATE))
00596
goto out;
00597
00598 replace:
00599 err = -ENOBUFS;
00600 new_f = kmem_cache_alloc(
fn_hash_kmem, SLAB_KERNEL);
00601
if (new_f == NULL)
00602
goto out;
00603
00604 memset(new_f, 0,
sizeof(
struct fib_node));
00605
00606 new_f->fn_key = key;
00607
#ifdef CONFIG_IP_ROUTE_TOS
00608
new_f->fn_tos = tos;
00609
#endif
00610
new_f->fn_type = type;
00611 new_f->fn_scope = r->rtm_scope;
00612
FIB_INFO(new_f) = fi;
00613
00614
00615
00616
00617
00618 new_f->fn_next = f;
00619 write_lock_bh(&
fib_hash_lock);
00620 *fp = new_f;
00621 write_unlock_bh(&
fib_hash_lock);
00622 fz->fz_nent++;
00623
00624
if (del_fp) {
00625 f = *del_fp;
00626
00627 write_lock_bh(&
fib_hash_lock);
00628 *del_fp = f->fn_next;
00629 write_unlock_bh(&
fib_hash_lock);
00630
00631
if (!(f->fn_state&
FN_S_ZOMBIE))
00632
rtmsg_fib(RTM_DELROUTE, f, z, tb->
tb_id, n, req);
00633
if (f->fn_state&
FN_S_ACCESSED)
00634
rt_cache_flush(-1);
00635
fn_free_node(f);
00636 fz->fz_nent--;
00637 }
else {
00638
rt_cache_flush(-1);
00639 }
00640
rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->
tb_id, n, req);
00641
return 0;
00642
00643 out:
00644
fib_release_info(fi);
00645
return err;
00646 }
00647
00648
00649
static int
00650 fn_hash_delete(
struct fib_table *tb,
struct rtmsg *r,
struct kern_rta *rta,
00651
struct nlmsghdr *n,
struct netlink_skb_parms *req)
00652 {
00653
struct fn_hash *table = (
struct fn_hash*)tb->
tb_data;
00654
struct fib_node **fp, **del_fp, *f;
00655
int z = r->rtm_dst_len;
00656
struct fn_zone *fz;
00657
fn_key_t key;
00658
int matched;
00659
#ifdef CONFIG_IP_ROUTE_TOS
00660
u8 tos = r->rtm_tos;
00661
#endif
00662
00663
FTprint(
"tb(%d)_delete: %d %08x/%d %d\n", tb->
tb_id, r->rtm_type, rta->
rta_dst ?
00664 *(u32*)rta->
rta_dst : 0, z, rta->
rta_oif ? *rta->
rta_oif : -1);
00665
if (z > 32)
00666
return -EINVAL;
00667
if ((fz = table->fn_zones[z]) == NULL)
00668
return -ESRCH;
00669
00670
fz_key_0(key);
00671
if (rta->
rta_dst) {
00672 u32 dst;
00673 memcpy(&dst, rta->
rta_dst, 4);
00674
if (dst & ~
FZ_MASK(fz))
00675
return -EINVAL;
00676 key =
fz_key(dst, fz);
00677 }
00678
00679 fp =
fz_chain_p(key, fz);
00680
00681
00682
FIB_SCAN(f, fp) {
00683
if (
fn_key_eq(f->fn_key, key))
00684
break;
00685
if (
fn_key_leq(key, f->fn_key)) {
00686
return -ESRCH;
00687 }
00688 }
00689
#ifdef CONFIG_IP_ROUTE_TOS
00690
FIB_SCAN_KEY(f, fp, key) {
00691
if (f->fn_tos == tos)
00692
break;
00693 }
00694
#endif
00695
00696 matched = 0;
00697 del_fp = NULL;
00698
FIB_SCAN_TOS(f, fp, key, tos) {
00699
struct fib_info * fi =
FIB_INFO(f);
00700
00701
if (f->fn_state&
FN_S_ZOMBIE) {
00702
return -ESRCH;
00703 }
00704 matched++;
00705
00706
if (del_fp == NULL &&
00707 (!r->rtm_type || f->fn_type == r->rtm_type) &&
00708 (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&
00709 (!r->rtm_protocol || fi->fib_protocol == r->rtm_protocol) &&
00710
fib_nh_match(r, n, rta, fi) == 0)
00711 del_fp = fp;
00712 }
00713
00714
if (del_fp) {
00715 f = *del_fp;
00716
rtmsg_fib(RTM_DELROUTE, f, z, tb->
tb_id, n, req);
00717
00718
if (matched != 1) {
00719 write_lock_bh(&
fib_hash_lock);
00720 *del_fp = f->fn_next;
00721 write_unlock_bh(&
fib_hash_lock);
00722
00723
if (f->fn_state&
FN_S_ACCESSED)
00724
rt_cache_flush(-1);
00725
fn_free_node(f);
00726 fz->fz_nent--;
00727 }
else {
00728 f->fn_state |=
FN_S_ZOMBIE;
00729
if (f->fn_state&
FN_S_ACCESSED) {
00730 f->fn_state &= ~
FN_S_ACCESSED;
00731
rt_cache_flush(-1);
00732 }
00733
if (++
fib_hash_zombies > 128)
00734
fib_flush();
00735 }
00736
00737
return 0;
00738 }
00739
return -ESRCH;
00740 }
00741
00742
extern __inline__
int
00743 fn_flush_list(
struct fib_node ** fp,
int z,
struct fn_hash *table)
00744 {
00745
int found = 0;
00746
struct fib_node *f;
00747
00748
while ((f = *fp) != NULL) {
00749
struct fib_info *fi =
FIB_INFO(f);
00750
00751
if (fi && ((f->fn_state&
FN_S_ZOMBIE) || (fi->fib_flags&RTNH_F_DEAD))) {
00752 write_lock_bh(&
fib_hash_lock);
00753 *fp = f->
fn_next;
00754 write_unlock_bh(&
fib_hash_lock);
00755
00756
fn_free_node(f);
00757 found++;
00758
continue;
00759 }
00760 fp = &f->
fn_next;
00761 }
00762
return found;
00763 }
00764
00765 static int fn_hash_flush(
struct fib_table *tb)
00766 {
00767
struct fn_hash *table = (
struct fn_hash*)tb->
tb_data;
00768
struct fn_zone *fz;
00769
int found = 0;
00770
00771
fib_hash_zombies = 0;
00772
for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {
00773
int i;
00774
int tmp = 0;
00775
for (i=fz->fz_divisor-1; i>=0; i--)
00776 tmp +=
fn_flush_list(&fz->fz_hash[i], fz->fz_order, table);
00777 fz->fz_nent -= tmp;
00778 found += tmp;
00779 }
00780
return found;
00781 }
00782
00783
00784
#ifdef CONFIG_PROC_FS
00785
00786
static int fn_hash_get_info(
struct fib_table *tb,
char *buffer,
int first,
int count)
00787 {
00788
struct fn_hash *table = (
struct fn_hash*)tb->
tb_data;
00789
struct fn_zone *fz;
00790
int pos = 0;
00791
int n = 0;
00792
00793 read_lock(&fib_hash_lock);
00794
for (fz=table->fn_zone_list; fz; fz = fz->fz_next) {
00795
int i;
00796
struct fib_node *f;
00797
int maxslot = fz->fz_divisor;
00798
struct fib_node **fp = fz->fz_hash;
00799
00800
if (fz->fz_nent == 0)
00801
continue;
00802
00803
if (pos + fz->fz_nent <= first) {
00804 pos += fz->fz_nent;
00805
continue;
00806 }
00807
00808
for (i=0; i < maxslot; i++, fp++) {
00809
for (f = *fp; f; f = f->fn_next) {
00810
if (++pos <= first)
00811
continue;
00812
fib_node_get_info(f->fn_type,
00813 f->fn_state&FN_S_ZOMBIE,
00814
FIB_INFO(f),
00815
fz_prefix(f->fn_key, fz),
00816
FZ_MASK(fz), buffer);
00817 buffer += 128;
00818
if (++n >= count)
00819
goto out;
00820 }
00821 }
00822 }
00823 out:
00824 read_unlock(&fib_hash_lock);
00825
return n;
00826 }
00827
#endif
00828
00829
00830
static __inline__
int
00831 fn_hash_dump_bucket(
struct sk_buff *skb,
struct netlink_callback *cb,
00832
struct fib_table *tb,
00833
struct fn_zone *fz,
00834
struct fib_node *f)
00835 {
00836
int i, s_i;
00837
00838 s_i = cb->
args[3];
00839
for (i=0; f; i++, f=f->
fn_next) {
00840
if (i < s_i)
continue;
00841
if (f->fn_state&
FN_S_ZOMBIE)
continue;
00842
if (
fib_dump_info(skb,
NETLINK_CB(cb->
skb).pid, cb->
nlh->
nlmsg_seq,
00843 RTM_NEWROUTE,
00844 tb->
tb_id, (f->fn_state&
FN_S_ZOMBIE) ? 0 : f->fn_type, f->fn_scope,
00845 &f->fn_key, fz->
fz_order, f->fn_tos,
00846 f->fn_info) < 0) {
00847 cb->
args[3] = i;
00848
return -1;
00849 }
00850 }
00851 cb->
args[3] = i;
00852
return skb->
len;
00853 }
00854
00855
static __inline__
int
00856 fn_hash_dump_zone(
struct sk_buff *skb,
struct netlink_callback *cb,
00857
struct fib_table *tb,
00858
struct fn_zone *fz)
00859 {
00860
int h, s_h;
00861
00862 s_h = cb->
args[2];
00863
for (h=0; h < fz->
fz_divisor; h++) {
00864
if (h < s_h)
continue;
00865
if (h > s_h)
00866 memset(&cb->
args[3], 0,
sizeof(cb->
args) - 3*
sizeof(cb->
args[0]));
00867
if (fz->
fz_hash == NULL || fz->
fz_hash[h] == NULL)
00868
continue;
00869
if (
fn_hash_dump_bucket(skb, cb, tb, fz, fz->
fz_hash[h]) < 0) {
00870 cb->
args[2] = h;
00871
return -1;
00872 }
00873 }
00874 cb->
args[2] = h;
00875
return skb->
len;
00876 }
00877
00878 static int fn_hash_dump(
struct fib_table *tb,
struct sk_buff *skb,
struct netlink_callback *cb)
00879 {
00880
int m, s_m;
00881
struct fn_zone *fz;
00882
struct fn_hash *table = (
struct fn_hash*)tb->
tb_data;
00883
00884 s_m = cb->
args[1];
00885 read_lock(&
fib_hash_lock);
00886
for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {
00887
if (m < s_m)
continue;
00888
if (m > s_m)
00889 memset(&cb->
args[2], 0,
sizeof(cb->
args) - 2*
sizeof(cb->
args[0]));
00890
if (
fn_hash_dump_zone(skb, cb, tb, fz) < 0) {
00891 cb->
args[1] = m;
00892 read_unlock(&
fib_hash_lock);
00893
return -1;
00894 }
00895 }
00896 read_unlock(&
fib_hash_lock);
00897 cb->
args[1] = m;
00898
return skb->
len;
00899 }
00900
00901 static void rtmsg_fib(
int event,
struct fib_node* f,
int z,
int tb_id,
00902
struct nlmsghdr *n,
struct netlink_skb_parms *req)
00903 {
00904
struct sk_buff *skb;
00905 u32 pid = req ? req->
pid : 0;
00906
int size =
NLMSG_SPACE(
sizeof(
struct rtmsg)+256);
00907
00908 skb =
alloc_skb(size, GFP_KERNEL);
00909
if (!skb)
00910
return;
00911
00912
if (
fib_dump_info(skb, pid, n->
nlmsg_seq, event, tb_id,
00913 f->
fn_type, f->
fn_scope, &f->
fn_key, z, f->
fn_tos,
00914
FIB_INFO(f)) < 0) {
00915
kfree_skb(skb);
00916
return;
00917 }
00918
NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_ROUTE;
00919
if (n->
nlmsg_flags&
NLM_F_ECHO)
00920 atomic_inc(&skb->users);
00921
netlink_broadcast(
rtnl, skb, pid, RTMGRP_IPV4_ROUTE, GFP_KERNEL);
00922
if (n->
nlmsg_flags&
NLM_F_ECHO)
00923
netlink_unicast(
rtnl, skb, pid, MSG_DONTWAIT);
00924 }
00925
00926
#ifdef CONFIG_IP_MULTIPLE_TABLES
00927
struct fib_table *
fib_hash_init(
int id)
00928 #
else
00929 struct fib_table * __init
fib_hash_init(
int id)
00930 #endif
00931 {
00932
struct fib_table *tb;
00933
00934
if (
fn_hash_kmem == NULL)
00935
fn_hash_kmem = kmem_cache_create(
"ip_fib_hash",
00936
sizeof(
struct fib_node),
00937 0, SLAB_HWCACHE_ALIGN,
00938 NULL, NULL);
00939
00940 tb = kmalloc(
sizeof(
struct fib_table) +
sizeof(
struct fn_hash), GFP_KERNEL);
00941
if (tb == NULL)
00942
return NULL;
00943
00944 tb->
tb_id =
id;
00945 tb->
tb_lookup =
fn_hash_lookup;
00946 tb->
tb_insert =
fn_hash_insert;
00947 tb->
tb_delete =
fn_hash_delete;
00948 tb->
tb_flush =
fn_hash_flush;
00949 tb->
tb_select_default =
fn_hash_select_default;
00950 tb->
tb_dump =
fn_hash_dump;
00951
#ifdef CONFIG_PROC_FS
00952
tb->
tb_get_info = fn_hash_get_info;
00953
#endif
00954
memset(tb->
tb_data, 0,
sizeof(
struct fn_hash));
00955
return tb;
00956 }