[CRIU] [PATCH 06/11] net: save network namespaces for sockets
Andrei Vagin
avagin at virtuozzo.com
Wed Feb 8 19:15:48 PST 2017
On Wed, Feb 08, 2017 at 04:53:25PM -0800, Andrei Vagin wrote:
> On Wed, Feb 08, 2017 at 12:48:00PM +0300, Pavel Emelyanov wrote:
> > On 02/02/2017 03:04 AM, Andrei Vagin wrote:
> > > 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.
> > >
> > > Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
> > > ---
> > > criu/include/namespaces.h | 2 ++
> > > criu/include/sockets.h | 3 ++-
> > > criu/net.c | 25 +++++++++++++++++++++++++
> > > 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-packet.proto | 1 +
> > > images/sk-unix.proto | 2 ++
> > > 13 files changed, 71 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 0666fa9..7dadc8d 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,28 @@ 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_item->ids == NULL)
> > > + return NULL;
> >
> > Shouldn't we check this under if (root_netns == NULL) check?
>
> Yes, we should
> >
> > > +
> > > + if (root_netns == NULL)
> > > + root_netns = lookup_ns_by_id(root_item->ids->net_ns_id, &net_ns_desc);
> > > +
> > > + return root_netns;
> > > +}
> > > +
> > > +struct ns_id *get_socket_ns(int lfd)
> >
> > Please, rename to get_uncollected_socket_ns() and add a comment
> > describing what the problem is.
>
> hmmmm, this function works for all sockets. Let's add a comment and save
> the function name. If you still think that we have to rename this
> function, could you just rename it before appling this patch.
> >
> > > +{
> > > + if (netns_nr == 1)
> >
> > This is called under root_ns_mask & CLONE_NEWNET, so we want to
> > check whether there are NS_OTHER net namespaces or not. Right?
>
> yes, if netns_nr is 1, it means that there is only NS_ROOT.
>
> >
> > > + 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 f0048ea..35c4d32 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-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;
> >
> > Why is ns_id needed here? The id_for is unique across namespaces, isn't it?
>
> Ooops. It is my fault, it should not be here. Thanks!
> I just added ns_id to all [SK_TYPE]_sk_entry and added this ns_id by mistake.
>
> Why do we have two images for packet sockets?
sk-packet isn't about packet sockets...
>
> [root at fc24 criu]# ls -l images/*sock*.proto
> -rw-r--r-- 1 root root 1171 Feb 9 02:55 images/packet-sock.proto
> [root at fc24 criu]# ls -l images/sk-*.proto
> -rw-r--r-- 1 root root 1247 Feb 9 02:55 images/sk-inet.proto
> -rw-r--r-- 1 root root 537 Feb 9 02:55 images/sk-netlink.proto
> -rw-r--r-- 1 root root 678 Nov 22 11:07 images/sk-opts.proto
> -rw-r--r-- 1 root root 110 Feb 9 03:02 images/sk-packet.proto
> -rw-r--r-- 1 root root 1306 Feb 9 03:04 images/sk-unix.proto
>
> >
> > > }
> > > 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;
> > > }
> > >
> >
More information about the CRIU
mailing list