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