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] = { ...@@ -85,6 +85,13 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
.fmt = FMT_FNAME_UNIXSK, .fmt = FMT_FNAME_UNIXSK,
.magic = UNIXSK_MAGIC, .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) static struct cr_fdset *alloc_cr_fdset(void)
......
...@@ -24,6 +24,7 @@ enum { ...@@ -24,6 +24,7 @@ enum {
CR_FD_SHMEM, CR_FD_SHMEM,
CR_FD_SIGACT, CR_FD_SIGACT,
CR_FD_UNIXSK, CR_FD_UNIXSK,
CR_FD_INETSK,
CR_FD_MAX CR_FD_MAX
}; };
...@@ -60,6 +61,7 @@ extern struct cr_fd_desc_tmpl fdset_template[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_VMAS "vmas-%d.img"
#define FMT_FNAME_SIGACTS "sigacts-%d.img" #define FMT_FNAME_SIGACTS "sigacts-%d.img"
#define FMT_FNAME_UNIXSK "unixsk-%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); extern int get_image_path(char *path, int size, const char *fmt, int pid);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define PIPES_MAGIC 0x05055050 #define PIPES_MAGIC 0x05055050
#define SIGACT_MAGIC 0x60606060 #define SIGACT_MAGIC 0x60606060
#define UNIXSK_MAGIC 0x07070707 #define UNIXSK_MAGIC 0x07070707
#define INETSK_MAGIC 0x08080808
#define FDINFO_FD 1 #define FDINFO_FD 1
#define FDINFO_MAP 2 #define FDINFO_MAP 2
...@@ -69,6 +70,19 @@ struct unix_sk_entry { ...@@ -69,6 +70,19 @@ struct unix_sk_entry {
u8 name[0]; u8 name[0];
} __packed; } __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 { struct vma_entry {
u64 start; u64 start;
u64 end; 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 @@ ...@@ -11,6 +11,7 @@
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h> #include <limits.h>
#include <arpa/inet.h>
#include "types.h" #include "types.h"
#include "libnetlink.h" #include "libnetlink.h"
...@@ -19,6 +20,7 @@ ...@@ -19,6 +20,7 @@
#include "image.h" #include "image.h"
#include "crtools.h" #include "crtools.h"
#include "util.h" #include "util.h"
#include "inet_diag.h"
static char buf[4096]; static char buf[4096];
...@@ -52,6 +54,19 @@ struct unix_sk_desc { ...@@ -52,6 +54,19 @@ struct unix_sk_desc {
unsigned int *icons; 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 #define SK_HASH_SIZE 32
static struct socket_desc *sockets[SK_HASH_SIZE]; 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) ...@@ -78,6 +93,36 @@ static int sk_collect_one(int ino, int family, struct socket_desc *d)
return 0; 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) static void show_one_unix(char *act, struct unix_sk_desc *sk)
{ {
dprintk("\t%s: ino %d type %d state %d name %s\n", 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) ...@@ -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); 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) static int can_dump_unix_sk(struct unix_sk_desc *sk)
{ {
if (sk->type != SOCK_STREAM && if (sk->type != SOCK_STREAM &&
...@@ -209,6 +317,8 @@ int try_dump_socket(pid_t pid, int fd, struct cr_fdset *cr_fdset) ...@@ -209,6 +317,8 @@ int try_dump_socket(pid_t pid, int fd, struct cr_fdset *cr_fdset)
switch (sk->family) { switch (sk->family) {
case AF_UNIX: case AF_UNIX:
return dump_one_unix(sk, fd, cr_fdset); return dump_one_unix(sk, fd, cr_fdset);
case AF_INET:
return dump_one_inet(sk, fd, cr_fdset);
default: default:
pr_err("BUG! Unknown socket collected\n"); pr_err("BUG! Unknown socket collected\n");
break; break;
...@@ -217,6 +327,36 @@ int try_dump_socket(pid_t pid, int fd, struct cr_fdset *cr_fdset) ...@@ -217,6 +327,36 @@ int try_dump_socket(pid_t pid, int fd, struct cr_fdset *cr_fdset)
return -1; 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) static int unix_collect_one(struct unix_diag_msg *m, struct rtattr **tb)
{ {
struct unix_sk_desc *d, **h; struct unix_sk_desc *d, **h;
...@@ -391,6 +531,7 @@ int collect_sockets(void) ...@@ -391,6 +531,7 @@ int collect_sockets(void)
struct nlmsghdr hdr; struct nlmsghdr hdr;
union { union {
struct unix_diag_req u; struct unix_diag_req u;
struct inet_diag_req i;
} r; } r;
} req; } req;
...@@ -416,6 +557,14 @@ int collect_sockets(void) ...@@ -416,6 +557,14 @@ int collect_sockets(void)
if (err) if (err)
goto out; 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: out:
close(nl); close(nl);
return err; 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