Commit a54d3cf1 authored by Andrei Vagin's avatar Andrei Vagin

net: save network namespaces for sockets

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
Acked-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 17f163a6
...@@ -184,4 +184,6 @@ extern int __userns_call(const char *func_name, uns_call_t call, int flags, ...@@ -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 int add_ns_shared_cb(int (*actor)(void *data), void *data);
extern struct ns_id *get_socket_ns(int lfd);
#endif /* __CR_NS_H__ */ #endif /* __CR_NS_H__ */
...@@ -19,6 +19,7 @@ struct socket_desc { ...@@ -19,6 +19,7 @@ struct socket_desc {
unsigned int family; unsigned int family;
unsigned int ino; unsigned int ino;
struct socket_desc *next; struct socket_desc *next;
struct ns_id *sk_ns;
int already_dumped; int already_dumped;
}; };
...@@ -31,7 +32,7 @@ extern void preload_socket_modules(void); ...@@ -31,7 +32,7 @@ extern void preload_socket_modules(void);
extern bool socket_test_collect_bit(unsigned int family, unsigned int proto); 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; struct ns_id;
extern int collect_sockets(struct ns_id *); extern int collect_sockets(struct ns_id *);
extern struct collect_image_info inet_sk_cinfo; extern struct collect_image_info inet_sk_cinfo;
......
...@@ -2151,6 +2151,7 @@ err_nl: ...@@ -2151,6 +2151,7 @@ err_nl:
goto out; goto out;
} }
static int netns_nr;
static int collect_net_ns(struct ns_id *ns, void *oarg) static int collect_net_ns(struct ns_id *ns, void *oarg)
{ {
bool for_dump = (oarg == (void *)1); bool for_dump = (oarg == (void *)1);
...@@ -2161,6 +2162,8 @@ static int collect_net_ns(struct ns_id *ns, void *oarg) ...@@ -2161,6 +2162,8 @@ static int collect_net_ns(struct ns_id *ns, void *oarg)
if (ret) if (ret)
return ret; return ret;
netns_nr++;
if (!for_dump) if (!for_dump)
return 0; return 0;
...@@ -2175,6 +2178,34 @@ int collect_net_namespaces(bool for_dump) ...@@ -2175,6 +2178,34 @@ int collect_net_namespaces(bool for_dump)
struct ns_desc net_ns_desc = NS_DESC_ENTRY(CLONE_NEWNET, "net"); 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) static int move_to_bridge(struct external *ext, void *arg)
{ {
int s = *(int *)arg; int s = *(int *)arg;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "sk-inet.h" #include "sk-inet.h"
#include "protobuf.h" #include "protobuf.h"
#include "util.h" #include "util.h"
#include "namespaces.h"
#define PB_ALEN_INET 1 #define PB_ALEN_INET 1
#define PB_ALEN_INET6 4 #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 ...@@ -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; struct inet_sk_desc *sk;
union libsoccr_addr address; union libsoccr_addr address;
struct ns_id *ns = NULL;
socklen_t aux; socklen_t aux;
int ret; int ret;
if (root_ns_mask & CLONE_NEWNET) {
ns = get_socket_ns(lfd);
if (ns == NULL)
return NULL;
}
sk = xzalloc(sizeof(*sk)); sk = xzalloc(sizeof(*sk));
if (!sk) if (!sk)
goto err; goto err;
...@@ -279,7 +287,7 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int ...@@ -279,7 +287,7 @@ static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p, int
sk->state = TCP_CLOSE; 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; return sk;
err: err:
...@@ -367,6 +375,10 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa ...@@ -367,6 +375,10 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
ie.id = id; ie.id = id;
ie.ino = sk->sd.ino; 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.family = family;
ie.proto = proto; ie.proto = proto;
ie.type = sk->type; ie.type = sk->type;
...@@ -511,7 +523,7 @@ int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns) ...@@ -511,7 +523,7 @@ int inet_collect_one(struct nlmsghdr *h, int family, int type, struct ns_id *ns)
else else
pr_err_once("Can't check shutdown state of inet socket\n"); 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); show_one_inet("Collected", d);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "images/sk-netlink.pb-c.h" #include "images/sk-netlink.pb-c.h"
#include "netlink_diag.h" #include "netlink_diag.h"
#include "libnetlink.h" #include "libnetlink.h"
#include "namespaces.h"
struct netlink_sk_desc { struct netlink_sk_desc {
struct socket_desc sd; struct socket_desc sd;
...@@ -61,7 +62,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) ...@@ -61,7 +62,7 @@ int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, void *arg)
sd->gsize = 0; 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) static bool can_dump_netlink_sk(int lfd)
...@@ -95,6 +96,8 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p) ...@@ -95,6 +96,8 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
if (sk) { if (sk) {
BUG_ON(sk->sd.already_dumped); BUG_ON(sk->sd.already_dumped);
ne.ns_id = sk->sd.sk_ns->id;
ne.has_ns_id = true;
ne.protocol = sk->protocol; ne.protocol = sk->protocol;
ne.portid = sk->portid; ne.portid = sk->portid;
ne.groups = sk->groups; ne.groups = sk->groups;
...@@ -137,9 +140,18 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p) ...@@ -137,9 +140,18 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
ne.dst_portid = sk->dst_portid; ne.dst_portid = sk->dst_portid;
ne.dst_group = sk->dst_group; ne.dst_group = sk->dst_group;
} else { /* unconnected and unbound socket */ } else { /* unconnected and unbound socket */
struct ns_id *nsid;
int val; int val;
socklen_t aux = sizeof(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) { if (getsockopt(lfd, SOL_SOCKET, SO_PROTOCOL, &val, &aux) < 0) {
pr_perror("Unable to get protocol for netlink socket"); pr_perror("Unable to get protocol for netlink socket");
goto err; goto err;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "xmalloc.h" #include "xmalloc.h"
#include "images/packet-sock.pb-c.h" #include "images/packet-sock.pb-c.h"
#include "images/fdinfo.pb-c.h" #include "images/fdinfo.pb-c.h"
#include "namespaces.h"
struct packet_sock_info { struct packet_sock_info {
PacketSockEntry *pse; PacketSockEntry *pse;
...@@ -163,6 +164,8 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p) ...@@ -163,6 +164,8 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p)
sd->sd.already_dumped = 1; sd->sd.already_dumped = 1;
psk.id = sd->file_id = id; psk.id = sd->file_id = id;
psk.ns_id = sd->sd.sk_ns->id;
psk.has_ns_id = true;
psk.type = sd->type; psk.type = sd->type;
psk.flags = p->flags; psk.flags = p->flags;
psk.fown = (FownEntry *)&p->fown; psk.fown = (FownEntry *)&p->fown;
...@@ -301,7 +304,7 @@ int packet_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, void *arg) ...@@ -301,7 +304,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)); 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: err:
xfree(sd->tx); xfree(sd->tx);
xfree(sd->rx); xfree(sd->rx);
......
...@@ -302,6 +302,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) ...@@ -302,6 +302,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
ue->id = id; ue->id = id;
ue->ino = sk->sd.ino; ue->ino = sk->sd.ino;
ue->ns_id = sk->sd.sk_ns->id;
ue->has_ns_id = true;
ue->type = sk->type; ue->type = sk->type;
ue->state = sk->state; ue->state = sk->state;
ue->flags = p->flags; ue->flags = p->flags;
...@@ -665,7 +667,7 @@ static int unix_collect_one(const struct unix_diag_msg *m, ...@@ -665,7 +667,7 @@ static int unix_collect_one(const struct unix_diag_msg *m,
d->wqlen = rq->udiag_wqueue; 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); list_add_tail(&d->list, &unix_sockets);
show_one_unix("Collected", d); show_one_unix("Collected", d);
......
...@@ -353,13 +353,14 @@ struct socket_desc *lookup_socket(unsigned ino, int family, int proto) ...@@ -353,13 +353,14 @@ struct socket_desc *lookup_socket(unsigned ino, int family, int proto)
return NULL; 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; struct socket_desc **chain;
d->ino = ino; d->ino = ino;
d->family = family; d->family = family;
d->already_dumped = 0; d->already_dumped = 0;
d->sk_ns = ns;
chain = &sockets[ino % SK_HASH_SIZE]; chain = &sockets[ino % SK_HASH_SIZE];
d->next = *chain; d->next = *chain;
......
...@@ -43,4 +43,5 @@ message packet_sock_entry { ...@@ -43,4 +43,5 @@ message packet_sock_entry {
optional uint32 fanout = 17 [ default = 0xffffffff ]; optional uint32 fanout = 17 [ default = 0xffffffff ];
optional packet_ring rx_ring = 18; optional packet_ring rx_ring = 18;
optional packet_ring tx_ring = 19; optional packet_ring tx_ring = 19;
optional uint32 ns_id = 20;
} }
...@@ -39,5 +39,6 @@ message inet_sk_entry { ...@@ -39,5 +39,6 @@ message inet_sk_entry {
/* for ipv6, we need to send the ifindex to bind(); we keep the ifname /* for ipv6, we need to send the ifindex to bind(); we keep the ifname
* here and convert it on restore */ * here and convert it on restore */
optional string ifname = 17; optional string ifname = 17;
optional uint32 ns_id = 18;
optional sk_shutdown shutdown = 19; optional sk_shutdown shutdown = 19;
} }
...@@ -16,4 +16,5 @@ message netlink_sk_entry { ...@@ -16,4 +16,5 @@ message netlink_sk_entry {
required uint32 dst_group = 10; required uint32 dst_group = 10;
required fown_entry fown = 11; required fown_entry fown = 11;
required sk_opts_entry opts = 12; required sk_opts_entry opts = 12;
optional uint32 ns_id = 13;
} }
...@@ -48,4 +48,6 @@ message unix_sk_entry { ...@@ -48,4 +48,6 @@ message unix_sk_entry {
*/ */
optional string name_dir = 14; optional string name_dir = 14;
optional bool deleted = 15; optional bool deleted = 15;
optional uint32 ns_id = 16;
} }
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