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/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 u32 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 77static rwlock_t dn_fib_tables_lock = RW_LOCK_UNLOCKED; 78static struct dn_fib_table *dn_fib_tables[DN_NUM_TABLES + 1]; 79 80static kmem_cache_t *dn_hash_kmem; 81static int dn_fib_hash_zombies; 82 83static __inline__ dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz) 84{ 85 u32 h = ntohs(key.datum)>>(16 - dz->dz_order); 86 h ^= (h >> 10); 87 h ^= (h >> 6); 88 h ^= (h >> 3); 89 h &= DZ_HASHMASK(dz); 90 return *(dn_fib_idx_t *)&h; 91} 92 93static __inline__ dn_fib_key_t dz_key(u16 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 dn_address 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) 273{ 274 struct rtmsg *rtm; 275 struct nlmsghdr *nlh; 276 unsigned char *b = skb->tail; 277 278 nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*rtm)); 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 (fi->fib_nhs == 1) { 294 if (fi->fib_nh->nh_gw) 295 RTA_PUT(skb, RTA_GATEWAY, 2, &fi->fib_nh->nh_gw); 296 if (fi->fib_nh->nh_oif) 297 RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif); 298 } 299 if (fi->fib_nhs > 1) { 300 struct rtnexthop *nhp; 301 struct rtattr *mp_head; 302 if (skb_tailroom(skb) <= RTA_SPACE(0)) 303 goto rtattr_failure; 304 mp_head = (struct rtattr *)skb_put(skb, RTA_SPACE(0)); 305 306 for_nexthops(fi) { 307 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) 308 goto rtattr_failure; 309 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); 310 nhp->rtnh_flags = nh->nh_flags & 0xFF; 311 nhp->rtnh_hops = nh->nh_weight - 1; 312 nhp->rtnh_ifindex = nh->nh_oif; 313 if (nh->nh_gw) 314 RTA_PUT(skb, RTA_GATEWAY, 2, &nh->nh_gw); 315 nhp->rtnh_len = skb->tail - (unsigned char *)nhp; 316 } endfor_nexthops(fi); 317 mp_head->rta_type = RTA_MULTIPATH; 318 mp_head->rta_len = skb->tail - (u8*)mp_head; 319 } 320 321 nlh->nlmsg_len = skb->tail - b; 322 return skb->len; 323 324 325nlmsg_failure: 326rtattr_failure: 327 skb_trim(skb, b - skb->data); 328 return -1; 329} 330 331 332static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, int tb_id, 333 struct nlmsghdr *nlh, struct netlink_skb_parms *req) 334{ 335 struct sk_buff *skb; 336 u32 pid = req ? req->pid : 0; 337 int size = NLMSG_SPACE(sizeof(struct rtmsg) + 256); 338 339 skb = alloc_skb(size, GFP_KERNEL); 340 if (!skb) 341 return; 342 343 if (dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, 344 f->fn_type, f->fn_scope, &f->fn_key, z, 345 DN_FIB_INFO(f)) < 0) { 346 kfree_skb(skb); 347 return; 348 } 349 NETLINK_CB(skb).dst_groups = RTMGRP_DECnet_ROUTE; 350 if (nlh->nlmsg_flags & NLM_F_ECHO) 351 atomic_inc(&skb->users); 352 netlink_broadcast(rtnl, skb, pid, RTMGRP_DECnet_ROUTE, GFP_KERNEL); 353 if (nlh->nlmsg_flags & NLM_F_ECHO) 354 netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); 355} 356 357static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, 358 struct netlink_callback *cb, 359 struct dn_fib_table *tb, 360 struct dn_zone *dz, 361 struct dn_fib_node *f) 362{ 363 int i, s_i; 364 365 s_i = cb->args[3]; 366 for(i = 0; f; i++, f = f->fn_next) { 367 if (i < s_i) 368 continue; 369 if (f->fn_state & DN_S_ZOMBIE) 370 continue; 371 if (dn_fib_dump_info(skb, NETLINK_CB(cb->skb).pid, 372 cb->nlh->nlmsg_seq, 373 RTM_NEWROUTE, 374 tb->n, 375 (f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type, 376 f->fn_scope, &f->fn_key, dz->dz_order, 377 f->fn_info) < 0) { 378 cb->args[3] = i; 379 return -1; 380 } 381 } 382 cb->args[3] = i; 383 return skb->len; 384} 385 386static __inline__ int dn_hash_dump_zone(struct sk_buff *skb, 387 struct netlink_callback *cb, 388 struct dn_fib_table *tb, 389 struct dn_zone *dz) 390{ 391 int h, s_h; 392 393 s_h = cb->args[2]; 394 for(h = 0; h < dz->dz_divisor; h++) { 395 if (h < s_h) 396 continue; 397 if (h > s_h) 398 memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0])); 399 if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL) 400 continue; 401 if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) { 402 cb->args[2] = h; 403 return -1; 404 } 405 } 406 cb->args[2] = h; 407 return skb->len; 408} 409 410static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb, 411 struct netlink_callback *cb) 412{ 413 int m, s_m; 414 struct dn_zone *dz; 415 struct dn_hash *table = (struct dn_hash *)tb->data; 416 417 s_m = cb->args[1]; 418 read_lock(&dn_fib_tables_lock); 419 for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) { 420 if (m < s_m) 421 continue; 422 if (m > s_m) 423 memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0])); 424 425 if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) { 426 cb->args[1] = m; 427 read_unlock(&dn_fib_tables_lock); 428 return -1; 429 } 430 } 431 read_unlock(&dn_fib_tables_lock); 432 cb->args[1] = m; 433 434 return skb->len; 435} 436 437static 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) 438{ 439 struct dn_hash *table = (struct dn_hash *)tb->data; 440 struct dn_fib_node *new_f, *f, **fp, **del_fp; 441 struct dn_zone *dz; 442 struct dn_fib_info *fi; 443 int z = r->rtm_dst_len; 444 int type = r->rtm_type; 445 dn_fib_key_t key; 446 int err; 447 448 if (z > 16) 449 return -EINVAL; 450 451 dz = table->dh_zones[z]; 452 if (!dz && !(dz = dn_new_zone(table, z))) 453 return -ENOBUFS; 454 455 dz_key_0(key); 456 if (rta->rta_dst) { 457 dn_address dst; 458 memcpy(&dst, rta->rta_dst, 2); 459 if (dst & ~DZ_MASK(dz)) 460 return -EINVAL; 461 key = dz_key(dst, dz); 462 } 463 464 if ((fi = dn_fib_create_info(r, rta, n, &err)) == NULL) 465 return err; 466 467 if (dz->dz_nent > (dz->dz_divisor << 2) && 468 dz->dz_divisor > DN_MAX_DIVISOR && 469 (z==16 || (1<<z) > dz->dz_divisor)) 470 dn_rehash_zone(dz); 471 472 fp = dn_chain_p(key, dz); 473 474 DN_FIB_SCAN(f, fp) { 475 if (dn_key_leq(key, f->fn_key)) 476 break; 477 } 478 479 del_fp = NULL; 480 481 if (f && (f->fn_state & DN_S_ZOMBIE) && 482 dn_key_eq(f->fn_key, key)) { 483 del_fp = fp; 484 fp = &f->fn_next; 485 f = *fp; 486 goto create; 487 } 488 489 DN_FIB_SCAN_KEY(f, fp, key) { 490 if (fi->fib_priority <= DN_FIB_INFO(f)->fib_priority) 491 break; 492 } 493 494 if (f && dn_key_eq(f->fn_key, key) && 495 fi->fib_priority == DN_FIB_INFO(f)->fib_priority) { 496 struct dn_fib_node **ins_fp; 497 498 err = -EEXIST; 499 if (n->nlmsg_flags & NLM_F_EXCL) 500 goto out; 501 502 if (n->nlmsg_flags & NLM_F_REPLACE) { 503 del_fp = fp; 504 fp = &f->fn_next; 505 f = *fp; 506 goto replace; 507 } 508 509 ins_fp = fp; 510 err = -EEXIST; 511 512 DN_FIB_SCAN_KEY(f, fp, key) { 513 if (fi->fib_priority != DN_FIB_INFO(f)->fib_priority) 514 break; 515 if (f->fn_type == type && f->fn_scope == r->rtm_scope 516 && DN_FIB_INFO(f) == fi) 517 goto out; 518 } 519 520 if (!(n->nlmsg_flags & NLM_F_APPEND)) { 521 fp = ins_fp; 522 f = *fp; 523 } 524 } 525 526create: 527 err = -ENOENT; 528 if (!(n->nlmsg_flags & NLM_F_CREATE)) 529 goto out; 530 531replace: 532 err = -ENOBUFS; 533 new_f = kmem_cache_alloc(dn_hash_kmem, SLAB_KERNEL); 534 if (new_f == NULL) 535 goto out; 536 537 memset(new_f, 0, sizeof(struct dn_fib_node)); 538 539 new_f->fn_key = key; 540 new_f->fn_type = type; 541 new_f->fn_scope = r->rtm_scope; 542 DN_FIB_INFO(new_f) = fi; 543 544 new_f->fn_next = f; 545 write_lock_bh(&dn_fib_tables_lock); 546 *fp = new_f; 547 write_unlock_bh(&dn_fib_tables_lock); 548 dz->dz_nent++; 549 550 if (del_fp) { 551 f = *del_fp; 552 write_lock_bh(&dn_fib_tables_lock); 553 *del_fp = f->fn_next; 554 write_unlock_bh(&dn_fib_tables_lock); 555 556 if (!(f->fn_state & DN_S_ZOMBIE)) 557 dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req); 558 if (f->fn_state & DN_S_ACCESSED) 559 dn_rt_cache_flush(-1); 560 dn_free_node(f); 561 dz->dz_nent--; 562 } else { 563 dn_rt_cache_flush(-1); 564 } 565 566 dn_rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->n, n, req); 567 568 return 0; 569out: 570 dn_fib_release_info(fi); 571 return err; 572} 573 574 575static 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) 576{ 577 struct dn_hash *table = (struct dn_hash*)tb->data; 578 struct dn_fib_node **fp, **del_fp, *f; 579 int z = r->rtm_dst_len; 580 struct dn_zone *dz; 581 dn_fib_key_t key; 582 int matched; 583 584 585 if (z > 16) 586 return -EINVAL; 587 588 if ((dz = table->dh_zones[z]) == NULL) 589 return -ESRCH; 590 591 dz_key_0(key); 592 if (rta->rta_dst) { 593 dn_address dst; 594 memcpy(&dst, rta->rta_dst, 2); 595 if (dst & ~DZ_MASK(dz)) 596 return -EINVAL; 597 key = dz_key(dst, dz); 598 } 599 600 fp = dn_chain_p(key, dz); 601 602 DN_FIB_SCAN(f, fp) { 603 if (dn_key_eq(f->fn_key, key)) 604 break; 605 if (dn_key_leq(key, f->fn_key)) 606 return -ESRCH; 607 } 608 609 matched = 0; 610 del_fp = NULL; 611 DN_FIB_SCAN_KEY(f, fp, key) { 612 struct dn_fib_info *fi = DN_FIB_INFO(f); 613 614 if (f->fn_state & DN_S_ZOMBIE) 615 return -ESRCH; 616 617 matched++; 618 619 if (del_fp == NULL && 620 (!r->rtm_type || f->fn_type == r->rtm_type) && 621 (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) && 622 (!r->rtm_protocol || 623 fi->fib_protocol == r->rtm_protocol) && 624 dn_fib_nh_match(r, n, rta, fi) == 0) 625 del_fp = fp; 626 } 627 628 if (del_fp) { 629 f = *del_fp; 630 dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req); 631 632 if (matched != 1) { 633 write_lock_bh(&dn_fib_tables_lock); 634 *del_fp = f->fn_next; 635 write_unlock_bh(&dn_fib_tables_lock); 636 637 if (f->fn_state & DN_S_ACCESSED) 638 dn_rt_cache_flush(-1); 639 dn_free_node(f); 640 dz->dz_nent--; 641 } else { 642 f->fn_state |= DN_S_ZOMBIE; 643 if (f->fn_state & DN_S_ACCESSED) { 644 f->fn_state &= ~DN_S_ACCESSED; 645 dn_rt_cache_flush(-1); 646 } 647 if (++dn_fib_hash_zombies > 128) 648 dn_fib_flush(); 649 } 650 651 return 0; 652 } 653 654 return -ESRCH; 655} 656 657static __inline__ int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table) 658{ 659 int found = 0; 660 struct dn_fib_node *f; 661 662 while((f = *fp) != NULL) { 663 struct dn_fib_info *fi = DN_FIB_INFO(f); 664 665 if (fi && ((f->fn_state & DN_S_ZOMBIE) || (fi->fib_flags & RTNH_F_DEAD))) { 666 write_lock_bh(&dn_fib_tables_lock); 667 *fp = f->fn_next; 668 write_unlock_bh(&dn_fib_tables_lock); 669 670 dn_free_node(f); 671 found++; 672 continue; 673 } 674 fp = &f->fn_next; 675 } 676 677 return found; 678} 679 680static int dn_fib_table_flush(struct dn_fib_table *tb) 681{ 682 struct dn_hash *table = (struct dn_hash *)tb->data; 683 struct dn_zone *dz; 684 int found = 0; 685 686 dn_fib_hash_zombies = 0; 687 for(dz = table->dh_zone_list; dz; dz = dz->dz_next) { 688 int i; 689 int tmp = 0; 690 for(i = dz->dz_divisor-1; i >= 0; i--) 691 tmp += dn_flush_list(&dz->dz_hash[i], dz->dz_order, table); 692 dz->dz_nent -= tmp; 693 found += tmp; 694 } 695 696 return found; 697} 698 699static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct dn_fib_key * 700key, struct dn_fib_res *res) 701{ 702 int err; 703 struct dn_zone *dz; 704 struct dn_hash *t = (struct dn_hash *)tb->data; 705 706 read_lock(&dn_fib_tables_lock); 707 for(dz = t->dh_zone_list; dz; dz = dz->dz_next) { 708 struct dn_fib_node *f; 709 dn_fib_key_t k = dz_key(key->dst, dz); 710 711 for(f = dz_chain(k, dz); f; f = f->fn_next) { 712 if (!dn_key_leq(k, f->fn_key)) 713 break; 714 else 715 continue; 716 717 f->fn_state |= DN_S_ACCESSED; 718 719 if (f->fn_state&DN_S_ZOMBIE) 720 continue; 721 if (f->fn_scope < key->scope) 722 continue; 723 724 err = dn_fib_semantic_match(f->fn_type, DN_FIB_INFO(f), key, res); 725 if (err == 0) { 726 res->type = f->fn_type; 727 res->scope = f->fn_scope; 728 res->prefixlen = dz->dz_order; 729 goto out; 730 } 731 if (err < 0) 732 goto out; 733 } 734 } 735 err = 1; 736out: 737 read_unlock(&dn_fib_tables_lock); 738 return err; 739} 740 741#ifdef CONFIG_PROC_FS 742 743static unsigned dn_fib_flag_trans(int type, int dead, u16 mask, struct dn_fib_info *fi) 744{ 745 static unsigned type2flags[RTN_MAX+1] = { 746 0, 0, 0, 0, 0, 0, 0, RTF_REJECT, RTF_REJECT, 0, 0, 0 747 }; 748 unsigned flags = type2flags[type]; 749 750 if (fi && fi->fib_nh->nh_gw) 751 flags |= RTF_GATEWAY; 752 if (mask == 0xFFFF) 753 flags |= RTF_HOST; 754 if (dead) 755 flags |= RTF_UP; 756 return flags; 757} 758 759static void dn_fib_node_get_info(int type, int dead, struct dn_fib_info *fi, u16 prefix, u16 mask, char *buffer) 760{ 761 int len; 762 unsigned flags = dn_fib_flag_trans(type, dead, mask, fi); 763 764 if (fi) { 765 len = sprintf(buffer, "%s\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u", 766 fi->fib_dev ? fi->fib_dev->name : "*", prefix, 767 fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority, 768 mask, 0, 0, 0); 769 } else { 770 len = sprintf(buffer, "*\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u", 771 prefix, 0, 772 flags, 0, 0, 0, 773 mask, 0, 0, 0); 774 } 775 memset(buffer+len, ' ', 127-len); 776 buffer[127] = '\n'; 777} 778 779static int dn_fib_table_get_info(struct dn_fib_table *tb, char *buffer, int first, int count) 780{ 781 struct dn_hash *table = (struct dn_hash *)tb->data; 782 struct dn_zone *dz; 783 int pos = 0; 784 int n = 0; 785 786 read_lock(&dn_fib_tables_lock); 787 for(dz = table->dh_zone_list; dz; dz = dz->dz_next) { 788 int i; 789 struct dn_fib_node *f; 790 int maxslot = dz->dz_divisor; 791 struct dn_fib_node **fp = dz->dz_hash; 792 793 if (dz->dz_nent == 0) 794 continue; 795 796 if (pos + dz->dz_nent < first) { 797 pos += dz->dz_nent; 798 continue; 799 } 800 801 for(i = 0; i < maxslot; i++, fp++) { 802 for(f = *fp; f ; f = f->fn_next) { 803 if (++pos <= first) 804 continue; 805 dn_fib_node_get_info(f->fn_type, 806 f->fn_state & DN_S_ZOMBIE, 807 DN_FIB_INFO(f), 808 dz_prefix(f->fn_key, dz), 809 DZ_MASK(dz), buffer); 810 buffer += 128; 811 if (++n >= count) 812 goto out; 813 } 814 } 815 } 816out: 817 read_unlock(&dn_fib_tables_lock); 818 return n; 819} 820#endif /* CONFIG_PROC_FS */ 821 822struct dn_fib_table *dn_fib_get_table(int n, int create) 823{ 824 struct dn_fib_table *t; 825 826 if (n < DN_MIN_TABLE) 827 return NULL; 828 829 if (n > DN_NUM_TABLES) 830 return NULL; 831 832 if (dn_fib_tables[n]) 833 return dn_fib_tables[n]; 834 835 if (!create) 836 return NULL; 837 838 if (in_interrupt() && net_ratelimit()) { 839 printk(KERN_DEBUG "DECnet: BUG! Attempt to create routing table 840from interrupt\n"); 841 return NULL; 842 } 843 if ((t = kmalloc(sizeof(struct dn_fib_table), GFP_KERNEL)) == NULL) 844 return NULL; 845 846 memset(t, 0, sizeof(struct dn_fib_table)); 847 848 t->n = n; 849 t->insert = dn_fib_table_insert; 850 t->delete = dn_fib_table_delete; 851 t->lookup = dn_fib_table_lookup; 852 t->flush = dn_fib_table_flush; 853#ifdef CONFIG_PROC_FS 854 t->get_info = dn_fib_table_get_info; 855#endif 856 t->dump = dn_fib_table_dump; 857 dn_fib_tables[n] = t; 858 859 return t; 860} 861 862static void dn_fib_del_tree(int n) 863{ 864 struct dn_fib_table *t; 865 866 write_lock(&dn_fib_tables_lock); 867 t = dn_fib_tables[n]; 868 dn_fib_tables[n] = NULL; 869 write_unlock(&dn_fib_tables_lock); 870 871 if (t) { 872 kfree(t); 873 } 874} 875 876struct dn_fib_table *dn_fib_empty_table(void) 877{ 878 int id; 879 880 for(id = DN_MIN_TABLE; id <= DN_NUM_TABLES; id++) 881 if (dn_fib_tables[id] == NULL) 882 return dn_fib_get_table(id, 1); 883 return NULL; 884} 885 886void __init dn_fib_table_init(void) 887{ 888 dn_hash_kmem = kmem_cache_create("dn_fib_info_cache", 889 sizeof(struct dn_fib_info), 890 0, SLAB_HWCACHE_ALIGN, 891 NULL, NULL); 892} 893 894void __exit dn_fib_table_cleanup(void) 895{ 896 int i; 897 898 for (i = 0; i < DN_NUM_TABLES + 1; ++i) 899 dn_fib_del_tree(i); 900 901 return; 902} 903