udp: add encap_destroy callback
authorTom Parkin <tparkin@katalix.com>
Tue, 19 Mar 2013 06:11:12 +0000 (06:11 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 20 Mar 2013 16:10:38 +0000 (12:10 -0400)
Users of udp encapsulation currently have an encap_rcv callback which they can
use to hook into the udp receive path.

In situations where a encapsulation user allocates resources associated with a
udp encap socket, it may be convenient to be able to also hook the proto
.destroy operation.  For example, if an encap user holds a reference to the
udp socket, the destroy hook might be used to relinquish this reference.

This patch adds a socket destroy hook into udp, which is set and enabled
in the same way as the existing encap_rcv hook.

Signed-off-by: Tom Parkin <tparkin@katalix.com>
Signed-off-by: James Chapman <jchapman@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/udp.h
net/ipv4/udp.c
net/ipv6/udp.c

index 9d81de1..42278bb 100644 (file)
@@ -68,6 +68,7 @@ struct udp_sock {
         * For encapsulation sockets.
         */
        int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
+       void (*encap_destroy)(struct sock *sk);
 };
 
 static inline struct udp_sock *udp_sk(const struct sock *sk)
index 265c42c..0a073a2 100644 (file)
@@ -1762,9 +1762,16 @@ int udp_rcv(struct sk_buff *skb)
 
 void udp_destroy_sock(struct sock *sk)
 {
+       struct udp_sock *up = udp_sk(sk);
        bool slow = lock_sock_fast(sk);
        udp_flush_pending_frames(sk);
        unlock_sock_fast(sk, slow);
+       if (static_key_false(&udp_encap_needed) && up->encap_type) {
+               void (*encap_destroy)(struct sock *sk);
+               encap_destroy = ACCESS_ONCE(up->encap_destroy);
+               if (encap_destroy)
+                       encap_destroy(sk);
+       }
 }
 
 /*
index 599e1ba..d8e5e85 100644 (file)
@@ -1285,10 +1285,18 @@ do_confirm:
 
 void udpv6_destroy_sock(struct sock *sk)
 {
+       struct udp_sock *up = udp_sk(sk);
        lock_sock(sk);
        udp_v6_flush_pending_frames(sk);
        release_sock(sk);
 
+       if (static_key_false(&udpv6_encap_needed) && up->encap_type) {
+               void (*encap_destroy)(struct sock *sk);
+               encap_destroy = ACCESS_ONCE(up->encap_destroy);
+               if (encap_destroy)
+                       encap_destroy(sk);
+       }
+
        inet6_destroy_sock(sk);
 }