at v2.6.18-rc1 822 lines 20 kB view raw
1/* 2 * DECnet An implementation of the DECnet protocol suite for the LINUX 3 * operating system. DECnet is implemented using the BSD Socket 4 * interface as the means of communication with the user level. 5 * 6 * DECnet Routing Forwarding Information Base (Routing Tables) 7 * 8 * Author: Steve Whitehouse <SteveW@ACM.org> 9 * Mostly copied from the IPv4 routing code 10 * 11 * 12 * Changes: 13 * 14 */ 15#include <linux/string.h> 16#include <linux/net.h> 17#include <linux/socket.h> 18#include <linux/sockios.h> 19#include <linux/init.h> 20#include <linux/skbuff.h> 21#include <linux/netlink.h> 22#include <linux/rtnetlink.h> 23#include <linux/proc_fs.h> 24#include <linux/netdevice.h> 25#include <linux/timer.h> 26#include <linux/spinlock.h> 27#include <asm/atomic.h> 28#include <asm/uaccess.h> 29#include <linux/route.h> /* RTF_xxx */ 30#include <net/neighbour.h> 31#include <net/dst.h> 32#include <net/flow.h> 33#include <net/dn.h> 34#include <net/dn_route.h> 35#include <net/dn_fib.h> 36#include <net/dn_neigh.h> 37#include <net/dn_dev.h> 38 39struct dn_zone 40{ 41 struct dn_zone *dz_next; 42 struct dn_fib_node **dz_hash; 43 int dz_nent; 44 int dz_divisor; 45 u32 dz_hashmask; 46#define DZ_HASHMASK(dz) ((dz)->dz_hashmask) 47 int dz_order; 48 __le16 dz_mask; 49#define DZ_MASK(dz) ((dz)->dz_mask) 50}; 51 52struct dn_hash 53{ 54 struct dn_zone *dh_zones[17]; 55 struct dn_zone *dh_zone_list; 56}; 57 58#define dz_key_0(key) ((key).datum = 0) 59#define dz_prefix(key,dz) ((key).datum) 60 61#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\ 62 for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++) 63 64#define endfor_nexthops(fi) } 65 66#define DN_MAX_DIVISOR 1024 67#define DN_S_ZOMBIE 1 68#define DN_S_ACCESSED 2 69 70#define DN_FIB_SCAN(f, fp) \ 71for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next) 72 73#define DN_FIB_SCAN_KEY(f, fp, key) \ 74for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next) 75 76#define RT_TABLE_MIN 1 77 78static DEFINE_RWLOCK(dn_fib_tables_lock); 79struct dn_fib_table *dn_fib_tables[RT_TABLE_MAX + 1]; 80 81static kmem_cache_t *dn_hash_kmem __read_mostly; 82static int dn_fib_hash_zombies; 83 84static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz) 85{ 86 u16 h = dn_ntohs(key.datum)>>(16 - dz->dz_order); 87 h ^= (h >> 10); 88 h ^= (h >> 6); 89 h &= DZ_HASHMASK(dz); 90 return *(dn_fib_idx_t *)&h; 91} 92 93static inline dn_fib_key_t dz_key(__le16 dst, struct dn_zone *dz) 94{ 95 dn_fib_key_t k; 96 k.datum = dst & DZ_MASK(dz); 97 return k; 98} 99 100static inline struct dn_fib_node **dn_chain_p(dn_fib_key_t key, struct dn_zone *dz) 101{ 102 return &dz->dz_hash[dn_hash(key, dz).datum]; 103} 104 105static inline struct dn_fib_node *dz_chain(dn_fib_key_t key, struct dn_zone *dz) 106{ 107 return dz->dz_hash[dn_hash(key, dz).datum]; 108} 109 110static inline int dn_key_eq(dn_fib_key_t a, dn_fib_key_t b) 111{ 112 return a.datum == b.datum; 113} 114 115static inline int dn_key_leq(dn_fib_key_t a, dn_fib_key_t b) 116{ 117 return a.datum <= b.datum; 118} 119 120static inline void dn_rebuild_zone(struct dn_zone *dz, 121 struct dn_fib_node **old_ht, 122 int old_divisor) 123{ 124 int i; 125 struct dn_fib_node *f, **fp, *next; 126 127 for(i = 0; i < old_divisor; i++) { 128 for(f = old_ht[i]; f; f = f->fn_next) { 129 next = f->fn_next; 130 for(fp = dn_chain_p(f->fn_key, dz); 131 *fp && dn_key_leq((*fp)->fn_key, f->fn_key); 132 fp = &(*fp)->fn_next) 133 /* NOTHING */; 134 f->fn_next = *fp; 135 *fp = f; 136 } 137 } 138} 139 140static void dn_rehash_zone(struct dn_zone *dz) 141{ 142 struct dn_fib_node **ht, **old_ht; 143 int old_divisor, new_divisor; 144 u32 new_hashmask; 145 146 old_divisor = dz->dz_divisor; 147 148 switch(old_divisor) { 149 case 16: 150 new_divisor = 256; 151 new_hashmask = 0xFF; 152 break; 153 default: 154 printk(KERN_DEBUG "DECnet: dn_rehash_zone: BUG! %d\n", old_divisor); 155 case 256: 156 new_divisor = 1024; 157 new_hashmask = 0x3FF; 158 break; 159 } 160 161 ht = kmalloc(new_divisor*sizeof(struct dn_fib_node*), GFP_KERNEL); 162 163 if (ht == NULL) 164 return; 165 166 memset(ht, 0, new_divisor*sizeof(struct dn_fib_node *)); 167 write_lock_bh(&dn_fib_tables_lock); 168 old_ht = dz->dz_hash; 169 dz->dz_hash = ht; 170 dz->dz_hashmask = new_hashmask; 171 dz->dz_divisor = new_divisor; 172 dn_rebuild_zone(dz, old_ht, old_divisor); 173 write_unlock_bh(&dn_fib_tables_lock); 174 kfree(old_ht); 175} 176 177static void dn_free_node(struct dn_fib_node *f) 178{ 179 dn_fib_release_info(DN_FIB_INFO(f)); 180 kmem_cache_free(dn_hash_kmem, f); 181} 182 183 184static struct dn_zone *dn_new_zone(struct dn_hash *table, int z) 185{ 186 int i; 187 struct dn_zone *dz = kmalloc(sizeof(struct dn_zone), GFP_KERNEL); 188 if (!dz) 189 return NULL; 190 191 memset(dz, 0, sizeof(struct dn_zone)); 192 if (z) { 193 dz->dz_divisor = 16; 194 dz->dz_hashmask = 0x0F; 195 } else { 196 dz->dz_divisor = 1; 197 dz->dz_hashmask = 0; 198 } 199 200 dz->dz_hash = kmalloc(dz->dz_divisor*sizeof(struct dn_fib_node *), GFP_KERNEL); 201 202 if (!dz->dz_hash) { 203 kfree(dz); 204 return NULL; 205 } 206 207 memset(dz->dz_hash, 0, dz->dz_divisor*sizeof(struct dn_fib_node*)); 208 dz->dz_order = z; 209 dz->dz_mask = dnet_make_mask(z); 210 211 for(i = z + 1; i <= 16; i++) 212 if (table->dh_zones[i]) 213 break; 214 215 write_lock_bh(&dn_fib_tables_lock); 216 if (i>16) { 217 dz->dz_next = table->dh_zone_list; 218 table->dh_zone_list = dz; 219 } else { 220 dz->dz_next = table->dh_zones[i]->dz_next; 221 table->dh_zones[i]->dz_next = dz; 222 } 223 table->dh_zones[z] = dz; 224 write_unlock_bh(&dn_fib_tables_lock); 225 return dz; 226} 227 228 229static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern_rta *rta, struct dn_fib_info *fi) 230{ 231 struct rtnexthop *nhp; 232 int nhlen; 233 234 if (rta->rta_priority && *rta->rta_priority != fi->fib_priority) 235 return 1; 236 237 if (rta->rta_oif || rta->rta_gw) { 238 if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) && 239 (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 2) == 0)) 240 return 0; 241 return 1; 242 } 243 244 if (rta->rta_mp == NULL) 245 return 0; 246 247 nhp = RTA_DATA(rta->rta_mp); 248 nhlen = RTA_PAYLOAD(rta->rta_mp); 249 250 for_nexthops(fi) { 251 int attrlen = nhlen - sizeof(struct rtnexthop); 252 __le16 gw; 253 254 if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) 255 return -EINVAL; 256 if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif) 257 return 1; 258 if (attrlen) { 259 gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); 260 261 if (gw && gw != nh->nh_gw) 262 return 1; 263 } 264 nhp = RTNH_NEXT(nhp); 265 } endfor_nexthops(fi); 266 267 return 0; 268} 269 270static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, 271 u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, 272 struct dn_fib_info *fi, unsigned int flags) 273{ 274 struct rtmsg *rtm; 275 struct nlmsghdr *nlh; 276 unsigned char *b = skb->tail; 277 278 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags); 279 rtm = NLMSG_DATA(nlh); 280 rtm->rtm_family = AF_DECnet; 281 rtm->rtm_dst_len = dst_len; 282 rtm->rtm_src_len = 0; 283 rtm->rtm_tos = 0; 284 rtm->rtm_table = tb_id; 285 rtm->rtm_flags = fi->fib_flags; 286 rtm->rtm_scope = scope; 287 rtm->rtm_type = type; 288 if (rtm->rtm_dst_len) 289 RTA_PUT(skb, RTA_DST, 2, dst); 290 rtm->rtm_protocol = fi->fib_protocol; 291 if (fi->fib_priority) 292 RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority); 293 if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0) 294 goto rtattr_failure; 295 if (fi->fib_nhs == 1) { 296 if (fi->fib_nh->nh_gw) 297 RTA_PUT(skb, RTA_GATEWAY, 2, &fi->fib_nh->nh_gw); 298 if (fi->fib_nh->nh_oif) 299 RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif); 300 } 301 if (fi->fib_nhs > 1) { 302 struct rtnexthop *nhp; 303 struct rtattr *mp_head; 304 if (skb_tailroom(skb) <= RTA_SPACE(0)) 305 goto rtattr_failure; 306 mp_head = (struct rtattr *)skb_put(skb, RTA_SPACE(0)); 307 308 for_nexthops(fi) { 309 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) 310 goto rtattr_failure; 311 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); 312 nhp->rtnh_flags = nh->nh_flags & 0xFF; 313 nhp->rtnh_hops = nh->nh_weight - 1; 314 nhp->rtnh_ifindex = nh->nh_oif; 315 if (nh->nh_gw) 316 RTA_PUT(skb, RTA_GATEWAY, 2, &nh->nh_gw); 317 nhp->rtnh_len = skb->tail - (unsigned char *)nhp; 318 } endfor_nexthops(fi); 319 mp_head->rta_type = RTA_MULTIPATH; 320 mp_head->rta_len = skb->tail - (u8*)mp_head; 321 } 322 323 nlh->nlmsg_len = skb->tail - b; 324 return skb->len; 325 326 327nlmsg_failure: 328rtattr_failure: 329 skb_trim(skb, b - skb->data); 330 return -1; 331} 332 333 334static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, int tb_id, 335 struct nlmsghdr *nlh, struct netlink_skb_parms *req) 336{ 337 struct sk_buff *skb; 338 u32 pid = req ? req->pid : 0; 339 int size = NLMSG_SPACE(sizeof(struct rtmsg) + 256); 340 341 skb = alloc_skb(size, GFP_KERNEL); 342 if (!skb) 343 return; 344 345 if (dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, 346 f->fn_type, f->fn_scope, &f->fn_key, z, 347 DN_FIB_INFO(f), 0) < 0) { 348 kfree_skb(skb); 349 return; 350 } 351 NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_ROUTE; 352 if (nlh->nlmsg_flags & NLM_F_ECHO) 353 atomic_inc(&skb->users); 354 netlink_broadcast(rtnl, skb, pid, RTNLGRP_DECnet_ROUTE, GFP_KERNEL); 355 if (nlh->nlmsg_flags & NLM_F_ECHO) 356 netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); 357} 358 359static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, 360 struct netlink_callback *cb, 361 struct dn_fib_table *tb, 362 struct dn_zone *dz, 363 struct dn_fib_node *f) 364{ 365 int i, s_i; 366 367 s_i = cb->args[3]; 368 for(i = 0; f; i++, f = f->fn_next) { 369 if (i < s_i) 370 continue; 371 if (f->fn_state & DN_S_ZOMBIE) 372 continue; 373 if (dn_fib_dump_info(skb, NETLINK_CB(cb->skb).pid, 374 cb->nlh->nlmsg_seq, 375 RTM_NEWROUTE, 376 tb->n, 377 (f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type, 378 f->fn_scope, &f->fn_key, dz->dz_order, 379 f->fn_info, NLM_F_MULTI) < 0) { 380 cb->args[3] = i; 381 return -1; 382 } 383 } 384 cb->args[3] = i; 385 return skb->len; 386} 387 388static __inline__ int dn_hash_dump_zone(struct sk_buff *skb, 389 struct netlink_callback *cb, 390 struct dn_fib_table *tb, 391 struct dn_zone *dz) 392{ 393 int h, s_h; 394 395 s_h = cb->args[2]; 396 for(h = 0; h < dz->dz_divisor; h++) { 397 if (h < s_h) 398 continue; 399 if (h > s_h) 400 memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0])); 401 if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL) 402 continue; 403 if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) { 404 cb->args[2] = h; 405 return -1; 406 } 407 } 408 cb->args[2] = h; 409 return skb->len; 410} 411 412static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb, 413 struct netlink_callback *cb) 414{ 415 int m, s_m; 416 struct dn_zone *dz; 417 struct dn_hash *table = (struct dn_hash *)tb->data; 418 419 s_m = cb->args[1]; 420 read_lock(&dn_fib_tables_lock); 421 for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) { 422 if (m < s_m) 423 continue; 424 if (m > s_m) 425 memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0])); 426 427 if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) { 428 cb->args[1] = m; 429 read_unlock(&dn_fib_tables_lock); 430 return -1; 431 } 432 } 433 read_unlock(&dn_fib_tables_lock); 434 cb->args[1] = m; 435 436 return skb->len; 437} 438 439static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) 440{ 441 struct dn_hash *table = (struct dn_hash *)tb->data; 442 struct dn_fib_node *new_f, *f, **fp, **del_fp; 443 struct dn_zone *dz; 444 struct dn_fib_info *fi; 445 int z = r->rtm_dst_len; 446 int type = r->rtm_type; 447 dn_fib_key_t key; 448 int err; 449 450 if (z > 16) 451 return -EINVAL; 452 453 dz = table->dh_zones[z]; 454 if (!dz && !(dz = dn_new_zone(table, z))) 455 return -ENOBUFS; 456 457 dz_key_0(key); 458 if (rta->rta_dst) { 459 __le16 dst; 460 memcpy(&dst, rta->rta_dst, 2); 461 if (dst & ~DZ_MASK(dz)) 462 return -EINVAL; 463 key = dz_key(dst, dz); 464 } 465 466 if ((fi = dn_fib_create_info(r, rta, n, &err)) == NULL) 467 return err; 468 469 if (dz->dz_nent > (dz->dz_divisor << 2) && 470 dz->dz_divisor > DN_MAX_DIVISOR && 471 (z==16 || (1<<z) > dz->dz_divisor)) 472 dn_rehash_zone(dz); 473 474 fp = dn_chain_p(key, dz); 475 476 DN_FIB_SCAN(f, fp) { 477 if (dn_key_leq(key, f->fn_key)) 478 break; 479 } 480 481 del_fp = NULL; 482 483 if (f && (f->fn_state & DN_S_ZOMBIE) && 484 dn_key_eq(f->fn_key, key)) { 485 del_fp = fp; 486 fp = &f->fn_next; 487 f = *fp; 488 goto create; 489 } 490 491 DN_FIB_SCAN_KEY(f, fp, key) { 492 if (fi->fib_priority <= DN_FIB_INFO(f)->fib_priority) 493 break; 494 } 495 496 if (f && dn_key_eq(f->fn_key, key) && 497 fi->fib_priority == DN_FIB_INFO(f)->fib_priority) { 498 struct dn_fib_node **ins_fp; 499 500 err = -EEXIST; 501 if (n->nlmsg_flags & NLM_F_EXCL) 502 goto out; 503 504 if (n->nlmsg_flags & NLM_F_REPLACE) { 505 del_fp = fp; 506 fp = &f->fn_next; 507 f = *fp; 508 goto replace; 509 } 510 511 ins_fp = fp; 512 err = -EEXIST; 513 514 DN_FIB_SCAN_KEY(f, fp, key) { 515 if (fi->fib_priority != DN_FIB_INFO(f)->fib_priority) 516 break; 517 if (f->fn_type == type && f->fn_scope == r->rtm_scope 518 && DN_FIB_INFO(f) == fi) 519 goto out; 520 } 521 522 if (!(n->nlmsg_flags & NLM_F_APPEND)) { 523 fp = ins_fp; 524 f = *fp; 525 } 526 } 527 528create: 529 err = -ENOENT; 530 if (!(n->nlmsg_flags & NLM_F_CREATE)) 531 goto out; 532 533replace: 534 err = -ENOBUFS; 535 new_f = kmem_cache_alloc(dn_hash_kmem, SLAB_KERNEL); 536 if (new_f == NULL) 537 goto out; 538 539 memset(new_f, 0, sizeof(struct dn_fib_node)); 540 541 new_f->fn_key = key; 542 new_f->fn_type = type; 543 new_f->fn_scope = r->rtm_scope; 544 DN_FIB_INFO(new_f) = fi; 545 546 new_f->fn_next = f; 547 write_lock_bh(&dn_fib_tables_lock); 548 *fp = new_f; 549 write_unlock_bh(&dn_fib_tables_lock); 550 dz->dz_nent++; 551 552 if (del_fp) { 553 f = *del_fp; 554 write_lock_bh(&dn_fib_tables_lock); 555 *del_fp = f->fn_next; 556 write_unlock_bh(&dn_fib_tables_lock); 557 558 if (!(f->fn_state & DN_S_ZOMBIE)) 559 dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req); 560 if (f->fn_state & DN_S_ACCESSED) 561 dn_rt_cache_flush(-1); 562 dn_free_node(f); 563 dz->dz_nent--; 564 } else { 565 dn_rt_cache_flush(-1); 566 } 567 568 dn_rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->n, n, req); 569 570 return 0; 571out: 572 dn_fib_release_info(fi); 573 return err; 574} 575 576 577static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) 578{ 579 struct dn_hash *table = (struct dn_hash*)tb->data; 580 struct dn_fib_node **fp, **del_fp, *f; 581 int z = r->rtm_dst_len; 582 struct dn_zone *dz; 583 dn_fib_key_t key; 584 int matched; 585 586 587 if (z > 16) 588 return -EINVAL; 589 590 if ((dz = table->dh_zones[z]) == NULL) 591 return -ESRCH; 592 593 dz_key_0(key); 594 if (rta->rta_dst) { 595 __le16 dst; 596 memcpy(&dst, rta->rta_dst, 2); 597 if (dst & ~DZ_MASK(dz)) 598 return -EINVAL; 599 key = dz_key(dst, dz); 600 } 601 602 fp = dn_chain_p(key, dz); 603 604 DN_FIB_SCAN(f, fp) { 605 if (dn_key_eq(f->fn_key, key)) 606 break; 607 if (dn_key_leq(key, f->fn_key)) 608 return -ESRCH; 609 } 610 611 matched = 0; 612 del_fp = NULL; 613 DN_FIB_SCAN_KEY(f, fp, key) { 614 struct dn_fib_info *fi = DN_FIB_INFO(f); 615 616 if (f->fn_state & DN_S_ZOMBIE) 617 return -ESRCH; 618 619 matched++; 620 621 if (del_fp == NULL && 622 (!r->rtm_type || f->fn_type == r->rtm_type) && 623 (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) && 624 (!r->rtm_protocol || 625 fi->fib_protocol == r->rtm_protocol) && 626 dn_fib_nh_match(r, n, rta, fi) == 0) 627 del_fp = fp; 628 } 629 630 if (del_fp) { 631 f = *del_fp; 632 dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req); 633 634 if (matched != 1) { 635 write_lock_bh(&dn_fib_tables_lock); 636 *del_fp = f->fn_next; 637 write_unlock_bh(&dn_fib_tables_lock); 638 639 if (f->fn_state & DN_S_ACCESSED) 640 dn_rt_cache_flush(-1); 641 dn_free_node(f); 642 dz->dz_nent--; 643 } else { 644 f->fn_state |= DN_S_ZOMBIE; 645 if (f->fn_state & DN_S_ACCESSED) { 646 f->fn_state &= ~DN_S_ACCESSED; 647 dn_rt_cache_flush(-1); 648 } 649 if (++dn_fib_hash_zombies > 128) 650 dn_fib_flush(); 651 } 652 653 return 0; 654 } 655 656 return -ESRCH; 657} 658 659static inline int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table) 660{ 661 int found = 0; 662 struct dn_fib_node *f; 663 664 while((f = *fp) != NULL) { 665 struct dn_fib_info *fi = DN_FIB_INFO(f); 666 667 if (fi && ((f->fn_state & DN_S_ZOMBIE) || (fi->fib_flags & RTNH_F_DEAD))) { 668 write_lock_bh(&dn_fib_tables_lock); 669 *fp = f->fn_next; 670 write_unlock_bh(&dn_fib_tables_lock); 671 672 dn_free_node(f); 673 found++; 674 continue; 675 } 676 fp = &f->fn_next; 677 } 678 679 return found; 680} 681 682static int dn_fib_table_flush(struct dn_fib_table *tb) 683{ 684 struct dn_hash *table = (struct dn_hash *)tb->data; 685 struct dn_zone *dz; 686 int found = 0; 687 688 dn_fib_hash_zombies = 0; 689 for(dz = table->dh_zone_list; dz; dz = dz->dz_next) { 690 int i; 691 int tmp = 0; 692 for(i = dz->dz_divisor-1; i >= 0; i--) 693 tmp += dn_flush_list(&dz->dz_hash[i], dz->dz_order, table); 694 dz->dz_nent -= tmp; 695 found += tmp; 696 } 697 698 return found; 699} 700 701static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowi *flp, struct dn_fib_res *res) 702{ 703 int err; 704 struct dn_zone *dz; 705 struct dn_hash *t = (struct dn_hash *)tb->data; 706 707 read_lock(&dn_fib_tables_lock); 708 for(dz = t->dh_zone_list; dz; dz = dz->dz_next) { 709 struct dn_fib_node *f; 710 dn_fib_key_t k = dz_key(flp->fld_dst, dz); 711 712 for(f = dz_chain(k, dz); f; f = f->fn_next) { 713 if (!dn_key_eq(k, f->fn_key)) { 714 if (dn_key_leq(k, f->fn_key)) 715 break; 716 else 717 continue; 718 } 719 720 f->fn_state |= DN_S_ACCESSED; 721 722 if (f->fn_state&DN_S_ZOMBIE) 723 continue; 724 725 if (f->fn_scope < flp->fld_scope) 726 continue; 727 728 err = dn_fib_semantic_match(f->fn_type, DN_FIB_INFO(f), flp, res); 729 730 if (err == 0) { 731 res->type = f->fn_type; 732 res->scope = f->fn_scope; 733 res->prefixlen = dz->dz_order; 734 goto out; 735 } 736 if (err < 0) 737 goto out; 738 } 739 } 740 err = 1; 741out: 742 read_unlock(&dn_fib_tables_lock); 743 return err; 744} 745 746 747struct dn_fib_table *dn_fib_get_table(int n, int create) 748{ 749 struct dn_fib_table *t; 750 751 if (n < RT_TABLE_MIN) 752 return NULL; 753 754 if (n > RT_TABLE_MAX) 755 return NULL; 756 757 if (dn_fib_tables[n]) 758 return dn_fib_tables[n]; 759 760 if (!create) 761 return NULL; 762 763 if (in_interrupt() && net_ratelimit()) { 764 printk(KERN_DEBUG "DECnet: BUG! Attempt to create routing table from interrupt\n"); 765 return NULL; 766 } 767 if ((t = kmalloc(sizeof(struct dn_fib_table) + sizeof(struct dn_hash), GFP_KERNEL)) == NULL) 768 return NULL; 769 770 memset(t, 0, sizeof(struct dn_fib_table)); 771 772 t->n = n; 773 t->insert = dn_fib_table_insert; 774 t->delete = dn_fib_table_delete; 775 t->lookup = dn_fib_table_lookup; 776 t->flush = dn_fib_table_flush; 777 t->dump = dn_fib_table_dump; 778 memset(t->data, 0, sizeof(struct dn_hash)); 779 dn_fib_tables[n] = t; 780 781 return t; 782} 783 784static void dn_fib_del_tree(int n) 785{ 786 struct dn_fib_table *t; 787 788 write_lock(&dn_fib_tables_lock); 789 t = dn_fib_tables[n]; 790 dn_fib_tables[n] = NULL; 791 write_unlock(&dn_fib_tables_lock); 792 793 kfree(t); 794} 795 796struct dn_fib_table *dn_fib_empty_table(void) 797{ 798 int id; 799 800 for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++) 801 if (dn_fib_tables[id] == NULL) 802 return dn_fib_get_table(id, 1); 803 return NULL; 804} 805 806void __init dn_fib_table_init(void) 807{ 808 dn_hash_kmem = kmem_cache_create("dn_fib_info_cache", 809 sizeof(struct dn_fib_info), 810 0, SLAB_HWCACHE_ALIGN, 811 NULL, NULL); 812} 813 814void __exit dn_fib_table_cleanup(void) 815{ 816 int i; 817 818 for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i) 819 dn_fib_del_tree(i); 820 821 return; 822}