[CRIU] [PATCH 06/12] netns: dump and restore network namespace ID-s
Pavel Emelyanov
xemul at virtuozzo.com
Mon Mar 13 04:10:35 PDT 2017
On 03/01/2017 02:53 AM, Andrei Vagin wrote:
> From: Andrei Vagin <avagin at virtuozzo.com>
>
> In each network namespace we can set an id for another network namespace
> to be able to address it in netlink messages.
>
> For example, we can say that a peer of a veth devices has to be created
> in a network namespace with a specified id. If we request information about
> a veth device, a kernel will report where a peer device lives.
>
> An user are able to set this ID-s, so we have to dump and restore them.
>
> Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
> ---
> criu/include/namespaces.h | 8 ++
> criu/namespaces.c | 7 ++
> criu/net.c | 185 +++++++++++++++++++++++++++++++++++++++++++---
> 3 files changed, 189 insertions(+), 11 deletions(-)
>
> diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
> index 2a3dc08..5df7679 100644
> --- a/criu/include/namespaces.h
> +++ b/criu/include/namespaces.h
> @@ -82,6 +82,12 @@ enum ns_type {
> NS_OTHER,
> };
>
> +struct netns_id {
> + unsigned id;
> + unsigned net_id;
> + struct list_head node;
> +};
> +
> struct ns_id {
> unsigned int kid;
> unsigned int id;
> @@ -112,8 +118,10 @@ struct ns_id {
>
> struct {
> int nsfd_id; /* a namespace descriptor id in fdstore */
> + int ns_fd; /* a namespace file descriptor */
Why do we need both?
> int nlsk; /* for sockets collection */
> int seqsk; /* to talk to parasite daemons */
> + struct list_head ids;
> } net;
> struct {
> UsernsEntry *e;
> diff --git a/criu/namespaces.c b/criu/namespaces.c
> index 3563c16..8e170aa 100644
> --- a/criu/namespaces.c
> +++ b/criu/namespaces.c
> @@ -307,6 +307,9 @@ struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid,
> nsid->ns_populated = false;
> INIT_LIST_HEAD(&nsid->children);
> INIT_LIST_HEAD(&nsid->siblings);
> +
> + if (nd == &net_ns_desc)
> + INIT_LIST_HEAD(&nsid->net.ids);
> }
>
> return nsid;
> @@ -432,6 +435,10 @@ static unsigned int generate_ns_id(int pid, unsigned int kid, struct ns_desc *nd
> INIT_LIST_HEAD(&nsid->siblings);
> nsid_add(nsid, nd, ns_next_id++, pid);
>
> + if (nd == &net_ns_desc) {
> + INIT_LIST_HEAD(&nsid->net.ids);
> + }
> +
> found:
> if (ns_ret)
> *ns_ret = nsid;
> diff --git a/criu/net.c b/criu/net.c
> index a3f79df..e893c0c 100644
> --- a/criu/net.c
> +++ b/criu/net.c
> @@ -640,6 +640,11 @@ static int dump_one_gre(struct ifinfomsg *ifi, char *kind,
> return dump_unknown_device(ifi, kind, tb, ns, fds);
> }
>
> +static int list_one_link(struct nlmsghdr *hdr, struct ns_id *ns, void *arg)
> +{
> + return 0;
> +}
> +
> static int dump_one_link(struct nlmsghdr *hdr, struct ns_id *ns, void *arg)
> {
> struct cr_imgset *fds = arg;
> @@ -856,6 +861,26 @@ out:
>
> }
>
> +static int list_links(int rtsk, void *args)
> +{
> + struct {
> + struct nlmsghdr nlh;
> + struct rtgenmsg g;
> + } req;
> +
> + pr_info("Dumping netns links\n");
> +
> + memset(&req, 0, sizeof(req));
> + req.nlh.nlmsg_len = sizeof(req);
> + req.nlh.nlmsg_type = RTM_GETLINK;
> + req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
> + req.nlh.nlmsg_pid = 0;
> + req.nlh.nlmsg_seq = CR_NLMSG_SEQ;
> + req.g.rtgen_family = AF_PACKET;
> +
> + return do_rtnl_req(rtsk, &req, sizeof(req), list_one_link, NULL, NULL, args);
> +}
Why is this call with empty list_one_link() required at all?
> +
> static int dump_links(int rtsk, struct ns_id *ns, struct cr_imgset *fds)
> {
> struct {
> @@ -1370,6 +1395,24 @@ static int dump_netns_conf(struct ns_id *ns, struct cr_imgset *fds)
> int size6 = ARRAY_SIZE(devconfs6);
> char def_stable_secret[MAX_STR_CONF_LEN + 1] = {};
> char all_stable_secret[MAX_STR_CONF_LEN + 1] = {};
> + NetnsId *ids;
> + struct netns_id *p;
> +
> + i = 0;
> + list_for_each_entry(p, &ns->net.ids, node)
> + i++;
This list is willed with walk_namespaces() call, one entry per callback,
so this is effectively constant.
> +
> + netns.nsids = xmalloc(sizeof(NetnsId *) * i);
> + ids = xmalloc(sizeof(NetnsId) * i);
> + i = 0;
> + list_for_each_entry(p, &ns->net.ids, node) {
> + netns_id__init(&ids[i]);
> + ids[i].id = p->id;
> + ids[i].nsid = p->net_id;
> + netns.nsids[i] = ids + i;
> + i++;
> + }
> + netns.n_nsids = i;
>
> netns.n_def_conf4 = size4;
> netns.n_all_conf4 = size4;
> @@ -1629,6 +1672,46 @@ static int mount_ns_sysfs(void)
> return ns_sysfs_fd >= 0 ? 0 : -1;
> }
>
> +struct net_id_arg {
> + struct ns_id *ns;
> + int sk;
> +};
> +
> +static int collect_netns_id(struct ns_id *ns, void *oarg)
> +{
> + struct net_id_arg *arg = oarg;
> + struct netns_id *netns_id;
> + int nsid = -1;
> +
> + if (net_get_nsid(arg->sk, ns->ns_pid, &nsid))
> + return -1;
> +
> + if (nsid == -1)
> + return 0;
> +
> + netns_id = xmalloc(sizeof(*netns_id));
> + if (!netns_id)
> + return -1;
> +
> + pr_debug("Fount the %d id for %d in %d\n", nsid, ns->id, arg->ns->id);
> + netns_id->id = ns->id;
> + netns_id->net_id = nsid;
> +
> + list_add(&netns_id->node, &arg->ns->net.ids);
> +
> + return 0;
> +}
> +
> +static int dump_netns_ids(int rtsk, struct ns_id *ns)
> +{
> + struct net_id_arg arg = {
> + .ns = ns,
> + .sk = rtsk,
> + };
> + return walk_namespaces(&net_ns_desc, collect_netns_id,
> + (void *)&arg);
> +}
> +
> int dump_net_ns(struct ns_id *ns)
> {
> struct cr_imgset *fds;
> @@ -1649,6 +1732,10 @@ int dump_net_ns(struct ns_id *ns)
> }
>
> if (!ret)
> + ret = list_links(sk, NULL);
> + if (!ret)
> + ret = dump_netns_ids(sk, ns);
> + if (!ret)
> ret = dump_links(sk, ns, fds);
>
> close(sk);
> @@ -1676,6 +1763,45 @@ int dump_net_ns(struct ns_id *ns)
> return ret;
> }
>
> +static int net_set_nsid(int rtsk, int fd, int nsid);
> +static int restore_netns_ids(struct ns_id *ns, NetnsEntry *netns)
> +{
> + int i, sk, exit_code = -1;
> +
> + sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
> + if (sk < 0) {
> + pr_perror("Can't open rtnl sock for net dump");
> + return -1;
> + }
> +
> + for (i = 0; i < netns->n_nsids; i++) {
> + struct ns_id *tg_ns;
> + struct netns_id *id;
> +
> + id = xmalloc(sizeof(*id));
> + if (!id)
> + goto out;
> + id->id = netns->nsids[i]->id;
> + id->net_id = netns->nsids[i]->nsid;
> + list_add(&id->node, &ns->net.ids);
> +
> + tg_ns = lookup_ns_by_id(id->id, &net_ns_desc);
> + if (tg_ns == NULL) {
> + pr_err("Unknown namespace: %d\n", id->id);
> + goto out;
> + }
> +
> + if (net_set_nsid(sk, tg_ns->net.ns_fd, id->net_id))
> + goto out;
> + }
> +
> + exit_code = 0;
> +out:
> + close(sk);
> +
> + return exit_code;
> +}
> +
> static int prepare_net_ns(struct ns_id *ns)
> {
> int ret = 0, nsid = ns->id;
> @@ -1684,6 +1810,8 @@ static int prepare_net_ns(struct ns_id *ns)
> if (!(opts.empty_ns & CLONE_NEWNET)) {
> ret = restore_netns_conf(nsid, &netns);
> if (!ret)
> + ret = restore_netns_ids(ns, netns);
> + if (!ret)
> ret = restore_links(nsid, &netns);
> if (netns)
> netns_entry__free_unpacked(netns, NULL);
> @@ -1703,25 +1831,27 @@ static int prepare_net_ns(struct ns_id *ns)
> if (!ret)
> ret = restore_nf_ct(nsid, CR_FD_NETNF_EXP);
>
> + if (!ret) {
> + ns->net.nsfd_id = fdstore_add(ns->net.ns_fd);
> + if (ns->net.nsfd_id < 0)
> + ret = -1;
> + }
> + close_safe(&ns->net.ns_fd);
> +
> + ns->ns_populated = true;
> +
> return ret;
> }
>
> static int open_net_ns(struct ns_id *nsid)
> {
> - int fd, id;
> + int fd;
>
> /* Pin one with a file descriptor */
> fd = open_proc(PROC_SELF, "ns/net");
> if (fd < 0)
> return -1;
> -
> - id = fdstore_add(fd);
> - close(fd);
> - if (id < 0) {
> - return -1;
> - }
> -
> - nsid->net.nsfd_id = id;
> + nsid->net.ns_fd = fd;
>
> return 0;
> }
> @@ -1732,8 +1862,6 @@ static int do_create_net_ns(struct ns_id *ns)
> pr_perror("Unable to create a new netns");
> return -1;
> }
> - if (prepare_net_ns(ns))
> - return -1;
> if (open_net_ns(ns))
> return -1;
> return 0;
> @@ -1790,6 +1918,17 @@ int prepare_net_namespaces()
> goto err;
> }
>
> + for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) {
> + if (nsid->nd != &net_ns_desc)
> + continue;
> +
> + if (switch_ns_by_fd(nsid->net.ns_fd, &net_ns_desc, NULL))
> + goto err;
> +
> + if (prepare_net_ns(nsid))
> + goto err;
> + }
> +
> close_service_fd(NS_FD_OFF);
>
> return 0;
> @@ -2277,6 +2416,30 @@ static int nsid_cb(struct nlmsghdr *msg, struct ns_id *ns, void *arg)
> return 0;
> }
>
> +static int net_set_nsid(int rtsk, int fd, int nsid)
> +{
> + struct {
> + struct nlmsghdr nlh;
> + struct rtgenmsg g;
> + char msg[128];
> + } req;
> +
> + memset(&req, 0, sizeof(req));
> + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
> + req.nlh.nlmsg_type = RTM_NEWNSID;
> + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
> + req.nlh.nlmsg_seq = CR_NLMSG_SEQ;
> + if (addattr_l(&req.nlh, sizeof(req), NETNSA_FD, &fd, sizeof(fd)))
> + return -1;
> + if (addattr_l(&req.nlh, sizeof(req), NETNSA_NSID, &nsid, sizeof(nsid)))
> + return -1;
> +
> + if (do_rtnl_req(rtsk, &req, req.nlh.nlmsg_len, NULL, NULL, NULL, NULL) < 0)
> + return -1;
> +
> + return 0;
> +}
> +
> int net_get_nsid(int rtsk, int pid, int *nsid)
> {
> struct {
>
More information about the CRIU
mailing list