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,
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__ */
......@@ -19,6 +19,7 @@ struct socket_desc {
unsigned int family;
unsigned int ino;
struct socket_desc *next;
struct ns_id *sk_ns;
int already_dumped;
};
......@@ -31,7 +32,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 struct collect_image_info inet_sk_cinfo;
......
......@@ -2151,6 +2151,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);
......@@ -2161,6 +2162,8 @@ static int collect_net_ns(struct ns_id *ns, void *oarg)
if (ret)
return ret;
netns_nr++;
if (!for_dump)
return 0;
......@@ -2175,6 +2178,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;
......
......@@ -26,6 +26,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;
......@@ -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_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:
......@@ -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.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;
......@@ -511,7 +523,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);
......
......@@ -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)
......@@ -95,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.sk_ns->id;
ne.has_ns_id = true;
ne.protocol = sk->protocol;
ne.portid = sk->portid;
ne.groups = sk->groups;
......@@ -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_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;
......
......@@ -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;
......@@ -163,6 +164,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;
......@@ -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));
}
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);
......
......@@ -302,6 +302,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;
......@@ -665,7 +667,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);
......
......@@ -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;
......
......@@ -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;
}
......@@ -39,5 +39,6 @@ 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;
optional sk_shutdown shutdown = 19;
}
......@@ -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;
}
......@@ -48,4 +48,6 @@ message unix_sk_entry {
*/
optional string name_dir = 14;
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