diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index cb76e3c725a0..8603cfb271f2 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2396,7 +2396,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) | |||
2396 | 2396 | ||
2397 | /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ | 2397 | /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ |
2398 | dev_out = ip_dev_find(oldflp->fl4_src); | 2398 | dev_out = ip_dev_find(oldflp->fl4_src); |
2399 | if ((dev_out == NULL) && !(sysctl_ip_nonlocal_bind)) | 2399 | if (dev_out == NULL) |
2400 | goto out; | 2400 | goto out; |
2401 | 2401 | ||
2402 | /* I removed check for oif == dev_out->oif here. | 2402 | /* I removed check for oif == dev_out->oif here. |
@@ -2407,7 +2407,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) | |||
2407 | of another iface. --ANK | 2407 | of another iface. --ANK |
2408 | */ | 2408 | */ |
2409 | 2409 | ||
2410 | if (dev_out && oldflp->oif == 0 | 2410 | if (oldflp->oif == 0 |
2411 | && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == htonl(0xFFFFFFFF))) { | 2411 | && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == htonl(0xFFFFFFFF))) { |
2412 | /* Special hack: user can direct multicasts | 2412 | /* Special hack: user can direct multicasts |
2413 | and limited broadcast via necessary interface | 2413 | and limited broadcast via necessary interface |
@@ -2598,6 +2598,69 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp) | |||
2598 | 2598 | ||
2599 | EXPORT_SYMBOL_GPL(__ip_route_output_key); | 2599 | EXPORT_SYMBOL_GPL(__ip_route_output_key); |
2600 | 2600 | ||
2601 | static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) | ||
2602 | { | ||
2603 | } | ||
2604 | |||
2605 | static struct dst_ops ipv4_dst_blackhole_ops = { | ||
2606 | .family = AF_INET, | ||
2607 | .protocol = __constant_htons(ETH_P_IP), | ||
2608 | .destroy = ipv4_dst_destroy, | ||
2609 | .check = ipv4_dst_check, | ||
2610 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, | ||
2611 | .entry_size = sizeof(struct rtable), | ||
2612 | }; | ||
2613 | |||
2614 | |||
2615 | static int ipv4_blackhole_output(struct sk_buff *skb) | ||
2616 | { | ||
2617 | kfree_skb(skb); | ||
2618 | return 0; | ||
2619 | } | ||
2620 | |||
2621 | static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock *sk) | ||
2622 | { | ||
2623 | struct rtable *ort = *rp; | ||
2624 | struct rtable *rt = (struct rtable *) | ||
2625 | dst_alloc(&ipv4_dst_blackhole_ops); | ||
2626 | |||
2627 | if (rt) { | ||
2628 | struct dst_entry *new = &rt->u.dst; | ||
2629 | |||
2630 | atomic_set(&new->__refcnt, 1); | ||
2631 | new->__use = 1; | ||
2632 | new->input = ipv4_blackhole_output; | ||
2633 | new->output = ipv4_blackhole_output; | ||
2634 | memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); | ||
2635 | |||
2636 | new->dev = ort->u.dst.dev; | ||
2637 | if (new->dev) | ||
2638 | dev_hold(new->dev); | ||
2639 | |||
2640 | rt->fl = ort->fl; | ||
2641 | |||
2642 | rt->idev = ort->idev; | ||
2643 | if (rt->idev) | ||
2644 | in_dev_hold(rt->idev); | ||
2645 | rt->rt_flags = ort->rt_flags; | ||
2646 | rt->rt_type = ort->rt_type; | ||
2647 | rt->rt_dst = ort->rt_dst; | ||
2648 | rt->rt_src = ort->rt_src; | ||
2649 | rt->rt_iif = ort->rt_iif; | ||
2650 | rt->rt_gateway = ort->rt_gateway; | ||
2651 | rt->rt_spec_dst = ort->rt_spec_dst; | ||
2652 | rt->peer = ort->peer; | ||
2653 | if (rt->peer) | ||
2654 | atomic_inc(&rt->peer->refcnt); | ||
2655 | |||
2656 | dst_free(new); | ||
2657 | } | ||
2658 | |||
2659 | dst_release(&(*rp)->u.dst); | ||
2660 | *rp = rt; | ||
2661 | return (rt ? 0 : -ENOMEM); | ||
2662 | } | ||
2663 | |||
2601 | int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags) | 2664 | int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags) |
2602 | { | 2665 | { |
2603 | int err; | 2666 | int err; |
@@ -2610,7 +2673,11 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, | |||
2610 | flp->fl4_src = (*rp)->rt_src; | 2673 | flp->fl4_src = (*rp)->rt_src; |
2611 | if (!flp->fl4_dst) | 2674 | if (!flp->fl4_dst) |
2612 | flp->fl4_dst = (*rp)->rt_dst; | 2675 | flp->fl4_dst = (*rp)->rt_dst; |
2613 | return xfrm_lookup((struct dst_entry **)rp, flp, sk, flags); | 2676 | err = __xfrm_lookup((struct dst_entry **)rp, flp, sk, flags); |
2677 | if (err == -EREMOTE) | ||
2678 | err = ipv4_dst_blackhole(rp, flp, sk); | ||
2679 | |||
2680 | return err; | ||
2614 | } | 2681 | } |
2615 | 2682 | ||
2616 | return 0; | 2683 | return 0; |
@@ -3139,6 +3206,8 @@ int __init ip_rt_init(void) | |||
3139 | kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, | 3206 | kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, |
3140 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); | 3207 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
3141 | 3208 | ||
3209 | ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep; | ||
3210 | |||
3142 | rt_hash_table = (struct rt_hash_bucket *) | 3211 | rt_hash_table = (struct rt_hash_bucket *) |
3143 | alloc_large_system_hash("IP route cache", | 3212 | alloc_large_system_hash("IP route cache", |
3144 | sizeof(struct rt_hash_bucket), | 3213 | sizeof(struct rt_hash_bucket), |