[11/12] net: dump and restore connected to a bridge links

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

Details

Message ID 1488325988-28456-12-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>

A network device, which is connected to a bridge, is restored
after the bridge. In this case we can set the master attribute and
the device will be connected to the bridge automatically.

Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
---
 criu/net.c          | 155 +++++++++++++++++++++++++++++++++++-----------------
 images/netdev.proto |   2 +
 2 files changed, 108 insertions(+), 49 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/net.c b/criu/net.c
index a61cfe2..a82262c 100644
--- a/criu/net.c
+++ b/criu/net.c
@@ -441,6 +441,11 @@  static int dump_one_netdev(int type, struct ifinfomsg *ifi,
 				(int)netdev.address.len, netdev.name);
 	}
 
+	if (tb[IFLA_MASTER]) {
+		netdev.has_master = true;
+		netdev.master = nla_get_u32(tb[IFLA_MASTER]);
+	}
+
 	netdev.n_conf4 = size4;
 	netdev.conf4 = xmalloc(sizeof(SysctlEntry *) * size4);
 	if (!netdev.conf4)
@@ -540,36 +545,6 @@  static int dump_unknown_device(struct ifinfomsg *ifi, char *kind,
 
 static int dump_bridge(NetDeviceEntry *nde, struct cr_imgset *imgset, struct nlattr **info)
 {
-	char spath[IFNAMSIZ + 16]; /* len("class/net//brif") + 1 for null */
-	int ret, fd;
-
-	ret = snprintf(spath, sizeof(spath), "class/net/%s/brif", nde->name);
-	if (ret < 0 || ret >= sizeof(spath))
-		return -1;
-
-	/* Let's only allow dumping empty bridges for now. To do a full bridge
-	 * restore, we need to make sure the bridge and slaves are restored in
-	 * the right order and attached correctly. It looks like the veth code
-	 * supports this, but we need some way to do ordering.
-	 */
-	fd = openat(ns_sysfs_fd, spath, O_DIRECTORY, 0);
-	if (fd < 0) {
-		pr_perror("opening %s failed", spath);
-		return -1;
-	}
-
-	ret = is_empty_dir(fd);
-	close(fd);
-	if (ret < 0) {
-		pr_perror("problem testing %s for emptiness", spath);
-		return -1;
-	}
-
-	if (!ret) {
-		pr_err("dumping bridges with attached slaves not supported currently\n");
-		return -1;
-	}
-
 	return write_netdev_img(nde, imgset, info);
 }
 
@@ -1369,37 +1344,110 @@  exit:
 	return ret;
 }
 
-static int restore_links()
+static int restore_master_link(int nlsk, struct ns_id *ns, struct net_link *link)
+{
+	struct newlink_req req;
+
+	memset(&req, 0, sizeof(req));
+
+	req.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.h.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE;
+	req.h.nlmsg_type = RTM_SETLINK;
+	req.h.nlmsg_seq = CR_NLMSG_SEQ;
+	req.i.ifi_family = AF_PACKET;
+	req.i.ifi_index = link->nde->ifindex;
+	req.i.ifi_flags = link->nde->flags;
+
+	addattr_l(&req.h, sizeof(req), IFLA_MASTER,
+			&link->nde->master, sizeof(link->nde->master));
+
+	return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL, NULL, NULL);
+}
+
+struct net_link *lookup_net_link(struct ns_id *ns, uint32_t ifindex)
+{
+	struct net_link *link;
+
+	list_for_each_entry(link, &ns->net.links, node)
+		if (link->nde->ifindex == ifindex)
+			return link;
+
+	return NULL;
+}
+
+static int __restore_links(struct ns_id *nsid, int *nrlinks, int *nrcreated)
 {
 	struct net_link *link, *t;
-	int exit_code = -1, nlsk = -1;
-	struct ns_id *nsid;
+	int ret;
 
-	for (nsid = ns_ids; nsid != NULL; nsid = nsid->next) {
-		if (nsid->nd != &net_ns_desc)
+	list_for_each_entry_safe(link, t, &nsid->net.links, node) {
+		struct net_link *mlink = NULL;
+
+		if (link->created)
 			continue;
 
-		if (switch_ns_by_fd(nsid->net.ns_fd, &net_ns_desc, NULL))
-			goto out;
+		(*nrlinks)++;
 
-		nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-		if (nlsk < 0) {
-			pr_perror("Can't create nlk socket");
-			return -1;
+		pr_debug("Try to restore a link %d:%d:%s",
+				nsid->id, link->nde->ifindex, link->nde->name);
+		if (link->nde->has_master) {
+			mlink = lookup_net_link(nsid, link->nde->master);
+			if (mlink == NULL) {
+				pr_err("Unable to find the %d master\n", link->nde->master);
+				return -1;
+			}
+
+			if (!mlink->created) {
+				pr_debug("The master %d:%d:%s isn't created yet",
+					nsid->id, mlink->nde->ifindex, mlink->nde->name);
+				continue;
+			}
 		}
 
-		list_for_each_entry_safe(link, t, &nsid->net.links, node) {
-			if (restore_link(nlsk, nsid, link))
-				goto out;
+		ret = restore_link(nsid->net.nlsk, nsid, link);
+		if (ret < 0)
+			return -1;
+
+		if (ret == 0) {
+			(*nrcreated)++;
+			link->created = true;
+
+			if (mlink && restore_master_link(nsid->net.nlsk, nsid, link))
+				return -1;
 		}
-		close_safe(&nlsk);
 	}
 
-	exit_code = 0;
-out:
-	close_safe(&nlsk);
+	return 0;
+}
 
-	return exit_code;
+static int restore_links()
+{
+	int nrcreated, nrlinks;
+	struct ns_id *nsid;
+
+	while (true) {
+		nrcreated = 0;
+		nrlinks = 0;
+		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))
+				return -1;
+
+			if (__restore_links(nsid, &nrlinks, &nrcreated))
+				return -1;
+		}
+
+		if (nrcreated == nrlinks)
+			break;
+		if (nrcreated == 0) {
+			pr_err("Unable to restore network links");
+			return -1;
+		}
+	}
+
+	return 0;
 }
 
 
@@ -2060,6 +2108,13 @@  int prepare_net_namespaces()
 
 		if (prepare_net_ns_first_stage(nsid))
 			goto err;
+
+		nsid->net.nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+		if (nsid->net.nlsk < 0) {
+			pr_perror("Can't create nlk socket");
+			return -1;
+		}
+
 	}
 
 	if (restore_links())
@@ -2074,6 +2129,8 @@  int prepare_net_namespaces()
 
 		if (prepare_net_ns_second_stage(nsid))
 			goto err;
+
+		close_safe(&nsid->net.nlsk);
 	}
 
 	close_service_fd(NS_FD_OFF);
diff --git a/images/netdev.proto b/images/netdev.proto
index 5bf39ef..1848fc3 100644
--- a/images/netdev.proto
+++ b/images/netdev.proto
@@ -45,6 +45,8 @@  message net_device_entry {
 
 	optional uint32 peer_ifindex	= 12;
 	optional uint32 peer_nsid	= 13;
+
+	optional uint32 master		= 14;
 }
 
 message netns_id {

Comments

Pavel Emelianov March 13, 2017, 10:58 a.m.
> @@ -1369,37 +1344,110 @@ exit:
>  	return ret;
>  }
>  
> -static int restore_links()
> +static int restore_master_link(int nlsk, struct ns_id *ns, struct net_link *link)
> +{
> +	struct newlink_req req;
> +
> +	memset(&req, 0, sizeof(req));
> +
> +	req.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
> +	req.h.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE;
> +	req.h.nlmsg_type = RTM_SETLINK;
> +	req.h.nlmsg_seq = CR_NLMSG_SEQ;
> +	req.i.ifi_family = AF_PACKET;
> +	req.i.ifi_index = link->nde->ifindex;
> +	req.i.ifi_flags = link->nde->flags;
> +
> +	addattr_l(&req.h, sizeof(req), IFLA_MASTER,
> +			&link->nde->master, sizeof(link->nde->master));
> +
> +	return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL, NULL, NULL);

This is move_to_bridge() isn't it? Can we factor this out?

> +}
> +
> +struct net_link *lookup_net_link(struct ns_id *ns, uint32_t ifindex)
> +{
> +	struct net_link *link;
> +
> +	list_for_each_entry(link, &ns->net.links, node)
> +		if (link->nde->ifindex == ifindex)
> +			return link;
> +
> +	return NULL;
> +}
> +
Andrey Vagin March 20, 2017, 9:15 p.m.
On Mon, Mar 13, 2017 at 01:58:02PM +0300, Pavel Emelyanov wrote:
> 
> > @@ -1369,37 +1344,110 @@ exit:
> >  	return ret;
> >  }
> >  
> > -static int restore_links()
> > +static int restore_master_link(int nlsk, struct ns_id *ns, struct net_link *link)
> > +{
> > +	struct newlink_req req;
> > +
> > +	memset(&req, 0, sizeof(req));
> > +
> > +	req.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
> > +	req.h.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE;
> > +	req.h.nlmsg_type = RTM_SETLINK;
> > +	req.h.nlmsg_seq = CR_NLMSG_SEQ;
> > +	req.i.ifi_family = AF_PACKET;
> > +	req.i.ifi_index = link->nde->ifindex;
> > +	req.i.ifi_flags = link->nde->flags;
> > +
> > +	addattr_l(&req.h, sizeof(req), IFLA_MASTER,
> > +			&link->nde->master, sizeof(link->nde->master));
> > +
> > +	return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL, NULL, NULL);
> 
> This is move_to_bridge() isn't it? Can we factor this out?

move_to_bridge use ioctl-s and does some other actions if_nametoindex(),
changeflags(). Here I know that if we have nsid in namespaces, we can
use netlink messages to add a device to a bridge. Actually it isn't only
about bridge-s. We set a master device, it will work for bondings too.

> 
> > +}
> > +
> > +struct net_link *lookup_net_link(struct ns_id *ns, uint32_t ifindex)
> > +{
> > +	struct net_link *link;
> > +
> > +	list_for_each_entry(link, &ns->net.links, node)
> > +		if (link->nde->ifindex == ifindex)
> > +			return link;
> > +
> > +	return NULL;
> > +}
> > +
>