ipv6: Add infrastructure to bind inet_peer objects to routes.
David S. Miller [Tue, 30 Nov 2010 20:27:11 +0000 (12:27 -0800)]
They are only allowed on cached ipv6 routes.

Signed-off-by: David S. Miller <davem@davemloft.net>

include/net/ip6_fib.h
include/net/ip6_route.h
net/ipv4/inetpeer.c
net/ipv6/route.c

index 062a823..708ff7c 100644 (file)
@@ -21,6 +21,7 @@
 #include <net/dst.h>
 #include <net/flow.h>
 #include <net/netlink.h>
+#include <net/inetpeer.h>
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 #define FIB6_TABLE_HASHSZ 256
@@ -109,6 +110,7 @@ struct rt6_info {
        u32                             rt6i_metric;
 
        struct inet6_dev                *rt6i_idev;
+       struct inet_peer                *rt6i_peer;
 
 #ifdef CONFIG_XFRM
        u32                             rt6i_flow_cache_genid;
index 278312c..23fed28 100644 (file)
@@ -56,6 +56,9 @@ static inline unsigned int rt6_flags2srcprefs(int flags)
        return (flags >> 3) & 7;
 }
 
+extern void                    rt6_bind_peer(struct rt6_info *rt,
+                                             int create);
+
 extern void                    ip6_route_input(struct sk_buff *skb);
 
 extern struct dst_entry *      ip6_route_output(struct net *net,
index 1c1335b..f95b89f 100644 (file)
@@ -532,6 +532,7 @@ static int compute_total(void)
 {
        return v4_peers.total + v6_peers.total;
 }
+EXPORT_SYMBOL_GPL(inet_getpeer);
 
 /* Called with local BH disabled. */
 static void peer_check_expire(unsigned long dummy)
@@ -577,3 +578,4 @@ void inet_putpeer(struct inet_peer *p)
 
        local_bh_enable();
 }
+EXPORT_SYMBOL_GPL(inet_putpeer);
index a0c4ad1..026caef 100644 (file)
@@ -188,11 +188,29 @@ static void ip6_dst_destroy(struct dst_entry *dst)
 {
        struct rt6_info *rt = (struct rt6_info *)dst;
        struct inet6_dev *idev = rt->rt6i_idev;
+       struct inet_peer *peer = rt->rt6i_peer;
 
        if (idev != NULL) {
                rt->rt6i_idev = NULL;
                in6_dev_put(idev);
        }
+       if (peer) {
+               BUG_ON(!(rt->rt6i_flags & RTF_CACHE));
+               rt->rt6i_peer = NULL;
+               inet_putpeer(peer);
+       }
+}
+
+void rt6_bind_peer(struct rt6_info *rt, int create)
+{
+       struct inet_peer *peer;
+
+       if (WARN_ON(!(rt->rt6i_flags & RTF_CACHE)))
+               return;
+
+       peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create);
+       if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL)
+               inet_putpeer(peer);
 }
 
 static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,