[CRIU] [PATCH 06/12] soccr/tcp: Read queues contents using library
Pavel Emelyanov
xemul at virtuozzo.com
Fri Aug 5 08:00:51 PDT 2016
Signed-off-by: Pavel Emelyanov <xemul at virtuozzo.com>
---
criu/sk-tcp.c | 118 +++++++---------------------------------------------------
soccr/soccr.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++
soccr/soccr.h | 1 +
3 files changed, 119 insertions(+), 105 deletions(-)
diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c
index 4e23bab..e1181dc 100644
--- a/criu/sk-tcp.c
+++ b/criu/sk-tcp.c
@@ -158,89 +158,13 @@ void cpt_unlock_tcp_connections(void)
tcp_unlock_one(sk);
}
-/*
- * TCP queues sequences and their relations to the code below
- *
- * output queue
- * net <----------------------------- sk
- * ^ ^ ^ seq >>
- * snd_una snd_nxt write_seq
- *
- * input queue
- * net -----------------------------> sk
- * << seq ^ ^
- * rcv_nxt copied_seq
- *
- *
- * inq_len = rcv_nxt - copied_seq = SIOCINQ
- * outq_len = write_seq - snd_una = SIOCOUTQ
- * inq_seq = rcv_nxt
- * outq_seq = write_seq
- *
- * On restore kernel moves the option we configure with setsockopt,
- * thus we should advance them on the _len value in restore_tcp_seqs.
- *
- */
-
-static int tcp_stream_get_queue(int sk, int queue_id,
- u32 *seq, u32 len, char **bufp)
-{
- int ret, aux;
- socklen_t auxl;
- char *buf;
-
- pr_debug("\tSet repair queue %d\n", queue_id);
- aux = queue_id;
- auxl = sizeof(aux);
- ret = setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &aux, auxl);
- if (ret < 0)
- goto err_sopt;
-
- pr_debug("\tGet queue seq\n");
- auxl = sizeof(*seq);
- ret = getsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, seq, &auxl);
- if (ret < 0)
- goto err_sopt;
-
- pr_info("\t`- seq %u len %u\n", *seq, len);
-
- if (len) {
- /*
- * Try to grab one byte more from the queue to
- * make sure there are len bytes for real
- */
- buf = xmalloc(len + 1);
- if (!buf)
- goto err_buf;
-
- pr_debug("\tReading queue (%d bytes)\n", len);
- ret = recv(sk, buf, len + 1, MSG_PEEK | MSG_DONTWAIT);
- if (ret != len)
- goto err_recv;
- } else
- buf = NULL;
-
- *bufp = buf;
- return 0;
-
-err_sopt:
- pr_perror("\tsockopt failed");
-err_buf:
- return -1;
-
-err_recv:
- pr_perror("\trecv failed (%d, want %d, errno %d)", ret, len, errno);
- xfree(buf);
- goto err_buf;
-}
-
static int dump_tcp_conn_state(struct inet_sk_desc *sk)
{
struct libsoccr_sk *socr = sk->priv;
int ret, aux;
struct cr_img *img;
TcpStreamEntry tse = TCP_STREAM_ENTRY__INIT;
- char *in_buf, *out_buf;
+ char *buf;
struct libsoccr_sk_data data;
ret = libsoccr_get_sk_data(socr, &data, sizeof(data));
@@ -253,7 +177,9 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk)
}
tse.inq_len = data.inq_len;
+ tse.inq_seq = data.inq_seq;
tse.outq_len = data.outq_len;
+ tse.outq_seq = data.outq_seq;
tse.unsq_len = data.unsq_len;
tse.has_unsq_len = true;
tse.mss_clamp = data.mss_clamp;
@@ -282,26 +208,6 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk)
}
/*
- * Read queue
- */
-
- pr_info("Reading inq for socket\n");
- ret = tcp_stream_get_queue(sk->rfd, TCP_RECV_QUEUE,
- &tse.inq_seq, tse.inq_len, &in_buf);
- if (ret < 0)
- goto err_in;
-
- /*
- * Write queue
- */
-
- pr_info("Reading outq for socket\n");
- ret = tcp_stream_get_queue(sk->rfd, TCP_SEND_QUEUE,
- &tse.outq_seq, tse.outq_len, &out_buf);
- if (ret < 0)
- goto err_out;
-
- /*
* TCP socket options
*/
@@ -333,16 +239,22 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk)
if (ret < 0)
goto err_iw;
- if (in_buf) {
- ret = write_img_buf(img, in_buf, tse.inq_len);
+ buf = libsoccr_get_queue_bytes(socr, TCP_RECV_QUEUE, 1);
+ if (buf) {
+ ret = write_img_buf(img, buf, tse.inq_len);
if (ret < 0)
goto err_iw;
+
+ xfree(buf);
}
- if (out_buf) {
- ret = write_img_buf(img, out_buf, tse.outq_len);
+ buf = libsoccr_get_queue_bytes(socr, TCP_SEND_QUEUE, 1);
+ if (buf) {
+ ret = write_img_buf(img, buf, tse.outq_len);
if (ret < 0)
goto err_iw;
+
+ xfree(buf);
}
pr_info("Done\n");
@@ -350,10 +262,6 @@ err_iw:
close_image(img);
err_img:
err_opt:
- xfree(out_buf);
-err_out:
- xfree(in_buf);
-err_in:
err_r:
return ret;
}
diff --git a/soccr/soccr.c b/soccr/soccr.c
index 12975fd..d157032 100644
--- a/soccr/soccr.c
+++ b/soccr/soccr.c
@@ -59,6 +59,8 @@ static void tcp_repair_off(int fd)
struct libsoccr_sk {
int fd;
+ char *recv_queue;
+ char *send_queue;
};
struct libsoccr_sk *libsoccr_pause(int fd)
@@ -74,6 +76,8 @@ struct libsoccr_sk *libsoccr_pause(int fd)
return NULL;
}
+ ret->recv_queue = NULL;
+ ret->send_queue = NULL;
ret->fd = fd;
return ret;
}
@@ -81,6 +85,8 @@ struct libsoccr_sk *libsoccr_pause(int fd)
void libsoccr_resume(struct libsoccr_sk *sk)
{
tcp_repair_off(sk->fd);
+ free(sk->send_queue);
+ free(sk->recv_queue);
free(sk);
}
@@ -186,6 +192,77 @@ static int get_window(struct libsoccr_sk *sk, struct libsoccr_sk_data *data)
}
/*
+ * TCP queues sequences and their relations to the code below
+ *
+ * output queue
+ * net <----------------------------- sk
+ * ^ ^ ^ seq >>
+ * snd_una snd_nxt write_seq
+ *
+ * input queue
+ * net -----------------------------> sk
+ * << seq ^ ^
+ * rcv_nxt copied_seq
+ *
+ *
+ * inq_len = rcv_nxt - copied_seq = SIOCINQ
+ * outq_len = write_seq - snd_una = SIOCOUTQ
+ * inq_seq = rcv_nxt
+ * outq_seq = write_seq
+ *
+ * On restore kernel moves the option we configure with setsockopt,
+ * thus we should advance them on the _len value in restore_tcp_seqs.
+ *
+ */
+
+static int get_queue(int sk, int queue_id,
+ __u32 *seq, __u32 len, char **bufp)
+{
+ int ret, aux;
+ socklen_t auxl;
+ char *buf;
+
+ aux = queue_id;
+ auxl = sizeof(aux);
+ ret = setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &aux, auxl);
+ if (ret < 0)
+ goto err_sopt;
+
+ auxl = sizeof(*seq);
+ ret = getsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, seq, &auxl);
+ if (ret < 0)
+ goto err_sopt;
+
+ if (len) {
+ /*
+ * Try to grab one byte more from the queue to
+ * make sure there are len bytes for real
+ */
+ buf = malloc(len + 1);
+ if (!buf)
+ goto err_buf;
+
+ ret = recv(sk, buf, len + 1, MSG_PEEK | MSG_DONTWAIT);
+ if (ret != len)
+ goto err_recv;
+ } else
+ buf = NULL;
+
+ *bufp = buf;
+ return 0;
+
+err_sopt:
+ loge("\tsockopt failed");
+err_buf:
+ return -1;
+
+err_recv:
+ loge("\trecv failed (%d, want %d)", ret, len);
+ free(buf);
+ goto err_buf;
+}
+
+/*
* This is how much data we've had in the initial libsoccr
*/
#define SOCR_DATA_MIN_SIZE (16 * sizeof(__u32))
@@ -208,5 +285,33 @@ int libsoccr_get_sk_data(struct libsoccr_sk *sk, struct libsoccr_sk_data *data,
if (get_window(sk, data))
return -4;
+ if (get_queue(sk->fd, TCP_RECV_QUEUE, &data->inq_seq, data->inq_len, &sk->recv_queue))
+ return -4;
+
+ if (get_queue(sk->fd, TCP_SEND_QUEUE, &data->outq_seq, data->outq_len, &sk->send_queue))
+ return -5;
+
return sizeof(struct libsoccr_sk_data);
}
+
+char *libsoccr_get_queue_bytes(struct libsoccr_sk *sk, int queue_id, int steal)
+{
+ char **p, *ret;
+
+ switch (queue_id) {
+ case TCP_RECV_QUEUE:
+ p = &sk->recv_queue;
+ break;
+ case TCP_SEND_QUEUE:
+ p = &sk->send_queue;
+ break;
+ default:
+ return NULL;
+ }
+
+ ret = *p;
+ if (steal)
+ *p = NULL;
+
+ return ret;
+}
diff --git a/soccr/soccr.h b/soccr/soccr.h
index a55d01e..f6c54bd 100644
--- a/soccr/soccr.h
+++ b/soccr/soccr.h
@@ -51,5 +51,6 @@ struct libsoccr_sk *libsoccr_pause(int fd);
void libsoccr_resume(struct libsoccr_sk *sk);
int libsoccr_get_sk_data(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size);
+char *libsoccr_get_queue_bytes(struct libsoccr_sk *sk, int queue_id, int steal);
#endif
--
2.5.0
More information about the CRIU
mailing list