mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-17 16:47:50 +00:00
soccr/tcp: Fill actual connection info using the library
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
This commit is contained in:
parent
4fdc20ed40
commit
d98c0ea67c
2 changed files with 161 additions and 138 deletions
166
criu/sk-tcp.c
166
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>
|
||||
|
|
@ -29,11 +27,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;
|
||||
|
|
@ -92,48 +85,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;
|
||||
|
|
@ -282,80 +233,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;
|
||||
|
|
@ -370,16 +251,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)
|
||||
|
|
@ -390,26 +295,11 @@ 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
|
||||
*/
|
||||
|
|
|
|||
133
soccr/soccr.c
133
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue