diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 113 |
1 files changed, 60 insertions, 53 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 061a7bba163a..6a4019a4ca89 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -72,6 +72,7 @@ | |||
72 | #define RT6_TRACE(x...) do { ; } while (0) | 72 | #define RT6_TRACE(x...) do { ; } while (0) |
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | #define CLONE_OFFLINK_ROUTE 0 | ||
75 | 76 | ||
76 | static int ip6_rt_max_size = 4096; | 77 | static int ip6_rt_max_size = 4096; |
77 | static int ip6_rt_gc_min_interval = HZ / 2; | 78 | static int ip6_rt_gc_min_interval = HZ / 2; |
@@ -465,9 +466,10 @@ if (rt == &ip6_null_entry && strict) { \ | |||
465 | void ip6_route_input(struct sk_buff *skb) | 466 | void ip6_route_input(struct sk_buff *skb) |
466 | { | 467 | { |
467 | struct fib6_node *fn; | 468 | struct fib6_node *fn; |
468 | struct rt6_info *rt; | 469 | struct rt6_info *rt, *nrt; |
469 | int strict; | 470 | int strict; |
470 | int attempts = 3; | 471 | int attempts = 3; |
472 | int err; | ||
471 | 473 | ||
472 | strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); | 474 | strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); |
473 | 475 | ||
@@ -492,51 +494,53 @@ restart: | |||
492 | dst_hold(&rt->u.dst); | 494 | dst_hold(&rt->u.dst); |
493 | read_unlock_bh(&rt6_lock); | 495 | read_unlock_bh(&rt6_lock); |
494 | 496 | ||
495 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 497 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
496 | struct rt6_info *nrt; | 498 | nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr); |
497 | int err; | 499 | else { |
498 | 500 | #if CLONE_OFFLINK_ROUTE | |
499 | nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, | 501 | nrt = rt6_alloc_clone(rt, &skb->nh.ipv6h->daddr); |
500 | &skb->nh.ipv6h->saddr); | 502 | #else |
501 | 503 | goto out2; | |
502 | dst_release(&rt->u.dst); | 504 | #endif |
503 | rt = nrt ? : &ip6_null_entry; | 505 | } |
504 | 506 | ||
505 | dst_hold(&rt->u.dst); | 507 | dst_release(&rt->u.dst); |
506 | if (nrt) { | 508 | rt = nrt ? : &ip6_null_entry; |
507 | err = ip6_ins_rt(nrt, NULL, NULL, | ||
508 | &NETLINK_CB(skb)); | ||
509 | if (!err) | ||
510 | goto out2; | ||
511 | } | ||
512 | 509 | ||
513 | if (--attempts <= 0) | 510 | dst_hold(&rt->u.dst); |
511 | if (nrt) { | ||
512 | err = ip6_ins_rt(nrt, NULL, NULL, &NETLINK_CB(skb)); | ||
513 | if (!err) | ||
514 | goto out2; | 514 | goto out2; |
515 | |||
516 | /* Race condition! In the gap, when rt6_lock was | ||
517 | released someone could insert this route. Relookup. | ||
518 | */ | ||
519 | dst_release(&rt->u.dst); | ||
520 | goto relookup; | ||
521 | } | 515 | } |
522 | 516 | ||
517 | if (--attempts <= 0) | ||
518 | goto out2; | ||
519 | |||
520 | /* | ||
521 | * Race condition! In the gap, when rt6_lock was | ||
522 | * released someone could insert this route. Relookup. | ||
523 | */ | ||
524 | dst_release(&rt->u.dst); | ||
525 | goto relookup; | ||
526 | |||
527 | out: | ||
528 | dst_hold(&rt->u.dst); | ||
529 | read_unlock_bh(&rt6_lock); | ||
523 | out2: | 530 | out2: |
524 | rt->u.dst.lastuse = jiffies; | 531 | rt->u.dst.lastuse = jiffies; |
525 | rt->u.dst.__use++; | 532 | rt->u.dst.__use++; |
526 | skb->dst = (struct dst_entry *) rt; | 533 | skb->dst = (struct dst_entry *) rt; |
527 | return; | 534 | return; |
528 | out: | ||
529 | dst_hold(&rt->u.dst); | ||
530 | read_unlock_bh(&rt6_lock); | ||
531 | goto out2; | ||
532 | } | 535 | } |
533 | 536 | ||
534 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | 537 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) |
535 | { | 538 | { |
536 | struct fib6_node *fn; | 539 | struct fib6_node *fn; |
537 | struct rt6_info *rt; | 540 | struct rt6_info *rt, *nrt; |
538 | int strict; | 541 | int strict; |
539 | int attempts = 3; | 542 | int attempts = 3; |
543 | int err; | ||
540 | 544 | ||
541 | strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); | 545 | strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); |
542 | 546 | ||
@@ -564,40 +568,43 @@ restart: | |||
564 | dst_hold(&rt->u.dst); | 568 | dst_hold(&rt->u.dst); |
565 | read_unlock_bh(&rt6_lock); | 569 | read_unlock_bh(&rt6_lock); |
566 | 570 | ||
567 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 571 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
568 | struct rt6_info *nrt; | ||
569 | int err; | ||
570 | |||
571 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); | 572 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); |
573 | else { | ||
574 | #if CLONE_OFFLINK_ROUTE | ||
575 | nrt = rt6_alloc_clone(rt, &fl->fl6_dst); | ||
576 | #else | ||
577 | goto out2; | ||
578 | #endif | ||
579 | } | ||
572 | 580 | ||
573 | dst_release(&rt->u.dst); | 581 | dst_release(&rt->u.dst); |
574 | rt = nrt ? : &ip6_null_entry; | 582 | rt = nrt ? : &ip6_null_entry; |
575 | |||
576 | dst_hold(&rt->u.dst); | ||
577 | if (nrt) { | ||
578 | err = ip6_ins_rt(nrt, NULL, NULL, NULL); | ||
579 | if (!err) | ||
580 | goto out2; | ||
581 | } | ||
582 | 583 | ||
583 | if (--attempts <= 0) | 584 | dst_hold(&rt->u.dst); |
585 | if (nrt) { | ||
586 | err = ip6_ins_rt(nrt, NULL, NULL, NULL); | ||
587 | if (!err) | ||
584 | goto out2; | 588 | goto out2; |
585 | |||
586 | /* Race condition! In the gap, when rt6_lock was | ||
587 | released someone could insert this route. Relookup. | ||
588 | */ | ||
589 | dst_release(&rt->u.dst); | ||
590 | goto relookup; | ||
591 | } | 589 | } |
592 | 590 | ||
591 | if (--attempts <= 0) | ||
592 | goto out2; | ||
593 | |||
594 | /* | ||
595 | * Race condition! In the gap, when rt6_lock was | ||
596 | * released someone could insert this route. Relookup. | ||
597 | */ | ||
598 | dst_release(&rt->u.dst); | ||
599 | goto relookup; | ||
600 | |||
601 | out: | ||
602 | dst_hold(&rt->u.dst); | ||
603 | read_unlock_bh(&rt6_lock); | ||
593 | out2: | 604 | out2: |
594 | rt->u.dst.lastuse = jiffies; | 605 | rt->u.dst.lastuse = jiffies; |
595 | rt->u.dst.__use++; | 606 | rt->u.dst.__use++; |
596 | return &rt->u.dst; | 607 | return &rt->u.dst; |
597 | out: | ||
598 | dst_hold(&rt->u.dst); | ||
599 | read_unlock_bh(&rt6_lock); | ||
600 | goto out2; | ||
601 | } | 608 | } |
602 | 609 | ||
603 | 610 | ||