Commit f3253a40 authored by Stanislav Kinsbursky's avatar Stanislav Kinsbursky Committed by Cyrill Gorcunov

checkpoint: IPv4 listening sockets dumping support

parent 654216c1
......@@ -85,6 +85,13 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
.fmt = FMT_FNAME_UNIXSK,
.magic = UNIXSK_MAGIC,
},
/* info about inet sockets */
[CR_FD_INETSK] = {
.fmt = FMT_FNAME_INETSK,
.magic = INETSK_MAGIC,
},
};
static struct cr_fdset *alloc_cr_fdset(void)
......
......@@ -24,6 +24,7 @@ enum {
CR_FD_SHMEM,
CR_FD_SIGACT,
CR_FD_UNIXSK,
CR_FD_INETSK,
CR_FD_MAX
};
......@@ -60,6 +61,7 @@ extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX];
#define FMT_FNAME_VMAS "vmas-%d.img"
#define FMT_FNAME_SIGACTS "sigacts-%d.img"
#define FMT_FNAME_UNIXSK "unixsk-%d.img"
#define FMT_FNAME_INETSK "inetsk-%d.img"
extern int get_image_path(char *path, int size, const char *fmt, int pid);
......
......@@ -13,6 +13,7 @@
#define PIPES_MAGIC 0x05055050
#define SIGACT_MAGIC 0x60606060
#define UNIXSK_MAGIC 0x07070707
#define INETSK_MAGIC 0x08080808
#define FDINFO_FD 1
#define FDINFO_MAP 2
......@@ -69,6 +70,19 @@ struct unix_sk_entry {
u8 name[0];
} __packed;
struct inet_sk_entry {
u32 fd;
u32 id;
u8 family;
u8 type;
u8 proto;
u8 state;
u16 src_port;
u8 pad[2];
u32 backlog;
u32 src_addr[4];
} __packed;
struct vma_entry {
u64 start;
u64 end;
......
#ifndef _INET_DIAG_H_
#define _INET_DIAG_H_ 1
#include <linux/types.h>
/* Just some random number */
#define TCPDIAG_GETSOCK 18
#define DCCPDIAG_GETSOCK 19
#define INET_DIAG_GETSOCK_MAX 24
/* Socket identity */
struct inet_diag_sockid {
__be16 idiag_sport;
__be16 idiag_dport;
__be32 idiag_src[4];
__be32 idiag_dst[4];
__u32 idiag_if;
__u32 idiag_cookie[2];
#define INET_DIAG_NOCOOKIE (~0U)
};
/* Request structure */
struct inet_diag_req_compat {
__u8 idiag_family; /* Family of addresses. */
__u8 idiag_src_len;
__u8 idiag_dst_len;
__u8 idiag_ext; /* Query extended information */
struct inet_diag_sockid id;
__u32 idiag_states; /* States to dump */
__u32 idiag_dbs; /* Tables to dump (NI) */
};
struct inet_diag_req {
__u8 sdiag_family;
__u8 sdiag_protocol;
__u8 idiag_ext;
__u8 pad;
__u32 idiag_states;
struct inet_diag_sockid id;
};
enum {
INET_DIAG_REQ_NONE,
INET_DIAG_REQ_BYTECODE,
};
#define INET_DIAG_REQ_MAX INET_DIAG_REQ_BYTECODE
/* Bytecode is sequence of 4 byte commands followed by variable arguments.
* All the commands identified by "code" are conditional jumps forward:
* to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be
* length of the command and its arguments.
*/
struct inet_diag_bc_op {
unsigned char code;
unsigned char yes;
unsigned short no;
};
enum {
INET_DIAG_BC_NOP,
INET_DIAG_BC_JMP,
INET_DIAG_BC_S_GE,
INET_DIAG_BC_S_LE,
INET_DIAG_BC_D_GE,
INET_DIAG_BC_D_LE,
INET_DIAG_BC_AUTO,
INET_DIAG_BC_S_COND,
INET_DIAG_BC_D_COND,
};
struct inet_diag_hostcond {
__u8 family;
__u8 prefix_len;
int port;
__be32 addr[0];
};
/* Base info structure. It contains socket identity (addrs/ports/cookie)
* and, alas, the information shown by netstat. */
struct inet_diag_msg {
__u8 idiag_family;
__u8 idiag_state;
__u8 idiag_timer;
__u8 idiag_retrans;
struct inet_diag_sockid id;
__u32 idiag_expires;
__u32 idiag_rqueue;
__u32 idiag_wqueue;
__u32 idiag_uid;
__u32 idiag_inode;
};
/* Extensions */
enum {
INET_DIAG_NONE,
INET_DIAG_MEMINFO,
INET_DIAG_INFO,
INET_DIAG_VEGASINFO,
INET_DIAG_CONG,
INET_DIAG_TOS,
INET_DIAG_TCLASS,
INET_DIAG_SKMEMINFO,
};
#define INET_DIAG_MAX INET_DIAG_SKMEMINFO
/* INET_DIAG_MEM */
struct inet_diag_meminfo {
__u32 idiag_rmem;
__u32 idiag_wmem;
__u32 idiag_fmem;
__u32 idiag_tmem;
};
/* INET_DIAG_VEGASINFO */
struct tcpvegas_info {
__u32 tcpv_enabled;
__u32 tcpv_rttcnt;
__u32 tcpv_rtt;
__u32 tcpv_minrtt;
};
#endif /* _INET_DIAG_H_ */
......@@ -11,6 +11,7 @@
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <arpa/inet.h>
#include "types.h"
#include "libnetlink.h"
......@@ -19,6 +20,7 @@
#include "image.h"
#include "crtools.h"
#include "util.h"
#include "inet_diag.h"
static char buf[4096];
......@@ -52,6 +54,19 @@ struct unix_sk_desc {
unsigned int *icons;
};
#define INET_ADDR_LEN 40
struct inet_sk_desc {
struct socket_desc sd;
unsigned int type;
unsigned int proto;
unsigned int src_port;
unsigned int state;
unsigned int rqlen;
unsigned int wqlen;
unsigned int src_addr[4];
};
#define SK_HASH_SIZE 32
static struct socket_desc *sockets[SK_HASH_SIZE];
......@@ -78,6 +93,36 @@ static int sk_collect_one(int ino, int family, struct socket_desc *d)
return 0;
}
static void show_one_inet(char *act, struct inet_sk_desc *sk)
{
char src_addr[INET_ADDR_LEN] = "<unknown>";
if (inet_ntop(AF_INET, (void *)sk->src_addr, src_addr,
INET_ADDR_LEN) == NULL) {
pr_err("Failed to translate address: %d\n", errno);
}
dprintk("\t%s: ino %d family %d type %d port %d "
"state %d src_addr %s\n",
act, sk->sd.ino, sk->sd.family, sk->type, sk->src_port,
sk->state, src_addr);
}
static void show_one_inet_img(char *act, struct inet_sk_entry *e)
{
char src_addr[INET_ADDR_LEN] = "<unknown>";
if (inet_ntop(AF_INET, (void *)e->src_addr, src_addr,
INET_ADDR_LEN) == NULL) {
pr_err("Failed to translate address: %d\n", errno);
}
dprintk("\t%s: fd %d family %d type %d proto %d port %d "
"state %d src_addr %d bytes\n",
act, e->fd, e->family, e->type, e->proto, e->src_port, e->state,
src_addr);
}
static void show_one_unix(char *act, struct unix_sk_desc *sk)
{
dprintk("\t%s: ino %d type %d state %d name %s\n",
......@@ -90,6 +135,69 @@ static void show_one_unix_img(char *act, struct unix_sk_entry *e)
act, e->fd, e->type, e->state, e->namelen);
}
static int can_dump_inet_sk(struct inet_sk_desc *sk)
{
if (sk->sd.family != AF_INET) {
pr_err("Only IPv4 sockets for now\n");
return 0;
}
if (sk->type != SOCK_STREAM) {
pr_err("Only stream inet sockets for now\n");
return 0;
}
switch (sk->state) {
case TCP_LISTEN:
if (sk->rqlen != 0) {
/*
* Currently the ICONS nla reports the conn
* requests for listen sockets. Need to pick
* those up and fix the connect job respectively
*/
pr_err("In-flight connection (l)\n");
return 0;
}
break;
default:
pr_err("Unknown state %d\n", sk->state);
return 0;
}
return 1;
}
static int dump_one_inet(struct socket_desc *_sk, int fd, struct cr_fdset *cr_fdset)
{
struct inet_sk_desc *sk = (struct inet_sk_desc *)_sk;
struct inet_sk_entry ie;
if (!can_dump_inet_sk(sk))
goto err;
memset(&ie, 0, sizeof(ie));
ie.fd = fd;
ie.id = sk->sd.ino;
ie.family = sk->sd.family;
ie.type = sk->type;
ie.proto = sk->proto;
ie.state = sk->state;
ie.src_port = sk->src_port;
ie.backlog = sk->wqlen;
memcpy(ie.src_addr, sk->src_addr, sizeof(u32) * 4);
write_ptr_safe(cr_fdset->fds[CR_FD_INETSK], &ie, err);
pr_info("Dumping inet socket at %d\n", fd);
show_one_inet("Dumping", sk);
show_one_inet_img("Dumped", &ie);
return 0;
err:
return -1;
}
static int can_dump_unix_sk(struct unix_sk_desc *sk)
{
if (sk->type != SOCK_STREAM &&
......@@ -209,6 +317,8 @@ int try_dump_socket(pid_t pid, int fd, struct cr_fdset *cr_fdset)
switch (sk->family) {
case AF_UNIX:
return dump_one_unix(sk, fd, cr_fdset);
case AF_INET:
return dump_one_inet(sk, fd, cr_fdset);
default:
pr_err("BUG! Unknown socket collected\n");
break;
......@@ -217,6 +327,36 @@ int try_dump_socket(pid_t pid, int fd, struct cr_fdset *cr_fdset)
return -1;
}
static int inet_tcp_collect_one(struct inet_diag_msg *m, struct rtattr **tb)
{
struct inet_sk_desc *d;
d = xzalloc(sizeof(*d));
if (!d)
return -1;
d->type = SOCK_STREAM;
d->proto = IPPROTO_TCP;
d->src_port = ntohs(m->id.idiag_sport);
d->state = m->idiag_state;
d->rqlen = m->idiag_rqueue;
d->wqlen = m->idiag_wqueue;
memcpy(d->src_addr, m->id.idiag_src, sizeof(u32) * 4);
return sk_collect_one(m->idiag_inode, AF_INET, &d->sd);
}
static int inet_tcp_receive_one(struct nlmsghdr *h)
{
struct inet_diag_msg *m = NLMSG_DATA(h);
struct rtattr *tb[INET_DIAG_MAX+1];
parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(m + 1),
h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
return inet_tcp_collect_one(m, tb);
}
static int unix_collect_one(struct unix_diag_msg *m, struct rtattr **tb)
{
struct unix_sk_desc *d, **h;
......@@ -391,6 +531,7 @@ int collect_sockets(void)
struct nlmsghdr hdr;
union {
struct unix_diag_req u;
struct inet_diag_req i;
} r;
} req;
......@@ -416,6 +557,14 @@ int collect_sockets(void)
if (err)
goto out;
/* Collect IPv4 TCP sockets */
req.r.i.sdiag_family = AF_INET;
req.r.i.sdiag_protocol = IPPROTO_TCP;
req.r.i.idiag_ext = 1 << (INET_DIAG_INFO - 1);
/* Only listening sockets supported yet */
req.r.i.idiag_states = 1 << TCP_LISTEN;
err = collect_sockets_nl(nl, &req, sizeof(req), inet_tcp_receive_one);
out:
close(nl);
return err;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment