[CRIU] [PATCH 03/10] [v2] net: save network namespaces for sockets
Andrei Vagin
avagin at openvz.org
Thu Feb 9 00:10:23 PST 2017
From: Andrei Vagin <avagin at virtuozzo.com>
Each socket has to be restored in a proper namespaces where
it has been created.
Here is an issue about unconnected and unbound sockets,
they are not reported via socket-diag and we can't to
get their network namespaces.
v2: add a comment before get_socket_ns()
remove nsid from sk_packet_entry
Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
---
criu/include/namespaces.h | 2 ++
criu/include/sockets.h | 3 ++-
criu/net.c | 31 +++++++++++++++++++++++++++++++
criu/sk-inet.c | 16 ++++++++++++++--
criu/sk-netlink.c | 14 +++++++++++++-
criu/sk-packet.c | 5 ++++-
criu/sk-unix.c | 4 +++-
criu/sockets.c | 3 ++-
images/packet-sock.proto | 1 +
images/sk-inet.proto | 1 +
images/sk-netlink.proto | 1 +
images/sk-unix.proto | 2 ++
12 files changed, 76 insertions(+), 7 deletions(-)
diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
index c9f3e8a..18eafb2 100644
--- a/criu/include/namespaces.h
+++ b/criu/include/namespaces.h
@@ -184,4 +184,6 @@ extern int __userns_call(const char *func_name, uns_call_t call, int flags,
extern int add_ns_shared_cb(int (*actor)(void *data), void *data);
+extern struct ns_id *get_socket_ns(int lfd);
+
#endif /* __CR_NS_H__ */
diff --git a/criu/include/sockets.h b/criu/include/sockets.h
index 18e20d1..7685eeb 100644
--- a/criu/include/sockets.h
+++ b/criu/include/sockets.h
@@ -18,6 +18,7 @@ struct socket_desc {
unsigned int family;
unsigned int ino;
struct socket_desc *next;
+ struct ns_id *sk_ns;
int already_dumped;
};
@@ -30,7 +31,7 @@ extern void preload_socket_modules(void);
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);
diff --git a/criu/net.c b/criu/net.c
index be8f048..b303b8a 100644
--- a/criu/net.c
+++ b/criu/net.c
@@ -1915,6 +1915,7 @@ err_nl:
goto out;
}
+static int netns_nr;
static int collect_net_ns(struct ns_id *ns, void *oarg)
{
bool for_dump = (oarg == (void *)1);
@@ -1925,6 +1926,8 @@ static int collect_net_ns(struct ns_id *ns, void *oarg)
if (ret)
return ret;
+ netns_nr++;
+
if (!for_dump)
return 0;
@@ -1939,6 +1942,34 @@ int collect_net_namespaces(bool for_dump)
struct ns_desc net_ns_desc = NS_DESC_ENTRY(CLONE_NEWNET, "net");
+static struct ns_id *get_root_netns()
+{
+ static struct ns_id *root_netns = NULL;
+
+ if (root_netns)
+ return root_netns;
+
+ if (root_item->ids == NULL)
+ return NULL;
+
+ root_netns = lookup_ns_by_id(root_item->ids->net_ns_id, &net_ns_desc);
+
+ return root_netns;
+}
+
+/*
+ * socket_diag doesn't report unbound and unconnected sockets,
+ * so we have to get their network namesapces explicitly
+ */
+struct ns_id *get_socket_ns(int lfd)
+{
+ if (netns_nr == 1)
+ return get_root_netns();
+
+ pr_perror("Unable to get a socket net namespace");
+ return NULL;
+}
+
static int move_to_bridge(struct external *ext, void *arg)
{
int s = *(int *)arg;
diff --git a/criu/sk-inet.c b/criu/sk-inet.c
index b8bd9e2..bb898d5 100644
--- a/criu/sk-inet.c
+++ b/criu/sk-inet.c
@@ -25,6 +25,7 @@
#include "sk-inet.h"
#include "protobuf.h"
#include "util.h"
+#include "namespaces.h"
#define PB_ALEN_INET 1
#define PB_ALEN_INET6 4
@@ -210,9 +211,16 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int
{
struct inet_sk_desc *sk;
union libsoccr_addr address;
+ struct ns_id *ns = NULL;
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;
@@ -272,7 +280,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:
@@ -341,6 +349,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.sk_ns) {
+ ie.ns_id = sk->sd.sk_ns->id;
+ ie.has_ns_id = true;
+ }
ie.family = family;
ie.proto = proto;
ie.type = sk->type;
@@ -477,7 +489,7 @@ int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns)
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 0fb873c..4ef934a 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;
@@ -61,7 +62,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, 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, ns);
}
static bool can_dump_netlink_sk(int lfd)
@@ -94,6 +95,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.sk_ns->id;
+ ne.has_ns_id = true;
ne.protocol = sk->protocol;
ne.portid = sk->portid;
ne.groups = sk->groups;
@@ -120,9 +123,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 cdd0595..f1cf117 100644
--- a/criu/sk-packet.c
+++ b/criu/sk-packet.c
@@ -20,6 +20,7 @@
#include "xmalloc.h"
#include "images/packet-sock.pb-c.h"
#include "images/fdinfo.pb-c.h"
+#include "namespaces.h"
struct packet_sock_info {
PacketSockEntry *pse;
@@ -162,6 +163,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.sk_ns->id;
+ psk.has_ns_id = true;
psk.type = sd->type;
psk.flags = p->flags;
psk.fown = (FownEntry *)&p->fown;
@@ -296,7 +299,7 @@ int packet_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, 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, ns);
err:
xfree(sd->tx);
xfree(sd->rx);
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index 5a69cd2..4d7a890 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -297,6 +297,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.sk_ns->id;
+ ue->has_ns_id = true;
ue->type = sk->type;
ue->state = sk->state;
ue->flags = p->flags;
@@ -660,7 +662,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);
diff --git a/criu/sockets.c b/criu/sockets.c
index fa551eb..86a6b21 100644
--- a/criu/sockets.c
+++ b/criu/sockets.c
@@ -353,13 +353,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->sk_ns = ns;
chain = &sockets[ino % SK_HASH_SIZE];
d->next = *chain;
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-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