]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/ipv4/route.c
net: Add dummy dst_ops->redirect method where needed.
[karo-tx-linux.git] / net / ipv4 / route.c
index 677d65253e4c601fa8a4f971d7eb57e1164e3e93..23bbe29b3bba6ef7e484ff7a455e1ca146ed8b11 100644 (file)
@@ -149,6 +149,7 @@ static void          ipv4_dst_destroy(struct dst_entry *dst);
 static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
 static void             ipv4_link_failure(struct sk_buff *skb);
 static void             ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
+static void             ip_do_redirect(struct dst_entry *dst, struct sk_buff *skb);
 static int rt_garbage_collect(struct dst_ops *ops);
 
 static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
@@ -158,34 +159,8 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
 
 static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old)
 {
-       struct rtable *rt = (struct rtable *) dst;
-       struct inet_peer *peer;
-       u32 *p = NULL;
-
-       peer = rt_get_peer_create(rt, rt->rt_dst);
-       if (peer) {
-               u32 *old_p = __DST_METRICS_PTR(old);
-               unsigned long prev, new;
-
-               p = peer->metrics;
-               if (inet_metrics_new(peer))
-                       memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
-
-               new = (unsigned long) p;
-               prev = cmpxchg(&dst->_metrics, old, new);
-
-               if (prev != old) {
-                       p = __DST_METRICS_PTR(prev);
-                       if (prev & DST_METRICS_READ_ONLY)
-                               p = NULL;
-               } else {
-                       if (rt->fi) {
-                               fib_info_put(rt->fi);
-                               rt->fi = NULL;
-                       }
-               }
-       }
-       return p;
+       WARN_ON(1);
+       return NULL;
 }
 
 static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
@@ -205,6 +180,7 @@ static struct dst_ops ipv4_dst_ops = {
        .negative_advice =      ipv4_negative_advice,
        .link_failure =         ipv4_link_failure,
        .update_pmtu =          ip_rt_update_pmtu,
+       .redirect =             ip_do_redirect,
        .local_out =            __ip_local_out,
        .neigh_lookup =         ipv4_neigh_lookup,
 };
@@ -915,7 +891,6 @@ static void rt_cache_invalidate(struct net *net)
 
        get_random_bytes(&shuffle, sizeof(shuffle));
        atomic_add(shuffle + 1U, &net->ipv4.rt_genid);
-       inetpeer_invalidate_family(AF_INET);
 }
 
 /*
@@ -1242,22 +1217,6 @@ skip_hashing:
        return rt;
 }
 
-void rt_bind_peer(struct rtable *rt, __be32 daddr, int create)
-{
-       struct inet_peer_base *base;
-       struct inet_peer *peer;
-
-       base = inetpeer_base_ptr(rt->_peer);
-       if (!base)
-               return;
-
-       peer = inet_getpeer_v4(base, daddr, create);
-       if (peer) {
-               if (!rt_set_peer(rt, peer))
-                       inet_putpeer(peer);
-       }
-}
-
 /*
  * Peer allocation may fail only in serious out-of-memory conditions.  However
  * we still can generate some output.
@@ -1314,16 +1273,35 @@ static void rt_del(unsigned int hash, struct rtable *rt)
        spin_unlock_bh(rt_hash_lock_addr(hash));
 }
 
-/* called in rcu_read_lock() section */
-void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
-                   __be32 saddr, struct net_device *dev)
+static void ip_do_redirect(struct dst_entry *dst, struct sk_buff *skb)
 {
-       int s, i;
-       struct in_device *in_dev = __in_dev_get_rcu(dev);
-       __be32 skeys[2] = { saddr, 0 };
-       int    ikeys[2] = { dev->ifindex, 0 };
+       const struct iphdr *iph = (const struct iphdr *) skb->data;
+       __be32 new_gw = icmp_hdr(skb)->un.gateway;
+       __be32 old_gw = ip_hdr(skb)->saddr;
+       struct net_device *dev = skb->dev;
+       __be32 daddr = iph->daddr;
+       __be32 saddr = iph->saddr;
+       struct in_device *in_dev;
+       struct neighbour *n;
+       struct rtable *rt;
        struct net *net;
 
+       switch (icmp_hdr(skb)->code & 7) {
+       case ICMP_REDIR_NET:
+       case ICMP_REDIR_NETTOS:
+       case ICMP_REDIR_HOST:
+       case ICMP_REDIR_HOSTTOS:
+               break;
+
+       default:
+               return;
+       }
+
+       rt = (struct rtable *) dst;
+       if (rt->rt_gateway != old_gw)
+               return;
+
+       in_dev = __in_dev_get_rcu(dev);
        if (!in_dev)
                return;
 
@@ -1343,45 +1321,16 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
                        goto reject_redirect;
        }
 
-       for (s = 0; s < 2; s++) {
-               for (i = 0; i < 2; i++) {
-                       unsigned int hash;
-                       struct rtable __rcu **rthp;
-                       struct rtable *rt;
-
-                       hash = rt_hash(daddr, skeys[s], ikeys[i], rt_genid(net));
-
-                       rthp = &rt_hash_table[hash].chain;
-
-                       while ((rt = rcu_dereference(*rthp)) != NULL) {
-                               struct neighbour *n;
-
-                               rthp = &rt->dst.rt_next;
-
-                               if (rt->rt_key_dst != daddr ||
-                                   rt->rt_key_src != skeys[s] ||
-                                   rt->rt_oif != ikeys[i] ||
-                                   rt_is_input_route(rt) ||
-                                   rt_is_expired(rt) ||
-                                   !net_eq(dev_net(rt->dst.dev), net) ||
-                                   rt->dst.error ||
-                                   rt->dst.dev != dev ||
-                                   rt->rt_gateway != old_gw)
-                                       continue;
-
-                               n = ipv4_neigh_lookup(&rt->dst, NULL, &new_gw);
-                               if (n) {
-                                       if (!(n->nud_state & NUD_VALID)) {
-                                               neigh_event_send(n, NULL);
-                                       } else {
-                                               rt->rt_gateway = new_gw;
-                                               rt->rt_flags |= RTCF_REDIRECTED;
-                                               call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n);
-                                       }
-                                       neigh_release(n);
-                               }
-                       }
+       n = ipv4_neigh_lookup(dst, NULL, &new_gw);
+       if (n) {
+               if (!(n->nud_state & NUD_VALID)) {
+                       neigh_event_send(n, NULL);
+               } else {
+                       rt->rt_gateway = new_gw;
+                       rt->rt_flags |= RTCF_REDIRECTED;
+                       call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n);
                }
+               neigh_release(n);
        }
        return;
 
@@ -1597,6 +1546,34 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
 }
 EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu);
 
+void ipv4_redirect(struct sk_buff *skb, struct net *net,
+                  int oif, u32 mark, u8 protocol, int flow_flags)
+{
+       const struct iphdr *iph = (const struct iphdr *)skb->data;
+       struct flowi4 fl4;
+       struct rtable *rt;
+
+       flowi4_init_output(&fl4, oif, mark, RT_TOS(iph->tos), RT_SCOPE_UNIVERSE,
+                          protocol, flow_flags, iph->daddr, iph->saddr, 0, 0);
+       rt = __ip_route_output_key(net, &fl4);
+       if (!IS_ERR(rt)) {
+               ip_do_redirect(&rt->dst, skb);
+               ip_rt_put(rt);
+       }
+}
+EXPORT_SYMBOL_GPL(ipv4_redirect);
+
+void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk)
+{
+       const struct inet_sock *inet = inet_sk(sk);
+
+       return ipv4_redirect(skb, sock_net(sk), sk->sk_bound_dev_if,
+                            sk->sk_mark,
+                            inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
+                            inet_sk_flowi_flags(sk));
+}
+EXPORT_SYMBOL_GPL(ipv4_sk_redirect);
+
 static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
 {
        struct rtable *rt = (struct rtable *) dst;
@@ -1614,10 +1591,6 @@ static void ipv4_dst_destroy(struct dst_entry *dst)
                fib_info_put(rt->fi);
                rt->fi = NULL;
        }
-       if (rt_has_peer(rt)) {
-               struct inet_peer *peer = rt_peer_ptr(rt);
-               inet_putpeer(peer);
-       }
 }
 
 
@@ -1737,47 +1710,27 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
 static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
                            struct fib_info *fi)
 {
-       struct inet_peer_base *base;
-       struct inet_peer *peer;
-
-       base = inetpeer_base_ptr(rt->_peer);
-       BUG_ON(!base);
-
-       peer = inet_getpeer_v4(base, rt->rt_dst, 0);
-       if (peer) {
-               __rt_set_peer(rt, peer);
-               if (inet_metrics_new(peer))
-                       memcpy(peer->metrics, fi->fib_metrics,
-                              sizeof(u32) * RTAX_MAX);
-               dst_init_metrics(&rt->dst, peer->metrics, false);
-       } else {
-               if (fi->fib_metrics != (u32 *) dst_default_metrics) {
-                       rt->fi = fi;
-                       atomic_inc(&fi->fib_clntref);
-               }
-               dst_init_metrics(&rt->dst, fi->fib_metrics, true);
+       if (fi->fib_metrics != (u32 *) dst_default_metrics) {
+               rt->fi = fi;
+               atomic_inc(&fi->fib_clntref);
        }
+       dst_init_metrics(&rt->dst, fi->fib_metrics, true);
 }
 
 static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *fl4,
                           const struct fib_result *res,
                           struct fib_info *fi, u16 type, u32 itag)
 {
-       struct dst_entry *dst = &rt->dst;
-
        if (fi) {
                if (FIB_RES_GW(*res) &&
                    FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
                        rt->rt_gateway = FIB_RES_GW(*res);
                rt_init_metrics(rt, fl4, fi);
 #ifdef CONFIG_IP_ROUTE_CLASSID
-               dst->tclassid = FIB_RES_NH(*res).nh_tclassid;
+               rt->dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
 #endif
        }
 
-       if (dst_mtu(dst) > IP_MAX_MTU)
-               dst_metric_set(dst, RTAX_MTU, IP_MAX_MTU);
-
 #ifdef CONFIG_IP_ROUTE_CLASSID
 #ifdef CONFIG_IP_MULTIPLE_TABLES
        set_class_tag(rt, fib_rules_tclass(res));
@@ -1851,7 +1804,6 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        rth->rt_mark    = skb->mark;
        rth->rt_pmtu    = 0;
        rth->rt_gateway = daddr;
-       rt_init_peer(rth, dev_net(dev)->ipv4.peers);
        rth->fi = NULL;
        if (our) {
                rth->dst.input= ip_local_deliver;
@@ -1977,7 +1929,6 @@ static int __mkroute_input(struct sk_buff *skb,
        rth->rt_mark    = skb->mark;
        rth->rt_pmtu    = 0;
        rth->rt_gateway = daddr;
-       rt_init_peer(rth, &res->table->tb_peers);
        rth->fi = NULL;
 
        rth->dst.input = ip_forward;
@@ -2156,7 +2107,6 @@ local_input:
        rth->rt_mark    = skb->mark;
        rth->rt_pmtu    = 0;
        rth->rt_gateway = daddr;
-       rt_init_peer(rth, net->ipv4.peers);
        rth->fi = NULL;
        if (res.type == RTN_UNREACHABLE) {
                rth->dst.input= ip_error;
@@ -2354,9 +2304,6 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
        rth->rt_mark    = fl4->flowi4_mark;
        rth->rt_pmtu    = 0;
        rth->rt_gateway = fl4->daddr;
-       rt_init_peer(rth, (res->table ?
-                          &res->table->tb_peers :
-                          dev_net(dev_out)->ipv4.peers));
        rth->fi = NULL;
 
        RT_CACHE_STAT_INC(out_slow_tot);
@@ -2644,6 +2591,10 @@ static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
 }
 
+static void ipv4_rt_blackhole_redirect(struct dst_entry *dst, struct sk_buff *skb)
+{
+}
+
 static u32 *ipv4_rt_blackhole_cow_metrics(struct dst_entry *dst,
                                          unsigned long old)
 {
@@ -2658,6 +2609,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
        .mtu                    =       ipv4_blackhole_mtu,
        .default_advmss         =       ipv4_default_advmss,
        .update_pmtu            =       ipv4_rt_blackhole_update_pmtu,
+       .redirect               =       ipv4_rt_blackhole_redirect,
        .cow_metrics            =       ipv4_rt_blackhole_cow_metrics,
        .neigh_lookup           =       ipv4_neigh_lookup,
 };
@@ -2673,7 +2625,6 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
                new->__use = 1;
                new->input = dst_discard;
                new->output = dst_discard;
-               dst_copy_metrics(new, &ort->dst);
 
                new->dev = ort->dst.dev;
                if (new->dev)
@@ -2694,7 +2645,6 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
                rt->rt_dst = ort->rt_dst;
                rt->rt_src = ort->rt_src;
                rt->rt_gateway = ort->rt_gateway;
-               rt_transfer_peer(rt, ort);
                rt->fi = ort->fi;
                if (rt->fi)
                        atomic_inc(&rt->fi->fib_clntref);
@@ -2732,7 +2682,7 @@ static int rt_fill_info(struct net *net,
        struct rtmsg *r;
        struct nlmsghdr *nlh;
        unsigned long expires = 0;
-       u32 id = 0, error;
+       u32 error;
 
        nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
        if (nlh == NULL)
@@ -2785,11 +2735,6 @@ static int rt_fill_info(struct net *net,
                goto nla_put_failure;
 
        error = rt->dst.error;
-       if (rt_has_peer(rt)) {
-               const struct inet_peer *peer = rt_peer_ptr(rt);
-               inet_peer_refcheck(peer);
-               id = atomic_read(&peer->ip_id_count) & 0xffff;
-       }
        expires = rt->dst.expires;
        if (expires) {
                if (time_before(jiffies, expires))
@@ -2824,7 +2769,7 @@ static int rt_fill_info(struct net *net,
                                goto nla_put_failure;
        }
 
-       if (rtnl_put_cacheinfo(skb, &rt->dst, id, expires, error) < 0)
+       if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, error) < 0)
                goto nla_put_failure;
 
        return nlmsg_end(skb, nlh);