[CRIU] [PATCH 6/7] sockets: Add support for IPv6 sockets
Cyrill Gorcunov
gorcunov at openvz.org
Fri Apr 20 18:56:39 EDT 2012
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
sockets.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 92 insertions(+), 21 deletions(-)
diff --git a/sockets.c b/sockets.c
index 5a07e67..eb951b0 100644
--- a/sockets.c
+++ b/sockets.c
@@ -169,8 +169,8 @@ static void show_one_unix_img(const char *act, const struct unix_sk_entry *e)
static int can_dump_inet_sk(const struct inet_sk_desc *sk)
{
- if (sk->sd.family != AF_INET) {
- pr_err("Only IPv4 sockets for now\n");
+ if (sk->sd.family != AF_INET && sk->sd.family != AF_INET6) {
+ pr_err("Only IPv4/6 sockets for now\n");
return 0;
}
@@ -400,6 +400,7 @@ int dump_socket(struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset)
case AF_UNIX:
return dump_one_unix(sk, p, lfd, cr_fdset);
case AF_INET:
+ case AF_INET6:
return dump_one_inet(sk, p, cr_fdset);
default:
pr_err("BUG! Unknown socket collected\n");
@@ -409,11 +410,12 @@ int dump_socket(struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset)
return -1;
}
-static int inet_collect_one(struct nlmsghdr *h, int type, int proto)
+static int inet_collect_one(struct nlmsghdr *h, int family, int type, int proto)
{
struct inet_sk_desc *d;
struct inet_diag_msg *m = NLMSG_DATA(h);
struct rtattr *tb[INET_DIAG_MAX+1];
+ int ret;
parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(m + 1),
h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
@@ -432,22 +434,41 @@ static int inet_collect_one(struct nlmsghdr *h, int type, int proto)
memcpy(d->src_addr, m->id.idiag_src, sizeof(u32) * 4);
memcpy(d->dst_addr, m->id.idiag_dst, sizeof(u32) * 4);
- return sk_collect_one(m->idiag_inode, AF_INET, &d->sd);
+ ret = sk_collect_one(m->idiag_inode, family, &d->sd);
+
+ show_one_inet("Collected", d);
+
+ return ret;
}
static int inet_tcp_receive_one(struct nlmsghdr *h)
{
- return inet_collect_one(h, SOCK_STREAM, IPPROTO_TCP);
+ return inet_collect_one(h, AF_INET, SOCK_STREAM, IPPROTO_TCP);
}
static int inet_udp_receive_one(struct nlmsghdr *h)
{
- return inet_collect_one(h, SOCK_DGRAM, IPPROTO_UDP);
+ return inet_collect_one(h, AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
static int inet_udplite_receive_one(struct nlmsghdr *h)
{
- return inet_collect_one(h, SOCK_DGRAM, IPPROTO_UDPLITE);
+ return inet_collect_one(h, AF_INET, SOCK_DGRAM, IPPROTO_UDPLITE);
+}
+
+static int inet6_tcp_receive_one(struct nlmsghdr *h)
+{
+ return inet_collect_one(h, AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+}
+
+static int inet6_udp_receive_one(struct nlmsghdr *h)
+{
+ return inet_collect_one(h, AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+}
+
+static int inet6_udplite_receive_one(struct nlmsghdr *h)
+{
+ return inet_collect_one(h, AF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE);
}
static int unix_collect_one(const struct unix_diag_msg *m,
@@ -768,6 +789,33 @@ int collect_sockets(void)
if (tmp)
err = tmp;
+ /* Collect IPv6 TCP sockets */
+ req.r.i.sdiag_family = AF_INET6;
+ req.r.i.sdiag_protocol = IPPROTO_TCP;
+ req.r.i.idiag_ext = 0;
+ /* Only listening sockets supported yet */
+ req.r.i.idiag_states = 1 << TCP_LISTEN;
+ tmp = collect_sockets_nl(nl, &req, sizeof(req), inet6_tcp_receive_one);
+ if (tmp)
+ err = tmp;
+
+ /* Collect IPv6 UDP sockets */
+ req.r.i.sdiag_family = AF_INET6;
+ req.r.i.sdiag_protocol = IPPROTO_UDP;
+ req.r.i.idiag_ext = 0;
+ req.r.i.idiag_states = -1; /* All */
+ tmp = collect_sockets_nl(nl, &req, sizeof(req), inet6_udp_receive_one);
+ if (tmp)
+ err = tmp;
+
+ /* Collect IPv6 UDP-lite sockets */
+ req.r.i.sdiag_family = AF_INET6;
+ req.r.i.sdiag_protocol = IPPROTO_UDPLITE;
+ req.r.i.idiag_ext = 0;
+ req.r.i.idiag_states = -1; /* All */
+ tmp = collect_sockets_nl(nl, &req, sizeof(req), inet6_udplite_receive_one);
+ if (tmp)
+ err = tmp;
out:
close(nl);
return err;
@@ -840,15 +888,18 @@ int collect_inet_sockets(void)
static int open_inet_sk(struct file_desc *d)
{
- int sk;
- struct sockaddr_in addr;
+ union {
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+ } addr;
struct inet_sk_info *ii;
+ int sk, addr_size;
ii = container_of(d, struct inet_sk_info, d);
show_one_inet_img("Restore", &ii->ie);
- if (ii->ie.family != AF_INET) {
+ if (ii->ie.family != AF_INET && ii->ie.family != AF_INET6) {
pr_err("Unsupported socket family: %d\n", ii->ie.family);
return -1;
}
@@ -871,12 +922,21 @@ static int open_inet_sk(struct file_desc *d)
* Listen sockets are easiest ones -- simply
* bind() and listen(), and that's all.
*/
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = ii->ie.family;
- addr.sin_port = htons(ii->ie.src_port);
- memcpy(&addr.sin_addr.s_addr, ii->ie.src_addr, sizeof(unsigned int) * 4);
-
- if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
+ memzero(&addr, sizeof(addr));
+ if (ii->ie.family == AF_INET) {
+ addr.v4.sin_family = ii->ie.family;
+ addr.v4.sin_port = htons(ii->ie.src_port);
+ memcpy(&addr.v4.sin_addr.s_addr, ii->ie.src_addr, sizeof(ii->ie.src_addr));
+ addr_size = sizeof(addr.v4);
+ } else if (ii->ie.family == AF_INET6) {
+ addr.v6.sin6_family = ii->ie.family;
+ addr.v6.sin6_port = htons(ii->ie.src_port);
+ memcpy(&addr.v6.sin6_addr.s6_addr, ii->ie.src_addr, sizeof(ii->ie.src_addr));
+ addr_size = sizeof(addr.v6);
+ } else
+ BUG_ON(1);
+
+ if (bind(sk, (struct sockaddr *)&addr, addr_size) == -1) {
pr_perror("Can't bind to a socket");
goto err;
}
@@ -899,12 +959,21 @@ static int open_inet_sk(struct file_desc *d)
goto err;
}
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = ii->ie.family;
- addr.sin_port = htons(ii->ie.dst_port);
- memcpy(&addr.sin_addr.s_addr, ii->ie.dst_addr, sizeof(ii->ie.dst_addr));
+ memzero(&addr, sizeof(addr));
+ if (ii->ie.family == AF_INET) {
+ addr.v4.sin_family = ii->ie.family;
+ addr.v4.sin_port = htons(ii->ie.dst_port);
+ memcpy(&addr.v4.sin_addr.s_addr, ii->ie.dst_addr, sizeof(ii->ie.dst_addr));
+ addr_size = sizeof(addr.v4);
+ } else if (ii->ie.family == AF_INET6) {
+ addr.v6.sin6_family = ii->ie.family;
+ addr.v6.sin6_port = htons(ii->ie.dst_port);
+ memcpy(&addr.v6.sin6_addr.s6_addr, ii->ie.dst_addr, sizeof(ii->ie.dst_addr));
+ addr_size = sizeof(addr.v6);
+ } else
+ BUG_ON(1);
- if (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ if (connect(sk, (struct sockaddr *)&addr, addr_size) == -1) {
pr_perror("Can't connect UDP socket back");
goto err;
}
@@ -931,6 +1000,8 @@ static inline char *skfamily2s(u32 f)
{
if (f == AF_INET)
return " inet";
+ else if (f == AF_INET6)
+ return "inet6";
else
return unknown(f);
}
--
1.7.7.6
More information about the CRIU
mailing list