diff mbox

[4/4] net: diag: Support destroying TCP sockets.

Message ID 1447811024-8553-5-git-send-email-lorenzo@google.com
State Superseded, archived
Delegated to: David Miller
Headers show

Commit Message

Lorenzo Colitti Nov. 18, 2015, 1:43 a.m. UTC
This implements SOCK_DESTROY for TCP sockets. It causes all
blocking calls on the socket to fail fast with ETIMEDOUT, which
is the same thing that would eventually happen if the socket was
left stuck on an IP address that the host no longer has.

Change-Id: Icce9db8b832e84c9b6477e5a901c927b942f2bb9
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
---
 net/ipv4/tcp_diag.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

Comments

kernel test robot Nov. 18, 2015, 3:43 a.m. UTC | #1
Hi Lorenzo,

[auto build test ERROR on net/master]
[also build test ERROR on v4.4-rc1 next-20151117]

url:    https://github.com/0day-ci/linux/commits/Lorenzo-Colitti/net-diag-split-inet_diag_dump_one_icsk-into-two/20151118-094638
config: x86_64-rhel (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

>> ERROR: "inet_diag_find_one_icsk" [net/ipv4/tcp_diag.ko] undefined!

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot Nov. 18, 2015, 4:25 a.m. UTC | #2
Hi Lorenzo,

[auto build test ERROR on net/master]
[also build test ERROR on v4.4-rc1 next-20151117]

url:    https://github.com/0day-ci/linux/commits/Lorenzo-Colitti/net-diag-split-inet_diag_dump_one_icsk-into-two/20151118-094638
config: i386-allmodconfig (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

>> ERROR: "inet_diag_find_one_icsk" undefined!

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Lorenzo Colitti Nov. 18, 2015, 4:46 a.m. UTC | #3
On Wed, Nov 18, 2015 at 12:43 PM, kbuild test robot <lkp@intel.com> wrote:
> All errors (new ones prefixed by >>):
>
>>> ERROR: "inet_diag_find_one_icsk" [net/ipv4/tcp_diag.ko] undefined!

Oops. Missing export. Should be fixed in v2.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index b316040..867159c 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -10,6 +10,7 @@ 
  */
 
 #include <linux/module.h>
+#include <linux/net.h>
 #include <linux/inet_diag.h>
 
 #include <linux/tcp.h>
@@ -46,12 +47,52 @@  static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
 	return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req);
 }
 
+static int tcp_diag_destroy(struct sk_buff *in_skb,
+			    const struct inet_diag_req_v2 *req)
+{
+	struct sock *sk;
+	struct net *net = sock_net(in_skb->sk);
+
+	if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+		return -EPERM;
+
+	sk = inet_diag_find_one_icsk(net, &tcp_hashinfo, req);
+	if (IS_ERR(sk))
+		return PTR_ERR(sk);
+
+	if (!sk_fullsock(sk)) {
+		sock_gen_put(sk);
+		return -EOPNOTSUPP;
+	}
+
+	/* Don't race with userspace socket closes such as tcp_close. */
+	lock_sock(sk);
+
+	/* Don't race with BH socket closes such as inet_csk_listen_stop. */
+	local_bh_disable();
+	bh_lock_sock(sk);
+
+	if (!sock_flag(sk, SOCK_DEAD)) {
+		smp_wmb();  /* Be consistent with tcp_reset */
+		sk->sk_err = ETIMEDOUT;
+		sk->sk_error_report(sk);
+		tcp_done(sk);
+	}
+
+	bh_unlock_sock(sk);
+	local_bh_enable();
+	release_sock(sk);
+	sock_put(sk);
+	return 0;
+}
+
 static const struct inet_diag_handler tcp_diag_handler = {
 	.dump		 = tcp_diag_dump,
 	.dump_one	 = tcp_diag_dump_one,
 	.idiag_get_info	 = tcp_diag_get_info,
 	.idiag_type	 = IPPROTO_TCP,
 	.idiag_info_size = sizeof(struct tcp_info),
+	.destroy	 = tcp_diag_destroy,
 };
 
 static int __init tcp_diag_init(void)