[CRIU] [PATCH 06/12] netns: dump and restore network namespace ID-s

Pavel Emelyanov xemul at virtuozzo.com
Tue Mar 21 03:41:40 PDT 2017


On 03/21/2017 12:01 AM, Andrei Vagin wrote:
> On Mon, Mar 13, 2017 at 02:10:35PM +0300, Pavel Emelyanov wrote:
>> 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?
> 
> When we create network devices, we need to switch between namespaces or
> set namespaces for pair devices, so it is more optimal to have
> descriptors on this stage.
> 
> nsfd_id is required to restore sockets, when we can't use randow file
> descirptors, because they can conflict with process file descriptors.

So these two are used "sequentially", one on early stage only and
the other one on later stage only, aren't they? Can we union them?

>>
>>>  			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?
> 
> If a device has a pair in another netns, the kernel will generate nsid
> for the second netns in the first netns when we requiest information
> about this device. So we list all devices before dumping net ids in this
> namespace.

We need a good descriptive comment about this fact in
that routine.

>>
>>> +
>>>  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.
> 
> I don't understand what you mean. Each namespace has own set of net ids
> and it has ids only for a few of other namespaces.
> 
> 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;
> 
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this means that this namespace doesn't
> have id in the "ns" netns.

Ah! Please, add code comment about it.

>         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;
> }               



More information about the CRIU mailing list