ipv4: Cache ip_error() routes even when not forwarding.
authorDavid S. Miller <davem@davemloft.net>
Tue, 26 Jun 2012 23:27:09 +0000 (16:27 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 26 Jun 2012 23:27:09 +0000 (16:27 -0700)
And account for the fact that, when we are not forwarding, we should
bump statistic counters rather than emit an ICMP response.

RP-filter rejected lookups are still not cached.

Since -EHOSTUNREACH and -ENETUNREACH can now no longer be seen in
ip_rcv_finish(), remove those checks.

Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ip_input.c
net/ipv4/route.c

index bca2517..2a39204 100644 (file)
@@ -342,13 +342,7 @@ static int ip_rcv_finish(struct sk_buff *skb)
                        err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
                                                   iph->tos, skb->dev);
                        if (unlikely(err)) {
-                               if (err == -EHOSTUNREACH)
-                                       IP_INC_STATS_BH(dev_net(skb->dev),
-                                                       IPSTATS_MIB_INADDRERRORS);
-                               else if (err == -ENETUNREACH)
-                                       IP_INC_STATS_BH(dev_net(skb->dev),
-                                                       IPSTATS_MIB_INNOROUTES);
-                               else if (err == -EXDEV)
+                               if (err == -EXDEV)
                                        NET_INC_STATS_BH(dev_net(skb->dev),
                                                         LINUX_MIB_IPRPFILTER);
                                goto drop;
index 846961c..81533e3 100644 (file)
@@ -1609,12 +1609,28 @@ void ip_rt_send_redirect(struct sk_buff *skb)
 
 static int ip_error(struct sk_buff *skb)
 {
+       struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
        struct rtable *rt = skb_rtable(skb);
        struct inet_peer *peer;
        unsigned long now;
+       struct net *net;
        bool send;
        int code;
 
+       net = dev_net(rt->dst.dev);
+       if (!IN_DEV_FORWARD(in_dev)) {
+               switch (rt->dst.error) {
+               case EHOSTUNREACH:
+                       IP_INC_STATS_BH(net, IPSTATS_MIB_INADDRERRORS);
+                       break;
+
+               case ENETUNREACH:
+                       IP_INC_STATS_BH(net, IPSTATS_MIB_INNOROUTES);
+                       break;
+               }
+               goto out;
+       }
+
        switch (rt->dst.error) {
        case EINVAL:
        default:
@@ -1624,8 +1640,7 @@ static int ip_error(struct sk_buff *skb)
                break;
        case ENETUNREACH:
                code = ICMP_NET_UNREACH;
-               IP_INC_STATS_BH(dev_net(rt->dst.dev),
-                               IPSTATS_MIB_INNOROUTES);
+               IP_INC_STATS_BH(net, IPSTATS_MIB_INNOROUTES);
                break;
        case EACCES:
                code = ICMP_PKT_FILTERED;
@@ -2255,11 +2270,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        fl4.daddr = daddr;
        fl4.saddr = saddr;
        err = fib_lookup(net, &fl4, &res);
-       if (err != 0) {
-               if (!IN_DEV_FORWARD(in_dev))
-                       goto e_hostunreach;
+       if (err != 0)
                goto no_route;
-       }
 
        RT_CACHE_STAT_INC(in_slow_tot);
 
@@ -2279,7 +2291,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        }
 
        if (!IN_DEV_FORWARD(in_dev))
-               goto e_hostunreach;
+               goto no_route;
        if (res.type != RTN_UNICAST)
                goto martian_destination;
 
@@ -2367,10 +2379,6 @@ martian_destination:
                                     &daddr, &saddr, dev->name);
 #endif
 
-e_hostunreach:
-       err = -EHOSTUNREACH;
-       goto out;
-
 e_inval:
        err = -EINVAL;
        goto out;