[10/12] net: create a list of all links

Submitted by Andrei Vagin on Feb. 28, 2017, 11:53 p.m.

Details

Message ID 1488325988-28456-11-git-send-email-avagin@openvz.org
State New
Series "Dump and restore internal veth devices"
Headers show

Commit Message

Andrei Vagin Feb. 28, 2017, 11:53 p.m.
From: Andrei Vagin <avagin@virtuozzo.com>

We will need to enumirate links a few times

Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
---
 criu/include/net.h |   3 +-
 criu/include/tun.h |   3 +-
 criu/net.c         | 180 +++++++++++++++++++++++++++++++----------------------
 criu/tun.c         |   5 +-
 4 files changed, 112 insertions(+), 79 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/include/net.h b/criu/include/net.h
index 72275b8..796dcc4 100644
--- a/criu/include/net.h
+++ b/criu/include/net.h
@@ -38,7 +38,8 @@  extern struct ns_desc net_ns_desc;
 #include "images/netdev.pb-c.h"
 extern int write_netdev_img(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr **info);
 extern int read_ns_sys_file(char *path, char *buf, int len);
-extern int restore_link_parms(NetDeviceEntry *nde, int nlsk);
+struct net_link;
+extern int restore_link_parms(struct net_link *link, int nlsk);
 
 extern int veth_pair_add(char *in, char *out);
 extern int macvlan_ext_add(struct external *ext);
diff --git a/criu/include/tun.h b/criu/include/tun.h
index c1434ae..2d0aa8e 100644
--- a/criu/include/tun.h
+++ b/criu/include/tun.h
@@ -11,7 +11,8 @@ 
 
 extern const struct fdtype_ops tunfile_dump_ops;
 extern int dump_tun_link(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr **info);
-extern int restore_one_tun(NetDeviceEntry *nde, int nlsk);
+struct net_link;
+extern int restore_one_tun(struct net_link *link, int nlsk);
 extern struct collect_image_info tunfile_cinfo;
 extern int check_tun_cr(int no_tun_err);
 
diff --git a/criu/net.c b/criu/net.c
index d9d94b4..a61cfe2 100644
--- a/criu/net.c
+++ b/criu/net.c
@@ -962,12 +962,14 @@  struct newlink_extras {
 	int target_netns;	/* IFLA_NET_NS_FD */
 };
 
-typedef int (*link_info_t)(struct ns_id *ns, NetDeviceEntry *, struct newlink_req *);
+typedef int (*link_info_t)(struct ns_id *ns, struct net_link *, struct newlink_req *);
 
 static int populate_newlink_req(struct ns_id *ns, struct newlink_req *req,
-			int msg_type, NetDeviceEntry *nde,
+			int msg_type, struct net_link * link,
 			link_info_t link_info, struct newlink_extras *extras)
 {
+	NetDeviceEntry *nde = link->nde;
+
 	memset(req, 0, sizeof(*req));
 
 	req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
@@ -1010,7 +1012,7 @@  static int populate_newlink_req(struct ns_id *ns, struct newlink_req *req,
 		linkinfo = NLMSG_TAIL(&req->h);
 		addattr_l(&req->h, sizeof(*req), IFLA_LINKINFO, NULL, 0);
 
-		ret = link_info(ns, nde, req);
+		ret = link_info(ns, link, req);
 		if (ret < 0)
 			return ret;
 
@@ -1021,27 +1023,27 @@  static int populate_newlink_req(struct ns_id *ns, struct newlink_req *req,
 }
 
 static int do_rtm_link_req(int msg_type,
-			NetDeviceEntry *nde, int nlsk, struct ns_id *ns,
+			struct net_link *link, int nlsk, struct ns_id *ns,
 			link_info_t link_info, struct newlink_extras *extras)
 {
 	struct newlink_req req;
 
-	if (populate_newlink_req(ns, &req, msg_type, nde, link_info, extras) < 0)
+	if (populate_newlink_req(ns, &req, msg_type, link, link_info, extras) < 0)
 		return -1;
 
 	return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL, NULL, NULL);
 }
 
-int restore_link_parms(NetDeviceEntry *nde, int nlsk)
+int restore_link_parms(struct net_link *link, int nlsk)
 {
-	return do_rtm_link_req(RTM_SETLINK, nde, nlsk, NULL, NULL, NULL);
+	return do_rtm_link_req(RTM_SETLINK, link, nlsk, NULL, NULL, NULL);
 }
 
-static int restore_one_link(struct ns_id *ns, NetDeviceEntry *nde, int nlsk,
+static int restore_one_link(struct ns_id *ns, struct net_link *link, int nlsk,
 			link_info_t link_info, struct newlink_extras *extras)
 {
-	pr_info("Restoring netdev %s idx %d\n", nde->name, nde->ifindex);
-	return do_rtm_link_req(RTM_NEWLINK, nde, nlsk, ns, link_info, extras);
+	pr_info("Restoring netdev %s idx %d\n", link->nde->name, link->nde->ifindex);
+	return do_rtm_link_req(RTM_NEWLINK, link, nlsk, ns, link_info, extras);
 }
 
 #ifndef VETH_INFO_MAX
@@ -1058,9 +1060,10 @@  enum {
 #define IFLA_NET_NS_FD	28
 #endif
 
-static int veth_peer_info(NetDeviceEntry *nde, struct newlink_req *req,
+static int veth_peer_info(struct net_link *link, struct newlink_req *req,
 						struct ns_id *ns, int ns_fd)
 {
+	NetDeviceEntry *nde = link->nde;
 	char key[100], *val;
 	struct ns_id *peer_ns = NULL;
 
@@ -1076,46 +1079,33 @@  static int veth_peer_info(NetDeviceEntry *nde, struct newlink_req *req,
 	}
 
 	if (nde->has_peer_nsid) {
-		if (ns && nde->peer_nsid == ns->id) {
-			struct net_link *link;
-
-			list_for_each_entry(link, &ns->net.links, node)
-				if (link->nde->ifindex == nde->peer_ifindex && link->created) {
-					pr_err("%d\n", nde->peer_ifindex);
-					req->h.nlmsg_type = RTM_SETLINK;
-					return 0;
-				}
-		}
+		struct net_link *plink;
+
 		peer_ns = lookup_ns_by_id(nde->peer_nsid, &net_ns_desc);
-		if (peer_ns->ns_populated) {
-			req->h.nlmsg_type = RTM_SETLINK;
-			return 0;
+		if (!peer_ns)
+			goto out;
+		list_for_each_entry(plink, &peer_ns->net.links, node) {
+			if (plink->nde->ifindex == nde->peer_ifindex && plink->created) {
+				req->h.nlmsg_type = RTM_SETLINK;
+				return 0;
+			}
 		}
 	}
 
+	link->created = true;
 	if (peer_ns) {
-		if (ns && nde->peer_nsid == ns->id) {
-			struct net_link *link;
-
-			link = xmalloc(sizeof(*link));
-			if (link == NULL)
-				return -1;
-
-			link->created = true;
-			list_add(&link->node, &ns->net.links);
-		}
-
 		addattr_l(&req->h, sizeof(*req), IFLA_NET_NS_FD, &peer_ns->net.ns_fd, sizeof(int));
 		return 0;
 	}
-
+out:
 	pr_err("Unknown peer net namespace");
 	return -1;
 }
 
-static int veth_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req)
+static int veth_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req)
 {
 	int ns_fd = get_service_fd(NS_FD_OFF);
+	NetDeviceEntry *nde = link->nde;
 	struct rtattr *veth_data, *peer_data;
 	struct ifinfomsg ifm;
 
@@ -1129,14 +1119,14 @@  static int veth_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_
 	ifm.ifi_index = nde->peer_ifindex;
 	addattr_l(&req->h, sizeof(*req), VETH_INFO_PEER, &ifm, sizeof(ifm));
 
-	veth_peer_info(nde, req, ns, ns_fd);
+	veth_peer_info(link, req, ns, ns_fd);
 	peer_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)peer_data;
 	veth_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)veth_data;
 
 	return 0;
 }
 
-static int venet_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req)
+static int venet_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req)
 {
 	int ns_fd = get_service_fd(NS_FD_OFF);
 	struct rtattr *venet_data;
@@ -1152,7 +1142,7 @@  static int venet_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink
 	return 0;
 }
 
-static int bridge_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req)
+static int bridge_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req)
 {
 	struct rtattr *bridge_data;
 
@@ -1178,9 +1168,10 @@  static int changeflags(int s, char *name, short flags)
 	return 0;
 }
 
-static int macvlan_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req)
+static int macvlan_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req)
 {
 	struct rtattr *macvlan_data;
+	NetDeviceEntry *nde = link->nde;
 	MacvlanLinkEntry *macvlan = nde->macvlan;
 
 	if (!macvlan) {
@@ -1232,7 +1223,7 @@  out:
 	return ret;
 }
 
-static int restore_one_macvlan(struct ns_id *ns, NetDeviceEntry *nde, int nlsk)
+static int restore_one_macvlan(struct ns_id *ns, struct net_link *link, int nlsk)
 {
 	struct newlink_extras extras = {
 		.link = -1,
@@ -1240,6 +1231,7 @@  static int restore_one_macvlan(struct ns_id *ns, NetDeviceEntry *nde, int nlsk)
 	};
 	char key[100], *val;
 	int my_netns = -1, ret = -1;
+	NetDeviceEntry *nde = link->nde;
 
 	snprintf(key, sizeof(key), "macvlan[%s]", nde->name);
 	val = external_lookup_data(key);
@@ -1267,7 +1259,7 @@  static int restore_one_macvlan(struct ns_id *ns, NetDeviceEntry *nde, int nlsk)
 	{
 		struct newlink_req req;
 
-		if (populate_newlink_req(ns, &req, RTM_NEWLINK, nde, macvlan_link_info, &extras) < 0)
+		if (populate_newlink_req(ns, &req, RTM_NEWLINK, link, macvlan_link_info, &extras) < 0)
 			goto out;
 
 		if (userns_call(userns_restore_one_link, 0, &req, sizeof(req), my_netns) < 0) {
@@ -1283,26 +1275,28 @@  out:
 	return ret;
 }
 
-static int __restore_link(struct ns_id *ns, NetDeviceEntry *nde, int nlsk)
+static int __restore_link(struct ns_id *ns, struct net_link *link, int nlsk)
 {
+	NetDeviceEntry *nde = link->nde;
+
 	pr_info("Restoring link %s type %d\n", nde->name, nde->type);
 
 	switch (nde->type) {
 	case ND_TYPE__LOOPBACK: /* fallthrough */
 	case ND_TYPE__EXTLINK:  /* see comment in images/netdev.proto */
-		return restore_link_parms(nde, nlsk);
+		return restore_link_parms(link, nlsk);
 	case ND_TYPE__VENET:
-		return restore_one_link(ns, nde, nlsk, venet_link_info, NULL);
+		return restore_one_link(ns, link, nlsk, venet_link_info, NULL);
 	case ND_TYPE__VETH:
-		return restore_one_link(ns, nde, nlsk, veth_link_info, NULL);
+		return restore_one_link(ns, link, nlsk, veth_link_info, NULL);
 	case ND_TYPE__TUN:
-		return restore_one_tun(nde, nlsk);
+		return restore_one_tun(link, nlsk);
 	case ND_TYPE__BRIDGE:
-		return restore_one_link(ns, nde, nlsk, bridge_link_info, NULL);
+		return restore_one_link(ns, link, nlsk, bridge_link_info, NULL);
 	case ND_TYPE__MACVLAN:
-		return restore_one_macvlan(ns, nde, nlsk);
+		return restore_one_macvlan(ns, link, nlsk);
 	default:
-		pr_err("Unsupported link type %d\n", nde->type);
+		pr_err("Unsupported link type %d\n", link->nde->type);
 		break;
 	}
 
@@ -1348,7 +1342,7 @@  static int restore_link(int nlsk, struct ns_id *ns, struct net_link *link)
 	NetnsEntry **def_netns = &ns->net.netns;
 	int ret;
 
-	ret = __restore_link(ns, nde, nlsk);
+	ret = __restore_link(ns, link, nlsk);
 	if (ret) {
 		pr_err("Can't restore link: %d\n", ret);
 		goto exit;
@@ -1375,26 +1369,35 @@  exit:
 	return ret;
 }
 
-static int restore_links(struct ns_id *ns)
+static int restore_links()
 {
 	struct net_link *link, *t;
-	int exit_code = -1, nlsk;
+	int exit_code = -1, nlsk = -1;
+	struct ns_id *nsid;
 
-	nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-	if (nlsk < 0) {
-		pr_perror("Can't create nlk socket");
-		return -1;
-	}
+	for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) {
+		if (nsid->nd != &net_ns_desc)
+			continue;
 
-	list_for_each_entry_safe(link, t, &ns->net.links, node) {
-		if (restore_link(nlsk, ns, link))
+		if (switch_ns_by_fd(nsid->net.ns_fd, &net_ns_desc, NULL))
 			goto out;
-		xfree(link);
+
+		nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+		if (nlsk < 0) {
+			pr_perror("Can't create nlk socket");
+			return -1;
+		}
+
+		list_for_each_entry_safe(link, t, &nsid->net.links, node) {
+			if (restore_link(nlsk, nsid, link))
+				goto out;
+		}
+		close_safe(&nlsk);
 	}
 
 	exit_code = 0;
 out:
-	close(nlsk);
+	close_safe(&nlsk);
 
 	return exit_code;
 }
@@ -1922,19 +1925,27 @@  out:
 	return exit_code;
 }
 
-static int prepare_net_ns(struct ns_id *ns)
+static int prepare_net_ns_first_stage(struct ns_id *ns)
+{
+	int ret = 0;
+
+	if (opts.empty_ns & CLONE_NEWNET)
+		return 0;
+
+	ret = restore_netns_conf(ns);
+	if (!ret)
+		ret = restore_netns_ids(ns);
+	if (!ret)
+		ret = read_links(ns);
+
+	return ret;
+}
+
+static int prepare_net_ns_second_stage(struct ns_id *ns)
 {
 	int ret = 0, nsid = ns->id;
 
 	if (!(opts.empty_ns & CLONE_NEWNET)) {
-		ret = restore_netns_conf(ns);
-		if (!ret)
-			ret = restore_netns_ids(ns);
-		if (!ret)
-			ret = read_links(ns);
-		if (!ret)
-			ret = restore_links(ns);
-
 		if (ns->net.netns)
 			netns_entry__free_unpacked(ns->net.netns, NULL);
 
@@ -2047,7 +2058,21 @@  int prepare_net_namespaces()
 		if (switch_ns_by_fd(nsid->net.ns_fd, &net_ns_desc, NULL))
 			goto err;
 
-		if (prepare_net_ns(nsid))
+		if (prepare_net_ns_first_stage(nsid))
+			goto err;
+	}
+
+	if (restore_links())
+		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_second_stage(nsid))
 			goto err;
 	}
 
@@ -2591,8 +2616,9 @@  int net_get_nsid(int rtsk, int pid, int *nsid)
 }
 
 
-static int nsid_link_info(struct ns_id *ns, NetDeviceEntry *nde, struct newlink_req *req)
+static int nsid_link_info(struct ns_id *ns, struct net_link *link, struct newlink_req *req)
 {
+	NetDeviceEntry *nde = link->nde;
 	struct rtattr *veth_data, *peer_data;
 	struct ifinfomsg ifm;
 
@@ -2669,6 +2695,10 @@  int kerndat_link_nsid()
 
 	if (pid == 0) {
 		NetDeviceEntry nde = NET_DEVICE_ENTRY__INIT;
+		struct net_link link = {
+			.created = false,
+			.nde = &nde,
+		};
 		int nsfd, sk, ret;
 
 		sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
@@ -2700,7 +2730,7 @@  int kerndat_link_nsid()
 		nde.has_peer_ifindex = true;
 		nde.has_peer_nsid = true;
 
-		ret = restore_one_link(NULL, &nde, sk, nsid_link_info, NULL);
+		ret = restore_one_link(NULL, &link, sk, nsid_link_info, NULL);
 		if (ret) {
 			pr_err("Unable to create a veth pair: %d\n", ret);
 			exit(1);
diff --git a/criu/tun.c b/criu/tun.c
index 6a429b6..3b93bb95 100644
--- a/criu/tun.c
+++ b/criu/tun.c
@@ -434,8 +434,9 @@  int dump_tun_link(NetDeviceEntry *nde, struct cr_imgset *fds, struct nlattr **in
 	return write_netdev_img(nde, fds, info);
 }
 
-int restore_one_tun(NetDeviceEntry *nde, int nlsk)
+int restore_one_tun(struct net_link *link, int nlsk)
 {
+	NetDeviceEntry *nde = link->nde;
 	int fd, ret = -1, aux;
 
 	if (!nde->tun) {
@@ -484,7 +485,7 @@  int restore_one_tun(NetDeviceEntry *nde, int nlsk)
 		goto out;
 	}
 
-	if (restore_link_parms(nde, nlsk)) {
+	if (restore_link_parms(link, nlsk)) {
 		pr_err("Error restoring %s link params\n", nde->name);
 		goto out;
 	}