[05/12] soccr/tcp: Fill actual connection info using the library (v2)

Submitted by Pavel Emelianov on Aug. 5, 2016, 3 p.m.

Details

Message ID 57A4AA0E.2090807@virtuozzo.com
State Accepted
Series "Introduce library for socket C/R"
Commit 607c656c9aeb615518e646835d8bba313de80b53
Headers show

Commit Message

Pavel Emelianov Aug. 5, 2016, 3 p.m.
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
---
 criu/sk-tcp.c | 166 ++++++++++------------------------------------------------
 soccr/soccr.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 161 insertions(+), 138 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c
index 763d754..4e23bab 100644
--- a/criu/sk-tcp.c
+++ b/criu/sk-tcp.c
@@ -1,6 +1,4 @@ 
 #include <netinet/tcp.h>
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/mman.h>
@@ -30,11 +28,6 @@ 
 #include "protobuf.h"
 #include "images/tcp-stream.pb-c.h"
 
-#ifndef SIOCOUTQNSD
-/* MAO - Define SIOCOUTQNSD ioctl if we don't have it */
-#define SIOCOUTQNSD     0x894B
-#endif
-
 #ifndef CONFIG_HAS_TCP_REPAIR_WINDOW
 struct tcp_repair_window {
 	u32   snd_wl1;
@@ -93,48 +86,6 @@  static int tcp_repair_on(int fd)
 	return ret;
 }
 
-static int refresh_inet_sk(struct inet_sk_desc *sk, struct tcp_info *ti)
-{
-	int size;
-
-	if (dump_opt(sk->rfd, SOL_TCP, TCP_INFO, ti)) {
-		pr_perror("Failed to obtain TCP_INFO");
-		return -1;
-	}
-
-	switch (ti->tcpi_state) {
-	case TCP_ESTABLISHED:
-	case TCP_CLOSE:
-		break;
-	default:
-		pr_err("Unknown state %d\n", sk->state);
-		return -1;
-	}
-
-	if (ioctl(sk->rfd, SIOCOUTQ, &size) == -1) {
-		pr_perror("Unable to get size of snd queue");
-		return -1;
-	}
-
-	sk->wqlen = size;
-
-	if (ioctl(sk->rfd, SIOCOUTQNSD, &size) == -1) {
-		pr_perror("Unable to get size of unsent data");
-		return -1;
-	}
-
-	sk->uwqlen = size;
-
-	if (ioctl(sk->rfd, SIOCINQ, &size) == -1) {
-		pr_perror("Unable to get size of recv queue");
-		return -1;
-	}
-
-	sk->rqlen = size;
-
-	return 0;
-}
-
 static int tcp_repair_establised(int fd, struct inet_sk_desc *sk)
 {
 	int ret;
@@ -283,80 +234,10 @@  err_recv:
 	goto err_buf;
 }
 
-static int tcp_stream_get_options(int sk, struct tcp_info *ti, TcpStreamEntry *tse)
-{
-	int ret;
-	socklen_t auxl;
-	int val;
-
-	auxl = sizeof(tse->mss_clamp);
-	ret = getsockopt(sk, SOL_TCP, TCP_MAXSEG, &tse->mss_clamp, &auxl);
-	if (ret < 0)
-		goto err_sopt;
-
-	tse->opt_mask = ti->tcpi_options;
-	if (ti->tcpi_options & TCPI_OPT_WSCALE) {
-		tse->snd_wscale = ti->tcpi_snd_wscale;
-		tse->rcv_wscale = ti->tcpi_rcv_wscale;
-		tse->has_rcv_wscale = true;
-	}
-
-	if (ti->tcpi_options & TCPI_OPT_TIMESTAMPS) {
-		auxl = sizeof(val);
-		ret = getsockopt(sk, SOL_TCP, TCP_TIMESTAMP, &val, &auxl);
-		if (ret < 0)
-			goto err_sopt;
-
-		tse->has_timestamp = true;
-		tse->timestamp = val;
-	}
-
-	pr_info("\toptions: mss_clamp %x wscale %x tstamp %d sack %d\n",
-			(int)tse->mss_clamp,
-			ti->tcpi_options & TCPI_OPT_WSCALE ? (int)tse->snd_wscale : -1,
-			ti->tcpi_options & TCPI_OPT_TIMESTAMPS ? 1 : 0,
-			ti->tcpi_options & TCPI_OPT_SACK ? 1 : 0);
-
-	return 0;
-
-err_sopt:
-	pr_perror("\tsockopt failed");
-	return -1;
-}
-
-static int tcp_get_window(int sk, TcpStreamEntry *tse)
-{
-	struct tcp_repair_window opt;
-	socklen_t optlen = sizeof(opt);
-
-	if (!kdat.has_tcp_window)
-		return 0;
-
-	if (getsockopt(sk, SOL_TCP,
-			TCP_REPAIR_WINDOW, &opt, &optlen)) {
-		pr_perror("Unable to get window properties");
-		return -1;
-	}
-
-	tse->has_snd_wl1	= true;
-	tse->has_snd_wnd	= true;
-	tse->has_max_window	= true;
-	tse->has_rcv_wnd	= true;
-	tse->has_rcv_wup	= true;
-	tse->snd_wl1		= opt.snd_wl1;
-	tse->snd_wnd		= opt.snd_wnd;
-	tse->max_window		= opt.max_window;
-	tse->rcv_wnd		= opt.rcv_wnd;
-	tse->rcv_wup		= opt.rcv_wup;
-
-	return 0;
-}
-
 static int dump_tcp_conn_state(struct inet_sk_desc *sk)
 {
 	struct libsoccr_sk *socr = sk->priv;
 	int ret, aux;
-	struct tcp_info ti;
 	struct cr_img *img;
 	TcpStreamEntry tse = TCP_STREAM_ENTRY__INIT;
 	char *in_buf, *out_buf;
@@ -371,16 +252,40 @@  static int dump_tcp_conn_state(struct inet_sk_desc *sk)
 		goto err_r;
 	}
 
-	ret = refresh_inet_sk(sk, &ti);
-	if (ret < 0)
-		goto err_r;
+	tse.inq_len = data.inq_len;
+	tse.outq_len = data.outq_len;
+	tse.unsq_len = data.unsq_len;
+	tse.has_unsq_len = true;
+	tse.mss_clamp = data.mss_clamp;
+	tse.opt_mask = data.opt_mask;
+	if (tse.opt_mask & TCPI_OPT_WSCALE) {
+		tse.snd_wscale = data.snd_wscale;
+		tse.rcv_wscale = data.rcv_wscale;
+		tse.has_rcv_wscale = true;
+	}
+	if (tse.opt_mask & TCPI_OPT_TIMESTAMPS) {
+		tse.timestamp = data.timestamp;
+		tse.has_timestamp = true;
+	}
+
+	if (data.flags & SOCCR_FLAGS_WINDOW) {
+		tse.has_snd_wl1		= true;
+		tse.has_snd_wnd		= true;
+		tse.has_max_window	= true;
+		tse.has_rcv_wnd		= true;
+		tse.has_rcv_wup		= true;
+		tse.snd_wl1		= data.snd_wl1;
+		tse.snd_wnd		= data.snd_wnd;
+		tse.max_window		= data.max_window;
+		tse.rcv_wnd		= data.rcv_wnd;
+		tse.rcv_wup		= data.rcv_wup;
+	}
 
 	/*
 	 * Read queue
 	 */
 
 	pr_info("Reading inq for socket\n");
-	tse.inq_len = sk->rqlen;
 	ret = tcp_stream_get_queue(sk->rfd, TCP_RECV_QUEUE,
 			&tse.inq_seq, tse.inq_len, &in_buf);
 	if (ret < 0)
@@ -391,27 +296,12 @@  static int dump_tcp_conn_state(struct inet_sk_desc *sk)
 	 */
 
 	pr_info("Reading outq for socket\n");
-	tse.outq_len = sk->wqlen;
-	tse.unsq_len = sk->uwqlen;
-	tse.has_unsq_len = true;
 	ret = tcp_stream_get_queue(sk->rfd, TCP_SEND_QUEUE,
 			&tse.outq_seq, tse.outq_len, &out_buf);
 	if (ret < 0)
 		goto err_out;
 
 	/*
-	 * Initial options
-	 */
-
-	pr_info("Reading options for socket\n");
-	ret = tcp_stream_get_options(sk->rfd, &ti, &tse);
-	if (ret < 0)
-		goto err_opt;
-
-	if (tcp_get_window(sk->rfd, &tse))
-		goto err_opt;
-
-	/*
 	 * TCP socket options
 	 */
 
diff --git a/soccr/soccr.c b/soccr/soccr.c
index 130f604..12975fd 100644
--- a/soccr/soccr.c
+++ b/soccr/soccr.c
@@ -1,8 +1,29 @@ 
 #include <netinet/tcp.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <linux/sockios.h>
 #include "soccr.h"
 
+#ifndef SIOCOUTQNSD
+/* MAO - Define SIOCOUTQNSD ioctl if we don't have it */
+#define SIOCOUTQNSD     0x894B
+#endif
+
+#ifndef TCP_REPAIR_WINDOW
+#define TCP_REPAIR_WINDOW       29
+#endif
+
+struct tcp_repair_window {
+	__u32   snd_wl1;
+	__u32   snd_wnd;
+	__u32   max_window;
+
+	__u32   rcv_wnd;
+	__u32   rcv_wup;
+};
+
 static void (*log)(unsigned int loglevel, const char *format, ...)
 	__attribute__ ((__format__ (__printf__, 2, 3)));
 static unsigned int log_level = 0;
@@ -63,6 +84,107 @@  void libsoccr_resume(struct libsoccr_sk *sk)
 	free(sk);
 }
 
+static int refresh_sk(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, struct tcp_info *ti)
+{
+	int size;
+	socklen_t olen = sizeof(*ti);
+
+	if (getsockopt(sk->fd, SOL_TCP, TCP_INFO, ti, &olen) || olen != sizeof(*ti)) {
+		loge("Failed to obtain TCP_INFO");
+		return -1;
+	}
+
+	switch (ti->tcpi_state) {
+	case TCP_ESTABLISHED:
+	case TCP_CLOSE:
+		break;
+	default:
+		loge("Unknown state %d\n", ti->tcpi_state);
+		return -1;
+	}
+
+	if (ioctl(sk->fd, SIOCOUTQ, &size) == -1) {
+		loge("Unable to get size of snd queue");
+		return -1;
+	}
+
+	data->outq_len = size;
+
+	if (ioctl(sk->fd, SIOCOUTQNSD, &size) == -1) {
+		loge("Unable to get size of unsent data");
+		return -1;
+	}
+
+	data->unsq_len = size;
+
+	if (ioctl(sk->fd, SIOCINQ, &size) == -1) {
+		loge("Unable to get size of recv queue");
+		return -1;
+	}
+
+	data->inq_len = size;
+
+	return 0;
+}
+
+static int get_stream_options(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, struct tcp_info *ti)
+{
+	int ret;
+	socklen_t auxl;
+	int val;
+
+	auxl = sizeof(data->mss_clamp);
+	ret = getsockopt(sk->fd, SOL_TCP, TCP_MAXSEG, &data->mss_clamp, &auxl);
+	if (ret < 0)
+		goto err_sopt;
+
+	data->opt_mask = ti->tcpi_options;
+	if (ti->tcpi_options & TCPI_OPT_WSCALE) {
+		data->snd_wscale = ti->tcpi_snd_wscale;
+		data->rcv_wscale = ti->tcpi_rcv_wscale;
+	}
+
+	if (ti->tcpi_options & TCPI_OPT_TIMESTAMPS) {
+		auxl = sizeof(val);
+		ret = getsockopt(sk->fd, SOL_TCP, TCP_TIMESTAMP, &val, &auxl);
+		if (ret < 0)
+			goto err_sopt;
+
+		data->timestamp = val;
+	}
+
+	return 0;
+
+err_sopt:
+	loge("\tsockopt failed");
+	return -1;
+}
+
+static int get_window(struct libsoccr_sk *sk, struct libsoccr_sk_data *data)
+{
+	struct tcp_repair_window opt;
+	socklen_t optlen = sizeof(opt);
+
+	if (getsockopt(sk->fd, SOL_TCP,
+			TCP_REPAIR_WINDOW, &opt, &optlen)) {
+		/* Appeared since 4.8, but TCP_repair itself is since 3.11 */
+		if (errno == ENOPROTOOPT)
+			return 0;
+
+		loge("Unable to get window properties");
+		return -1;
+	}
+
+	data->flags |= SOCCR_FLAGS_WINDOW;
+	data->snd_wl1		= opt.snd_wl1;
+	data->snd_wnd		= opt.snd_wnd;
+	data->max_window	= opt.max_window;
+	data->rcv_wnd		= opt.rcv_wnd;
+	data->rcv_wup		= opt.rcv_wup;
+
+	return 0;
+}
+
 /*
  * This is how much data we've had in the initial libsoccr
  */
@@ -70,10 +192,21 @@  void libsoccr_resume(struct libsoccr_sk *sk)
 
 int libsoccr_get_sk_data(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size)
 {
+	struct tcp_info ti;
+
 	if (!data || data_size < SOCR_DATA_MIN_SIZE)
 		return -1;
 
 	memset(data, 0, data_size);
 
+	if (refresh_sk(sk, data, &ti))
+		return -2;
+
+	if (get_stream_options(sk, data, &ti))
+		return -3;
+
+	if (get_window(sk, data))
+		return -4;
+
 	return sizeof(struct libsoccr_sk_data);
 }