[CRIU] [PATCH 05/10] net: save network namespaces for sockets
Andrei Vagin
avagin at openvz.org
Wed Aug 31 15:55:28 PDT 2016
From: Andrew Vagin <avagin at virtuozzo.com>
Each socket has to be restored in a proper namespaces where
it has been created.
Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
---
criu/include/sockets.h | 10 ++++++++--
criu/sk-inet.c | 18 +++++++++++++++---
criu/sk-netlink.c | 15 ++++++++++++++-
criu/sk-packet.c | 6 +++++-
criu/sk-unix.c | 9 ++++++---
criu/sockets.c | 35 +++++++++++++++++++++++------------
images/packet-sock.proto | 1 +
images/sk-inet.proto | 1 +
images/sk-netlink.proto | 1 +
images/sk-packet.proto | 1 +
images/sk-unix.proto | 2 ++
11 files changed, 77 insertions(+), 22 deletions(-)
diff --git a/criu/include/sockets.h b/criu/include/sockets.h
index 40295bb..fc64ac2 100644
--- a/criu/include/sockets.h
+++ b/criu/include/sockets.h
@@ -21,9 +21,15 @@ struct socket_desc {
unsigned int family;
unsigned int ino;
struct socket_desc *next;
+ struct ns_id *ns;
int already_dumped;
};
+struct sock_req_args {
+ struct ns_id *ns;
+ void *req;
+};
+
extern int dump_socket(struct fd_parms *p, int lfd, struct cr_img *);
extern int dump_socket_opts(int sk, SkOptsEntry *soe);
extern int restore_socket_opts(int sk, SkOptsEntry *soe);
@@ -33,7 +39,7 @@ extern void preload_socket_modules();
extern bool socket_test_collect_bit(unsigned int family, unsigned int proto);
-extern int sk_collect_one(unsigned ino, int family, struct socket_desc *d);
+extern int sk_collect_one(unsigned ino, int family, struct socket_desc *d, struct ns_id *ns);
struct ns_id;
extern int collect_sockets(struct ns_id *);
extern int collect_inet_sockets(void);
@@ -50,7 +56,7 @@ extern const struct fdtype_ops inet6_dump_ops;
extern const struct fdtype_ops netlink_dump_ops;
extern const struct fdtype_ops packet_dump_ops;
-extern int inet_collect_one(struct nlmsghdr *h, int family, int type);
+extern int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns);
extern int unix_receive_one(struct nlmsghdr *h, void *);
extern int netlink_receive_one(struct nlmsghdr *hdr, void *arg);
diff --git a/criu/sk-inet.c b/criu/sk-inet.c
index f4bc519..8083c05 100644
--- a/criu/sk-inet.c
+++ b/criu/sk-inet.c
@@ -22,6 +22,7 @@
#include "rst-malloc.h"
#include "sockets.h"
#include "sk-inet.h"
+#include "namespaces.h"
#define PB_ALEN_INET 1
#define PB_ALEN_INET6 4
@@ -182,10 +183,17 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk)
static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int proto)
{
struct inet_sk_desc *sk;
+ struct ns_id *ns = NULL;
char address;
socklen_t aux;
int ret;
+ if (root_ns_mask & CLONE_NEWNET) {
+ ns = get_socket_ns(lfd);
+ if (ns == NULL)
+ return NULL;
+ }
+
sk = xzalloc(sizeof(*sk));
if (!sk)
goto err;
@@ -231,7 +239,7 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int
sk->state = TCP_CLOSE;
- sk_collect_one(sk->sd.ino, sk->sd.family, &sk->sd);
+ sk_collect_one(sk->sd.ino, sk->sd.family, &sk->sd, ns);
return sk;
err:
@@ -300,6 +308,10 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
ie.id = id;
ie.ino = sk->sd.ino;
+ if (sk->sd.ns) {
+ ie.ns_id = sk->sd.ns->id;
+ ie.has_ns_id = true;
+ }
ie.family = family;
ie.proto = proto;
ie.type = sk->type;
@@ -408,7 +420,7 @@ const struct fdtype_ops inet6_dump_ops = {
.dump = dump_one_inet6_fd,
};
-int inet_collect_one(struct nlmsghdr *h, int family, int type)
+int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns)
{
struct inet_sk_desc *d;
struct inet_diag_msg *m = NLMSG_DATA(h);
@@ -435,7 +447,7 @@ int inet_collect_one(struct nlmsghdr *h, int family, int type)
else
pr_err_once("Can't check shutdown state of inet socket\n");
- ret = sk_collect_one(m->idiag_inode, family, &d->sd);
+ ret = sk_collect_one(m->idiag_inode, family, &d->sd, ns);
show_one_inet("Collected", d);
diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c
index dc5c4a1..252a484 100644
--- a/criu/sk-netlink.c
+++ b/criu/sk-netlink.c
@@ -12,6 +12,7 @@
#include "images/sk-netlink.pb-c.h"
#include "netlink_diag.h"
#include "libnetlink.h"
+#include "namespaces.h"
struct netlink_sk_desc {
struct socket_desc sd;
@@ -30,6 +31,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, void *arg)
struct netlink_diag_msg *m;
struct netlink_sk_desc *sd;
unsigned long *groups;
+ struct sock_req_args *req_args = arg;
m = NLMSG_DATA(hdr);
pr_debug("Collect netlink sock 0x%x\n", m->ndiag_ino);
@@ -61,7 +63,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, void *arg)
sd->gsize = 0;
}
- return sk_collect_one(m->ndiag_ino, PF_NETLINK, &sd->sd);
+ return sk_collect_one(m->ndiag_ino, PF_NETLINK, &sd->sd, req_args->ns);
}
static bool can_dump_netlink_sk(int lfd)
@@ -94,6 +96,8 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
if (sk) {
BUG_ON(sk->sd.already_dumped);
+ ne.ns_id = sk->sd.ns->id;
+ ne.has_ns_id = true;
ne.protocol = sk->protocol;
ne.portid = sk->portid;
ne.groups = sk->groups;
@@ -120,9 +124,18 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
ne.dst_portid = sk->dst_portid;
ne.dst_group = sk->dst_group;
} else { /* unconnected and unbound socket */
+ struct ns_id *nsid;
int val;
socklen_t aux = sizeof(val);
+ if (root_ns_mask & CLONE_NEWNET) {
+ nsid = get_socket_ns(lfd);
+ if (nsid == NULL)
+ return -1;
+ ne.ns_id = nsid->id;
+ ne.has_ns_id = true;
+ }
+
if (getsockopt(lfd, SOL_SOCKET, SO_PROTOCOL, &val, &aux) < 0) {
pr_perror("Unable to get protocol for netlink socket");
goto err;
diff --git a/criu/sk-packet.c b/criu/sk-packet.c
index d82268e..d064f36 100644
--- a/criu/sk-packet.c
+++ b/criu/sk-packet.c
@@ -18,6 +18,7 @@
#include "protobuf.h"
#include "images/packet-sock.pb-c.h"
#include "images/fdinfo.pb-c.h"
+#include "namespaces.h"
struct packet_sock_info {
PacketSockEntry *pse;
@@ -160,6 +161,8 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p)
sd->sd.already_dumped = 1;
psk.id = sd->file_id = id;
+ psk.ns_id = sd->sd.ns->id;
+ psk.has_ns_id = true;
psk.type = sd->type;
psk.flags = p->flags;
psk.fown = (FownEntry *)&p->fown;
@@ -245,6 +248,7 @@ int packet_receive_one(struct nlmsghdr *hdr, void *arg)
struct packet_diag_msg *m;
struct nlattr *tb[PACKET_DIAG_MAX + 1];
struct packet_sock_desc *sd;
+ struct sock_req_args *req_args = arg;
m = NLMSG_DATA(hdr);
nlmsg_parse(hdr, sizeof(struct packet_diag_msg),
@@ -294,7 +298,7 @@ int packet_receive_one(struct nlmsghdr *hdr, void *arg)
memcpy(sd->tx, RTA_DATA(tb[PACKET_DIAG_TX_RING]), sizeof(*sd->tx));
}
- return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd);
+ return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd, req_args->ns);
err:
xfree(sd->tx);
xfree(sd->rx);
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index 99f0b08..1b5d2aa 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -305,6 +305,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
ue->id = id;
ue->ino = sk->sd.ino;
+ ue->ns_id = sk->sd.ns->id;
+ ue->has_ns_id = true;
ue->type = sk->type;
ue->state = sk->state;
ue->flags = p->flags;
@@ -591,7 +593,7 @@ skip:
}
static int unix_collect_one(const struct unix_diag_msg *m,
- struct nlattr **tb)
+ struct nlattr **tb, struct ns_id *ns)
{
struct unix_sk_desc *d;
int ret = 0;
@@ -668,7 +670,7 @@ static int unix_collect_one(const struct unix_diag_msg *m,
d->wqlen = rq->udiag_wqueue;
}
- sk_collect_one(m->udiag_ino, AF_UNIX, &d->sd);
+ sk_collect_one(m->udiag_ino, AF_UNIX, &d->sd, ns);
list_add_tail(&d->list, &unix_sockets);
show_one_unix("Collected", d);
@@ -686,10 +688,11 @@ int unix_receive_one(struct nlmsghdr *h, void *arg)
{
struct unix_diag_msg *m = NLMSG_DATA(h);
struct nlattr *tb[UNIX_DIAG_MAX+1];
+ struct sock_req_args *req_args = arg;
nlmsg_parse(h, sizeof(struct unix_diag_msg), tb, UNIX_DIAG_MAX, NULL);
- return unix_collect_one(m, tb);
+ return unix_collect_one(m, tb, req_args->ns);
}
static int dump_external_sockets(struct unix_sk_desc *peer)
diff --git a/criu/sockets.c b/criu/sockets.c
index ffc4f39..edd459f 100644
--- a/criu/sockets.c
+++ b/criu/sockets.c
@@ -350,13 +350,14 @@ struct socket_desc *lookup_socket(unsigned ino, int family, int proto)
return NULL;
}
-int sk_collect_one(unsigned ino, int family, struct socket_desc *d)
+int sk_collect_one(unsigned ino, int family, struct socket_desc *d, struct ns_id *ns)
{
struct socket_desc **chain;
d->ino = ino;
d->family = family;
d->already_dumped = 0;
+ d->ns = ns;
chain = &sockets[ino % SK_HASH_SIZE];
d->next = *chain;
@@ -583,7 +584,8 @@ int dump_socket(struct fd_parms *p, int lfd, struct cr_img *img)
static int inet_receive_one(struct nlmsghdr *h, void *arg)
{
- struct inet_diag_req_v2 *i = arg;
+ struct sock_req_args *req_args = arg;
+ struct inet_diag_req_v2 *i = req_args->req;
int type;
switch (i->sdiag_protocol) {
@@ -599,7 +601,7 @@ static int inet_receive_one(struct nlmsghdr *h, void *arg)
return -1;
}
- return inet_collect_one(h, i->sdiag_family, type);
+ return inet_collect_one(h, i->sdiag_family, type, req_args->ns);
}
static int do_collect_req(int nl, struct sock_diag_req *req, int size,
@@ -620,6 +622,7 @@ int collect_sockets(struct ns_id *ns)
int err = 0, tmp;
int nl = ns->net.nlsk;
struct sock_diag_req req;
+ struct sock_req_args args = { .ns = ns };
memset(&req, 0, sizeof(req));
req.hdr.nlmsg_len = sizeof(req);
@@ -633,7 +636,7 @@ int collect_sockets(struct ns_id *ns)
req.r.u.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_VFS |
UDIAG_SHOW_PEER | UDIAG_SHOW_ICONS |
UDIAG_SHOW_RQLEN;
- tmp = do_collect_req(nl, &req, sizeof(req), unix_receive_one, NULL);
+ tmp = do_collect_req(nl, &req, sizeof(req), unix_receive_one, &args);
if (tmp)
err = tmp;
@@ -643,7 +646,8 @@ int collect_sockets(struct ns_id *ns)
req.r.i.idiag_ext = 0;
/* Only listening and established sockets supported yet */
req.r.i.idiag_states = (1 << TCP_LISTEN) | (1 << TCP_ESTABLISHED);
- tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+ args.req = &req.r.i;
+ tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
if (tmp)
err = tmp;
@@ -652,7 +656,8 @@ int collect_sockets(struct ns_id *ns)
req.r.i.sdiag_protocol = IPPROTO_UDP;
req.r.i.idiag_ext = 0;
req.r.i.idiag_states = -1; /* All */
- tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+ args.req = &req.r.i;
+ tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
if (tmp)
err = tmp;
@@ -661,7 +666,8 @@ int collect_sockets(struct ns_id *ns)
req.r.i.sdiag_protocol = IPPROTO_UDPLITE;
req.r.i.idiag_ext = 0;
req.r.i.idiag_states = -1; /* All */
- tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+ args.req = &req.r.i;
+ tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
if (tmp)
err = tmp;
@@ -671,7 +677,8 @@ int collect_sockets(struct ns_id *ns)
req.r.i.idiag_ext = 0;
/* Only listening sockets supported yet */
req.r.i.idiag_states = (1 << TCP_LISTEN) | (1 << TCP_ESTABLISHED);
- tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+ args.req = &req.r.i;
+ tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
if (tmp)
err = tmp;
@@ -680,7 +687,8 @@ int collect_sockets(struct ns_id *ns)
req.r.i.sdiag_protocol = IPPROTO_UDP;
req.r.i.idiag_ext = 0;
req.r.i.idiag_states = -1; /* All */
- tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+ args.req = &req.r.i;
+ tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
if (tmp)
err = tmp;
@@ -689,7 +697,8 @@ int collect_sockets(struct ns_id *ns)
req.r.i.sdiag_protocol = IPPROTO_UDPLITE;
req.r.i.idiag_ext = 0;
req.r.i.idiag_states = -1; /* All */
- tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
+ args.req = &req.r.i;
+ tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &args);
if (tmp)
err = tmp;
@@ -697,7 +706,8 @@ int collect_sockets(struct ns_id *ns)
req.r.p.sdiag_protocol = 0;
req.r.p.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MCLIST |
PACKET_SHOW_FANOUT | PACKET_SHOW_RING_CFG;
- tmp = do_collect_req(nl, &req, sizeof(req), packet_receive_one, NULL);
+ args.req = NULL;
+ tmp = do_collect_req(nl, &req, sizeof(req), packet_receive_one, &args);
if (tmp) {
pr_warn("The current kernel doesn't support packet_diag\n");
if (ns->ns_pid == 0 || tmp != -ENOENT) /* Fedora 19 */
@@ -707,7 +717,8 @@ int collect_sockets(struct ns_id *ns)
req.r.n.sdiag_family = AF_NETLINK;
req.r.n.sdiag_protocol = NDIAG_PROTO_ALL;
req.r.n.ndiag_show = NDIAG_SHOW_GROUPS;
- tmp = do_collect_req(nl, &req, sizeof(req), netlink_receive_one, NULL);
+ args.req = NULL;
+ tmp = do_collect_req(nl, &req, sizeof(req), netlink_receive_one, &args);
if (tmp) {
pr_warn("The current kernel doesn't support netlink_diag\n");
if (ns->ns_pid == 0 || tmp != -ENOENT) /* Fedora 19 */
diff --git a/images/packet-sock.proto b/images/packet-sock.proto
index f6198c1..25875b4 100644
--- a/images/packet-sock.proto
+++ b/images/packet-sock.proto
@@ -43,4 +43,5 @@ message packet_sock_entry {
optional uint32 fanout = 17 [ default = 0xffffffff ];
optional packet_ring rx_ring = 18;
optional packet_ring tx_ring = 19;
+ optional uint32 ns_id = 20;
}
diff --git a/images/sk-inet.proto b/images/sk-inet.proto
index 01dda87..09c5a47 100644
--- a/images/sk-inet.proto
+++ b/images/sk-inet.proto
@@ -39,4 +39,5 @@ message inet_sk_entry {
/* for ipv6, we need to send the ifindex to bind(); we keep the ifname
* here and convert it on restore */
optional string ifname = 17;
+ optional uint32 ns_id = 18;
}
diff --git a/images/sk-netlink.proto b/images/sk-netlink.proto
index ed24c50..402281d 100644
--- a/images/sk-netlink.proto
+++ b/images/sk-netlink.proto
@@ -16,4 +16,5 @@ message netlink_sk_entry {
required uint32 dst_group = 10;
required fown_entry fown = 11;
required sk_opts_entry opts = 12;
+ optional uint32 ns_id = 13;
}
diff --git a/images/sk-packet.proto b/images/sk-packet.proto
index 5f61c73..33ace1d 100644
--- a/images/sk-packet.proto
+++ b/images/sk-packet.proto
@@ -3,4 +3,5 @@ syntax = "proto2";
message sk_packet_entry {
required uint32 id_for = 1;
required uint32 length = 2;
+ optional uint32 ns_id = 4;
}
diff --git a/images/sk-unix.proto b/images/sk-unix.proto
index 3026214..d695070 100644
--- a/images/sk-unix.proto
+++ b/images/sk-unix.proto
@@ -48,4 +48,6 @@ message unix_sk_entry {
*/
optional string name_dir = 14;
optional bool deleted = 15;
+
+ optional uint32 ns_id = 16;
}
--
2.7.4
More information about the CRIU
mailing list