Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.16 803 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 (Glue/Info List) 7 * 8 * Author: Steve Whitehouse <SteveW@ACM.org> 9 * 10 * 11 * Changes: 12 * Alexey Kuznetsov : SMP locking changes 13 * Steve Whitehouse : Rewrote it... Well to be more correct, I 14 * copied most of it from the ipv4 fib code. 15 * Steve Whitehouse : Updated it in style and fixed a few bugs 16 * which were fixed in the ipv4 code since 17 * this code was copied from it. 18 * 19 */ 20#include <linux/config.h> 21#include <linux/string.h> 22#include <linux/net.h> 23#include <linux/socket.h> 24#include <linux/sockios.h> 25#include <linux/init.h> 26#include <linux/skbuff.h> 27#include <linux/netlink.h> 28#include <linux/rtnetlink.h> 29#include <linux/proc_fs.h> 30#include <linux/netdevice.h> 31#include <linux/timer.h> 32#include <linux/spinlock.h> 33#include <asm/atomic.h> 34#include <asm/uaccess.h> 35#include <net/neighbour.h> 36#include <net/dst.h> 37#include <net/flow.h> 38#include <net/dn.h> 39#include <net/dn_route.h> 40#include <net/dn_fib.h> 41#include <net/dn_neigh.h> 42#include <net/dn_dev.h> 43 44#define RT_MIN_TABLE 1 45 46#define for_fib_info() { struct dn_fib_info *fi;\ 47 for(fi = dn_fib_info_list; fi; fi = fi->fib_next) 48#define endfor_fib_info() } 49 50#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\ 51 for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++) 52 53#define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\ 54 for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++) 55 56#define endfor_nexthops(fi) } 57 58extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb); 59 60static DEFINE_SPINLOCK(dn_fib_multipath_lock); 61static struct dn_fib_info *dn_fib_info_list; 62static DEFINE_RWLOCK(dn_fib_info_lock); 63 64static struct 65{ 66 int error; 67 u8 scope; 68} dn_fib_props[RTA_MAX+1] = { 69 [RTN_UNSPEC] = { .error = 0, .scope = RT_SCOPE_NOWHERE }, 70 [RTN_UNICAST] = { .error = 0, .scope = RT_SCOPE_UNIVERSE }, 71 [RTN_LOCAL] = { .error = 0, .scope = RT_SCOPE_HOST }, 72 [RTN_BROADCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, 73 [RTN_ANYCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, 74 [RTN_MULTICAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, 75 [RTN_BLACKHOLE] = { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE }, 76 [RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE }, 77 [RTN_PROHIBIT] = { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE }, 78 [RTN_THROW] = { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE }, 79 [RTN_NAT] = { .error = 0, .scope = RT_SCOPE_NOWHERE }, 80 [RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, 81}; 82 83void dn_fib_free_info(struct dn_fib_info *fi) 84{ 85 if (fi->fib_dead == 0) { 86 printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n"); 87 return; 88 } 89 90 change_nexthops(fi) { 91 if (nh->nh_dev) 92 dev_put(nh->nh_dev); 93 nh->nh_dev = NULL; 94 } endfor_nexthops(fi); 95 kfree(fi); 96} 97 98void dn_fib_release_info(struct dn_fib_info *fi) 99{ 100 write_lock(&dn_fib_info_lock); 101 if (fi && --fi->fib_treeref == 0) { 102 if (fi->fib_next) 103 fi->fib_next->fib_prev = fi->fib_prev; 104 if (fi->fib_prev) 105 fi->fib_prev->fib_next = fi->fib_next; 106 if (fi == dn_fib_info_list) 107 dn_fib_info_list = fi->fib_next; 108 fi->fib_dead = 1; 109 dn_fib_info_put(fi); 110 } 111 write_unlock(&dn_fib_info_lock); 112} 113 114static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi) 115{ 116 const struct dn_fib_nh *onh = ofi->fib_nh; 117 118 for_nexthops(fi) { 119 if (nh->nh_oif != onh->nh_oif || 120 nh->nh_gw != onh->nh_gw || 121 nh->nh_scope != onh->nh_scope || 122 nh->nh_weight != onh->nh_weight || 123 ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD)) 124 return -1; 125 onh++; 126 } endfor_nexthops(fi); 127 return 0; 128} 129 130static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi) 131{ 132 for_fib_info() { 133 if (fi->fib_nhs != nfi->fib_nhs) 134 continue; 135 if (nfi->fib_protocol == fi->fib_protocol && 136 nfi->fib_prefsrc == fi->fib_prefsrc && 137 nfi->fib_priority == fi->fib_priority && 138 memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 && 139 ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 && 140 (nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0)) 141 return fi; 142 } endfor_fib_info(); 143 return NULL; 144} 145 146u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type) 147{ 148 while(RTA_OK(attr,attrlen)) { 149 if (attr->rta_type == type) 150 return *(u16*)RTA_DATA(attr); 151 attr = RTA_NEXT(attr, attrlen); 152 } 153 154 return 0; 155} 156 157static int dn_fib_count_nhs(struct rtattr *rta) 158{ 159 int nhs = 0; 160 struct rtnexthop *nhp = RTA_DATA(rta); 161 int nhlen = RTA_PAYLOAD(rta); 162 163 while(nhlen >= (int)sizeof(struct rtnexthop)) { 164 if ((nhlen -= nhp->rtnh_len) < 0) 165 return 0; 166 nhs++; 167 nhp = RTNH_NEXT(nhp); 168 } 169 170 return nhs; 171} 172 173static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r) 174{ 175 struct rtnexthop *nhp = RTA_DATA(rta); 176 int nhlen = RTA_PAYLOAD(rta); 177 178 change_nexthops(fi) { 179 int attrlen = nhlen - sizeof(struct rtnexthop); 180 if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) 181 return -EINVAL; 182 183 nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags; 184 nh->nh_oif = nhp->rtnh_ifindex; 185 nh->nh_weight = nhp->rtnh_hops + 1; 186 187 if (attrlen) { 188 nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); 189 } 190 nhp = RTNH_NEXT(nhp); 191 } endfor_nexthops(fi); 192 193 return 0; 194} 195 196 197static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh) 198{ 199 int err; 200 201 if (nh->nh_gw) { 202 struct flowi fl; 203 struct dn_fib_res res; 204 205 memset(&fl, 0, sizeof(fl)); 206 207 if (nh->nh_flags&RTNH_F_ONLINK) { 208 struct net_device *dev; 209 210 if (r->rtm_scope >= RT_SCOPE_LINK) 211 return -EINVAL; 212 if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST) 213 return -EINVAL; 214 if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL) 215 return -ENODEV; 216 if (!(dev->flags&IFF_UP)) 217 return -ENETDOWN; 218 nh->nh_dev = dev; 219 dev_hold(dev); 220 nh->nh_scope = RT_SCOPE_LINK; 221 return 0; 222 } 223 224 memset(&fl, 0, sizeof(fl)); 225 fl.fld_dst = nh->nh_gw; 226 fl.oif = nh->nh_oif; 227 fl.fld_scope = r->rtm_scope + 1; 228 229 if (fl.fld_scope < RT_SCOPE_LINK) 230 fl.fld_scope = RT_SCOPE_LINK; 231 232 if ((err = dn_fib_lookup(&fl, &res)) != 0) 233 return err; 234 235 err = -EINVAL; 236 if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) 237 goto out; 238 nh->nh_scope = res.scope; 239 nh->nh_oif = DN_FIB_RES_OIF(res); 240 nh->nh_dev = DN_FIB_RES_DEV(res); 241 if (nh->nh_dev == NULL) 242 goto out; 243 dev_hold(nh->nh_dev); 244 err = -ENETDOWN; 245 if (!(nh->nh_dev->flags & IFF_UP)) 246 goto out; 247 err = 0; 248out: 249 dn_fib_res_put(&res); 250 return err; 251 } else { 252 struct net_device *dev; 253 254 if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK)) 255 return -EINVAL; 256 257 dev = __dev_get_by_index(nh->nh_oif); 258 if (dev == NULL || dev->dn_ptr == NULL) 259 return -ENODEV; 260 if (!(dev->flags&IFF_UP)) 261 return -ENETDOWN; 262 nh->nh_dev = dev; 263 dev_hold(nh->nh_dev); 264 nh->nh_scope = RT_SCOPE_HOST; 265 } 266 267 return 0; 268} 269 270 271struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp) 272{ 273 int err; 274 struct dn_fib_info *fi = NULL; 275 struct dn_fib_info *ofi; 276 int nhs = 1; 277 278 if (dn_fib_props[r->rtm_type].scope > r->rtm_scope) 279 goto err_inval; 280 281 if (rta->rta_mp) { 282 nhs = dn_fib_count_nhs(rta->rta_mp); 283 if (nhs == 0) 284 goto err_inval; 285 } 286 287 fi = kmalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL); 288 err = -ENOBUFS; 289 if (fi == NULL) 290 goto failure; 291 memset(fi, 0, sizeof(*fi)+nhs*sizeof(struct dn_fib_nh)); 292 293 fi->fib_protocol = r->rtm_protocol; 294 fi->fib_nhs = nhs; 295 fi->fib_flags = r->rtm_flags; 296 if (rta->rta_priority) 297 fi->fib_priority = *rta->rta_priority; 298 if (rta->rta_mx) { 299 int attrlen = RTA_PAYLOAD(rta->rta_mx); 300 struct rtattr *attr = RTA_DATA(rta->rta_mx); 301 302 while(RTA_OK(attr, attrlen)) { 303 unsigned flavour = attr->rta_type; 304 if (flavour) { 305 if (flavour > RTAX_MAX) 306 goto err_inval; 307 fi->fib_metrics[flavour-1] = *(unsigned*)RTA_DATA(attr); 308 } 309 attr = RTA_NEXT(attr, attrlen); 310 } 311 } 312 if (rta->rta_prefsrc) 313 memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2); 314 315 if (rta->rta_mp) { 316 if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0) 317 goto failure; 318 if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif) 319 goto err_inval; 320 if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2)) 321 goto err_inval; 322 } else { 323 struct dn_fib_nh *nh = fi->fib_nh; 324 if (rta->rta_oif) 325 nh->nh_oif = *rta->rta_oif; 326 if (rta->rta_gw) 327 memcpy(&nh->nh_gw, rta->rta_gw, 2); 328 nh->nh_flags = r->rtm_flags; 329 nh->nh_weight = 1; 330 } 331 332 if (r->rtm_type == RTN_NAT) { 333 if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif) 334 goto err_inval; 335 memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 2); 336 goto link_it; 337 } 338 339 if (dn_fib_props[r->rtm_type].error) { 340 if (rta->rta_gw || rta->rta_oif || rta->rta_mp) 341 goto err_inval; 342 goto link_it; 343 } 344 345 if (r->rtm_scope > RT_SCOPE_HOST) 346 goto err_inval; 347 348 if (r->rtm_scope == RT_SCOPE_HOST) { 349 struct dn_fib_nh *nh = fi->fib_nh; 350 351 /* Local address is added */ 352 if (nhs != 1 || nh->nh_gw) 353 goto err_inval; 354 nh->nh_scope = RT_SCOPE_NOWHERE; 355 nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif); 356 err = -ENODEV; 357 if (nh->nh_dev == NULL) 358 goto failure; 359 } else { 360 change_nexthops(fi) { 361 if ((err = dn_fib_check_nh(r, fi, nh)) != 0) 362 goto failure; 363 } endfor_nexthops(fi) 364 } 365 366 if (fi->fib_prefsrc) { 367 if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || 368 memcmp(&fi->fib_prefsrc, rta->rta_dst, 2)) 369 if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) 370 goto err_inval; 371 } 372 373link_it: 374 if ((ofi = dn_fib_find_info(fi)) != NULL) { 375 fi->fib_dead = 1; 376 dn_fib_free_info(fi); 377 ofi->fib_treeref++; 378 return ofi; 379 } 380 381 fi->fib_treeref++; 382 atomic_inc(&fi->fib_clntref); 383 write_lock(&dn_fib_info_lock); 384 fi->fib_next = dn_fib_info_list; 385 fi->fib_prev = NULL; 386 if (dn_fib_info_list) 387 dn_fib_info_list->fib_prev = fi; 388 dn_fib_info_list = fi; 389 write_unlock(&dn_fib_info_lock); 390 return fi; 391 392err_inval: 393 err = -EINVAL; 394 395failure: 396 *errp = err; 397 if (fi) { 398 fi->fib_dead = 1; 399 dn_fib_free_info(fi); 400 } 401 402 return NULL; 403} 404 405int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowi *fl, struct dn_fib_res *res) 406{ 407 int err = dn_fib_props[type].error; 408 409 if (err == 0) { 410 if (fi->fib_flags & RTNH_F_DEAD) 411 return 1; 412 413 res->fi = fi; 414 415 switch(type) { 416 case RTN_NAT: 417 DN_FIB_RES_RESET(*res); 418 atomic_inc(&fi->fib_clntref); 419 return 0; 420 case RTN_UNICAST: 421 case RTN_LOCAL: 422 for_nexthops(fi) { 423 if (nh->nh_flags & RTNH_F_DEAD) 424 continue; 425 if (!fl->oif || fl->oif == nh->nh_oif) 426 break; 427 } 428 if (nhsel < fi->fib_nhs) { 429 res->nh_sel = nhsel; 430 atomic_inc(&fi->fib_clntref); 431 return 0; 432 } 433 endfor_nexthops(fi); 434 res->fi = NULL; 435 return 1; 436 default: 437 if (net_ratelimit()) 438 printk("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n", type); 439 res->fi = NULL; 440 return -EINVAL; 441 } 442 } 443 return err; 444} 445 446void dn_fib_select_multipath(const struct flowi *fl, struct dn_fib_res *res) 447{ 448 struct dn_fib_info *fi = res->fi; 449 int w; 450 451 spin_lock_bh(&dn_fib_multipath_lock); 452 if (fi->fib_power <= 0) { 453 int power = 0; 454 change_nexthops(fi) { 455 if (!(nh->nh_flags&RTNH_F_DEAD)) { 456 power += nh->nh_weight; 457 nh->nh_power = nh->nh_weight; 458 } 459 } endfor_nexthops(fi); 460 fi->fib_power = power; 461 if (power < 0) { 462 spin_unlock_bh(&dn_fib_multipath_lock); 463 res->nh_sel = 0; 464 return; 465 } 466 } 467 468 w = jiffies % fi->fib_power; 469 470 change_nexthops(fi) { 471 if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) { 472 if ((w -= nh->nh_power) <= 0) { 473 nh->nh_power--; 474 fi->fib_power--; 475 res->nh_sel = nhsel; 476 spin_unlock_bh(&dn_fib_multipath_lock); 477 return; 478 } 479 } 480 } endfor_nexthops(fi); 481 res->nh_sel = 0; 482 spin_unlock_bh(&dn_fib_multipath_lock); 483} 484 485 486static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta) 487{ 488 int i; 489 490 for(i = 1; i <= RTA_MAX; i++) { 491 struct rtattr *attr = rta[i-1]; 492 if (attr) { 493 if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2) 494 return -EINVAL; 495 if (i != RTA_MULTIPATH && i != RTA_METRICS) 496 rta[i-1] = (struct rtattr *)RTA_DATA(attr); 497 } 498 } 499 500 return 0; 501} 502 503int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 504{ 505 struct dn_fib_table *tb; 506 struct rtattr **rta = arg; 507 struct rtmsg *r = NLMSG_DATA(nlh); 508 509 if (dn_fib_check_attr(r, rta)) 510 return -EINVAL; 511 512 tb = dn_fib_get_table(r->rtm_table, 0); 513 if (tb) 514 return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); 515 516 return -ESRCH; 517} 518 519int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 520{ 521 struct dn_fib_table *tb; 522 struct rtattr **rta = arg; 523 struct rtmsg *r = NLMSG_DATA(nlh); 524 525 if (dn_fib_check_attr(r, rta)) 526 return -EINVAL; 527 528 tb = dn_fib_get_table(r->rtm_table, 1); 529 if (tb) 530 return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); 531 532 return -ENOBUFS; 533} 534 535 536int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) 537{ 538 int t; 539 int s_t; 540 struct dn_fib_table *tb; 541 542 if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) && 543 ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED) 544 return dn_cache_dump(skb, cb); 545 546 s_t = cb->args[0]; 547 if (s_t == 0) 548 s_t = cb->args[0] = RT_MIN_TABLE; 549 550 for(t = s_t; t <= RT_TABLE_MAX; t++) { 551 if (t < s_t) 552 continue; 553 if (t > s_t) 554 memset(&cb->args[1], 0, 555 sizeof(cb->args) - sizeof(cb->args[0])); 556 tb = dn_fib_get_table(t, 0); 557 if (tb == NULL) 558 continue; 559 if (tb->dump(tb, skb, cb) < 0) 560 break; 561 } 562 563 cb->args[0] = t; 564 565 return skb->len; 566} 567 568static void fib_magic(int cmd, int type, __u16 dst, int dst_len, struct dn_ifaddr *ifa) 569{ 570 struct dn_fib_table *tb; 571 struct { 572 struct nlmsghdr nlh; 573 struct rtmsg rtm; 574 } req; 575 struct dn_kern_rta rta; 576 577 memset(&req.rtm, 0, sizeof(req.rtm)); 578 memset(&rta, 0, sizeof(rta)); 579 580 if (type == RTN_UNICAST) 581 tb = dn_fib_get_table(RT_MIN_TABLE, 1); 582 else 583 tb = dn_fib_get_table(RT_TABLE_LOCAL, 1); 584 585 if (tb == NULL) 586 return; 587 588 req.nlh.nlmsg_len = sizeof(req); 589 req.nlh.nlmsg_type = cmd; 590 req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND; 591 req.nlh.nlmsg_pid = 0; 592 req.nlh.nlmsg_seq = 0; 593 594 req.rtm.rtm_dst_len = dst_len; 595 req.rtm.rtm_table = tb->n; 596 req.rtm.rtm_protocol = RTPROT_KERNEL; 597 req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST); 598 req.rtm.rtm_type = type; 599 600 rta.rta_dst = &dst; 601 rta.rta_prefsrc = &ifa->ifa_local; 602 rta.rta_oif = &ifa->ifa_dev->dev->ifindex; 603 604 if (cmd == RTM_NEWROUTE) 605 tb->insert(tb, &req.rtm, &rta, &req.nlh, NULL); 606 else 607 tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL); 608} 609 610static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa) 611{ 612 613 fib_magic(RTM_NEWROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa); 614 615#if 0 616 if (!(dev->flags&IFF_UP)) 617 return; 618 /* In the future, we will want to add default routes here */ 619 620#endif 621} 622 623static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa) 624{ 625 int found_it = 0; 626 struct net_device *dev; 627 struct dn_dev *dn_db; 628 struct dn_ifaddr *ifa2; 629 630 ASSERT_RTNL(); 631 632 /* Scan device list */ 633 read_lock(&dev_base_lock); 634 for(dev = dev_base; dev; dev = dev->next) { 635 dn_db = dev->dn_ptr; 636 if (dn_db == NULL) 637 continue; 638 for(ifa2 = dn_db->ifa_list; ifa2; ifa2 = ifa2->ifa_next) { 639 if (ifa2->ifa_local == ifa->ifa_local) { 640 found_it = 1; 641 break; 642 } 643 } 644 } 645 read_unlock(&dev_base_lock); 646 647 if (found_it == 0) { 648 fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa); 649 650 if (dnet_addr_type(ifa->ifa_local) != RTN_LOCAL) { 651 if (dn_fib_sync_down(ifa->ifa_local, NULL, 0)) 652 dn_fib_flush(); 653 } 654 } 655} 656 657static void dn_fib_disable_addr(struct net_device *dev, int force) 658{ 659 if (dn_fib_sync_down(0, dev, force)) 660 dn_fib_flush(); 661 dn_rt_cache_flush(0); 662 neigh_ifdown(&dn_neigh_table, dev); 663} 664 665static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, void *ptr) 666{ 667 struct dn_ifaddr *ifa = (struct dn_ifaddr *)ptr; 668 669 switch(event) { 670 case NETDEV_UP: 671 dn_fib_add_ifaddr(ifa); 672 dn_fib_sync_up(ifa->ifa_dev->dev); 673 dn_rt_cache_flush(-1); 674 break; 675 case NETDEV_DOWN: 676 dn_fib_del_ifaddr(ifa); 677 if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) { 678 dn_fib_disable_addr(ifa->ifa_dev->dev, 1); 679 } else { 680 dn_rt_cache_flush(-1); 681 } 682 break; 683 } 684 return NOTIFY_DONE; 685} 686 687int dn_fib_sync_down(dn_address local, struct net_device *dev, int force) 688{ 689 int ret = 0; 690 int scope = RT_SCOPE_NOWHERE; 691 692 if (force) 693 scope = -1; 694 695 for_fib_info() { 696 /* 697 * This makes no sense for DECnet.... we will almost 698 * certainly have more than one local address the same 699 * over all our interfaces. It needs thinking about 700 * some more. 701 */ 702 if (local && fi->fib_prefsrc == local) { 703 fi->fib_flags |= RTNH_F_DEAD; 704 ret++; 705 } else if (dev && fi->fib_nhs) { 706 int dead = 0; 707 708 change_nexthops(fi) { 709 if (nh->nh_flags&RTNH_F_DEAD) 710 dead++; 711 else if (nh->nh_dev == dev && 712 nh->nh_scope != scope) { 713 spin_lock_bh(&dn_fib_multipath_lock); 714 nh->nh_flags |= RTNH_F_DEAD; 715 fi->fib_power -= nh->nh_power; 716 nh->nh_power = 0; 717 spin_unlock_bh(&dn_fib_multipath_lock); 718 dead++; 719 } 720 } endfor_nexthops(fi) 721 if (dead == fi->fib_nhs) { 722 fi->fib_flags |= RTNH_F_DEAD; 723 ret++; 724 } 725 } 726 } endfor_fib_info(); 727 return ret; 728} 729 730 731int dn_fib_sync_up(struct net_device *dev) 732{ 733 int ret = 0; 734 735 if (!(dev->flags&IFF_UP)) 736 return 0; 737 738 for_fib_info() { 739 int alive = 0; 740 741 change_nexthops(fi) { 742 if (!(nh->nh_flags&RTNH_F_DEAD)) { 743 alive++; 744 continue; 745 } 746 if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP)) 747 continue; 748 if (nh->nh_dev != dev || dev->dn_ptr == NULL) 749 continue; 750 alive++; 751 spin_lock_bh(&dn_fib_multipath_lock); 752 nh->nh_power = 0; 753 nh->nh_flags &= ~RTNH_F_DEAD; 754 spin_unlock_bh(&dn_fib_multipath_lock); 755 } endfor_nexthops(fi); 756 757 if (alive > 0) { 758 fi->fib_flags &= ~RTNH_F_DEAD; 759 ret++; 760 } 761 } endfor_fib_info(); 762 return ret; 763} 764 765void dn_fib_flush(void) 766{ 767 int flushed = 0; 768 struct dn_fib_table *tb; 769 int id; 770 771 for(id = RT_TABLE_MAX; id > 0; id--) { 772 if ((tb = dn_fib_get_table(id, 0)) == NULL) 773 continue; 774 flushed += tb->flush(tb); 775 } 776 777 if (flushed) 778 dn_rt_cache_flush(-1); 779} 780 781static struct notifier_block dn_fib_dnaddr_notifier = { 782 .notifier_call = dn_fib_dnaddr_event, 783}; 784 785void __exit dn_fib_cleanup(void) 786{ 787 dn_fib_table_cleanup(); 788 dn_fib_rules_cleanup(); 789 790 unregister_dnaddr_notifier(&dn_fib_dnaddr_notifier); 791} 792 793 794void __init dn_fib_init(void) 795{ 796 797 dn_fib_table_init(); 798 dn_fib_rules_init(); 799 800 register_dnaddr_notifier(&dn_fib_dnaddr_notifier); 801} 802 803