[lxc-devel] [PATCH] Add get_interfaces to the API - v3

Stéphane Graber stgraber at ubuntu.com
Wed Sep 18 18:47:15 UTC 2013


On Mon, Sep 16, 2013 at 05:01:11PM -0400, S.Çağlar Onur wrote:
> get_ips accepts an interface name as a parameter but there was no
> way to get the interfaces names from the container. This patch
> introduces a new get_interfaces call to the API so that users
> can obtain the name of the interfaces.
> 
> Support for python bindings also introduced as a part of this version.
> 
> Signed-off-by: S.Çağlar Onur <caglar at 10ur.org>

Acked-by: Stéphane Graber <stgraber at ubuntu.com>

> ---
>  src/lxc/lxccontainer.c              | 129 ++++++++++++++++++++++++++----------
>  src/lxc/lxccontainer.h              |   3 +
>  src/lxc/utils.c                     |  22 +++++-
>  src/lxc/utils.h                     |   1 +
>  src/python-lxc/examples/api_test.py |   5 ++
>  src/python-lxc/lxc.c                |  60 +++++++++++++++--
>  src/python-lxc/lxc/__init__.py      |   8 +++
>  7 files changed, 189 insertions(+), 39 deletions(-)
> 
> diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> index 79237df..8621cd8 100644
> --- a/src/lxc/lxccontainer.c
> +++ b/src/lxc/lxccontainer.c
> @@ -1179,23 +1179,26 @@ static bool lxcapi_clear_config_item(struct lxc_container *c, const char *key)
>  	return ret == 0;
>  }
>  
> -char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, int scope)
> -{
> -	int count = 0;
> -	struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
> -	char addressOutputBuffer[INET6_ADDRSTRLEN];
> -	void *tempAddrPtr = NULL;
> -	char **addresses = NULL, **temp;
> -	char *address = NULL;
> +static inline void exit_from_ns(struct lxc_container *c, int *old_netns, int *new_netns) {
> +	/* Switch back to original netns */
> +	if (*old_netns >= 0 && setns(*old_netns, CLONE_NEWNET))
> +		SYSERROR("failed to setns");
> +	if (*new_netns >= 0)
> +		close(*new_netns);
> +	if (*old_netns >= 0)
> +		close(*old_netns);
> +}
> +
> +static inline bool enter_to_ns(struct lxc_container *c, int *old_netns, int *new_netns) {
> +	int ret = 0;
>  	char new_netns_path[MAXPATHLEN];
> -	int old_netns = -1, new_netns = -1, ret = 0;
>  
>  	if (!c->is_running(c))
>  		goto out;
>  
>  	/* Save reference to old netns */
> -	old_netns = open("/proc/self/ns/net", O_RDONLY);
> -	if (old_netns < 0) {
> +	*old_netns = open("/proc/self/ns/net", O_RDONLY);
> +	if (*old_netns < 0) {
>  		SYSERROR("failed to open /proc/self/ns/net");
>  		goto out;
>  	}
> @@ -1205,16 +1208,91 @@ char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, in
>  	if (ret < 0 || ret >= MAXPATHLEN)
>  		goto out;
>  
> -	new_netns = open(new_netns_path, O_RDONLY);
> -	if (new_netns < 0) {
> +	*new_netns = open(new_netns_path, O_RDONLY);
> +	if (*new_netns < 0) {
>  		SYSERROR("failed to open %s", new_netns_path);
>  		goto out;
>  	}
>  
> -	if (setns(new_netns, CLONE_NEWNET)) {
> +	if (setns(*new_netns, CLONE_NEWNET)) {
>  		SYSERROR("failed to setns");
>  		goto out;
>  	}
> +	return true;
> +out:
> +	exit_from_ns(c, old_netns, new_netns);
> +	return false;
> +}
> +
> +static char** lxcapi_get_interfaces(struct lxc_container *c)
> +{
> +	int count = 0, i;
> +	bool found = false;
> +	struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
> +	char **interfaces = NULL, **temp;
> +	int old_netns = -1, new_netns = -1;
> +
> +	if (!enter_to_ns(c, &old_netns, &new_netns))
> +		goto out;
> +
> +	/* Grab the list of interfaces */
> +	if (getifaddrs(&interfaceArray)) {
> +		SYSERROR("failed to get interfaces list");
> +		goto out;
> +	}
> +
> +	/* Iterate through the interfaces */
> +	for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) {
> +		/*
> +		 * WARNING: Following "for" loop does a linear search over the interfaces array
> +		 * For the containers with lots of interfaces this may be problematic.
> +         * I'm not expecting this to be the common usage but if it turns out to be
> +		 *     than using binary search or a hash table could be more elegant solution.
> +	 	 */
> +		for (i = 0; i < count; i++) {
> +			if (strcmp(interfaces[i], tempIfAddr->ifa_name) == 0) {
> +				found = true;
> +				break;
> +			}
> +		}
> +
> +		if (!found) {
> +			count += 1;
> +			temp = realloc(interfaces, count * sizeof(*interfaces));
> +			if (!temp) {
> +				count -= 1;
> +				goto out;
> +			}
> +			interfaces = temp;
> +			interfaces[count - 1] = strdup(tempIfAddr->ifa_name);
> +		}
> +		found = false;
> +    }
> +
> +out:
> +       if (interfaceArray)
> +               freeifaddrs(interfaceArray);
> +
> +       exit_from_ns(c, &old_netns, &new_netns);
> +
> +       /* Append NULL to the array */
> +       interfaces = (char **)lxc_append_null_to_array((void **)interfaces, count);
> +
> +       return interfaces;
> +}
> +
> +static char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, int scope)
> +{
> +	int count = 0;
> +	struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
> +	char addressOutputBuffer[INET6_ADDRSTRLEN];
> +	void *tempAddrPtr = NULL;
> +	char **addresses = NULL, **temp;
> +	char *address = NULL;
> +	int old_netns = -1, new_netns = -1;
> +
> +	if (!enter_to_ns(c, &old_netns, &new_netns))
> +		goto out;
>  
>  	/* Grab the list of interfaces */
>  	if (getifaddrs(&interfaceArray)) {
> @@ -1265,28 +1343,10 @@ out:
>  	if(interfaceArray)
>  		freeifaddrs(interfaceArray);
>  
> -	/* Switch back to original netns */
> -	if (old_netns >= 0 && setns(old_netns, CLONE_NEWNET))
> -		SYSERROR("failed to setns");
> -	if (new_netns >= 0)
> -		close(new_netns);
> -	if (old_netns >= 0)
> -		close(old_netns);
> +	exit_from_ns(c, &old_netns, &new_netns);
>  
>  	/* Append NULL to the array */
> -	if (count) {
> -		count++;
> -		temp = realloc(addresses, count * sizeof(*addresses));
> -		if (!temp) {
> -			int i;
> -			for (i = 0; i < count-1; i++)
> -				free(addresses[i]);
> -			free(addresses);
> -			return NULL;
> -		}
> -		addresses = temp;
> -		addresses[count - 1] = NULL;
> -	}
> +	addresses = (char **)lxc_append_null_to_array((void **)addresses, count);
>  
>  	return addresses;
>  }
> @@ -2576,6 +2636,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
>  	c->get_config_path = lxcapi_get_config_path;
>  	c->set_config_path = lxcapi_set_config_path;
>  	c->clone = lxcapi_clone;
> +	c->get_interfaces = lxcapi_get_interfaces;
>  	c->get_ips = lxcapi_get_ips;
>  	c->attach = lxcapi_attach;
>  	c->attach_run_wait = lxcapi_attach_run_wait;
> diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
> index f9ae43b..89b55bd 100644
> --- a/src/lxc/lxccontainer.h
> +++ b/src/lxc/lxccontainer.h
> @@ -90,6 +90,9 @@ struct lxc_container {
>  	 * the length which was our would be printed. */
>  	int (*get_config_item)(struct lxc_container *c, const char *key, char *retv, int inlen);
>  	int (*get_keys)(struct lxc_container *c, const char *key, char *retv, int inlen);
> +	// Return interface names.  The result is strdup()d, so free the result.
> +	char** (*get_interfaces)(struct lxc_container *c);
> +	// Return IP addresses.  The result is strdup()d, so free the result.
>  	char** (*get_ips)(struct lxc_container *c, char* interface, char* family, int scope);
>  	/*
>  	 * get_cgroup_item returns the number of bytes read, or an error (<0).
> diff --git a/src/lxc/utils.c b/src/lxc/utils.c
> index 78b234d..924cc19 100644
> --- a/src/lxc/utils.c
> +++ b/src/lxc/utils.c
> @@ -852,7 +852,7 @@ int lxc_write_to_file(const char *filename, const void* buf, size_t count, bool
>  		return -1;
>  	ret = lxc_write_nointr(fd, buf, count);
>  	if (ret < 0)
> -		goto out_error; 
> +		goto out_error;
>  	if ((size_t)ret != count)
>  		goto out_error;
>  	if (add_newline) {
> @@ -899,3 +899,23 @@ int lxc_read_from_file(const char *filename, void* buf, size_t count)
>  	errno = saved_errno;
>  	return ret;
>  }
> +
> +void **lxc_append_null_to_array(void **array, size_t count)
> +{
> +	void **temp;
> +
> +	/* Append NULL to the array */
> +	if (count) {
> +		temp = realloc(array, (count + 1) * sizeof(*array));
> +		if (!temp) {
> +			int i;
> +			for (i = 0; i < count; i++)
> +				free(array[i]);
> +			free(array);
> +			return NULL;
> +		}
> +		array = temp;
> +		array[count] = NULL;
> +	}
> +	return array;
> +}
> diff --git a/src/lxc/utils.h b/src/lxc/utils.h
> index ba7cfb3..55f98fa 100644
> --- a/src/lxc/utils.h
> +++ b/src/lxc/utils.h
> @@ -236,4 +236,5 @@ extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
>  extern size_t lxc_array_len(void **array);
>  extern void **lxc_dup_array(void **array, lxc_dup_fn element_dup_fn, lxc_free_fn element_free_fn);
>  
> +extern void **lxc_append_null_to_array(void **array, size_t count);
>  #endif
> diff --git a/src/python-lxc/examples/api_test.py b/src/python-lxc/examples/api_test.py
> index e078d2b..4754332 100644
> --- a/src/python-lxc/examples/api_test.py
> +++ b/src/python-lxc/examples/api_test.py
> @@ -89,6 +89,11 @@ assert(container.init_pid > 1)
>  assert(container.running)
>  assert(container.state == "RUNNING")
>  
> +
> +## Checking IP address
> +print("Getting the interface names")
> +assert(container.get_interfaces() == ('lo', 'eth0'))
> +
>  ## Checking IP address
>  print("Getting the IP addresses")
>  
> diff --git a/src/python-lxc/lxc.c b/src/python-lxc/lxc.c
> index bd053a7..b6e0804 100644
> --- a/src/python-lxc/lxc.c
> +++ b/src/python-lxc/lxc.c
> @@ -411,6 +411,52 @@ Container_get_keys(Container *self, PyObject *args, PyObject *kwds)
>  }
>  
>  static PyObject *
> +Container_get_interfaces(Container *self)
> +{
> +    int i = 0;
> +    char** interfaces = NULL;
> +
> +    PyObject* ret;
> +
> +    /* Get the interfaces */
> +    interfaces = self->container->get_interfaces(self->container);
> +    if (!interfaces)
> +        return PyTuple_New(0);
> +
> +    /* Count the entries */
> +    while (interfaces[i])
> +        i++;
> +
> +    /* Create the new tuple */
> +    ret = PyTuple_New(i);
> +    if (!ret)
> +        return NULL;
> +
> +    /* Add the entries to the tuple and free the memory */
> +    i = 0;
> +    while (interfaces[i]) {
> +        PyObject *unicode = PyUnicode_FromString(interfaces[i]);
> +        if (!unicode) {
> +            Py_DECREF(ret);
> +            ret = NULL;
> +            break;
> +        }
> +        PyTuple_SET_ITEM(ret, i, unicode);
> +        i++;
> +    }
> +
> +    /* Free the list of IPs */
> +    i = 0;
> +    while (interfaces[i]) {
> +        free(interfaces[i]);
> +        i++;
> +    }
> +    free(interfaces);
> +
> +    return ret;
> +}
> +
> +static PyObject *
>  Container_get_ips(Container *self, PyObject *args, PyObject *kwds)
>  {
>      static char *kwlist[] = {"interface", "family", "scope", NULL};
> @@ -898,15 +944,15 @@ LXC_arch_to_personality(PyObject *self, PyObject *arg)
>          PyErr_SetString(PyExc_ValueError, "Expected a string");
>          return NULL;
>      }
> -    
> +
>      pystr = PyUnicode_AsUTF8String(arg);
>      if (!pystr)
>          return NULL;
> -    
> +
>      str = PyBytes_AsString(pystr);
>      if (!str)
>          goto out;
> -    
> +
>      rv = lxc_config_parse_arch(str);
>      if (rv == -1)
>          PyErr_SetString(PyExc_KeyError, "Failed to lookup architecture.");
> @@ -1025,6 +1071,12 @@ static PyMethodDef Container_methods[] = {
>       "\n"
>       "Get a list of valid sub-keys for a key."
>      },
> +    {"get_interfaces", (PyCFunction)Container_get_interfaces,
> +     METH_NOARGS,
> +     "get_interface() -> tuple\n"
> +     "\n"
> +     "Get a tuple of interfaces for the container."
> +    },
>      {"get_ips", (PyCFunction)Container_get_ips,
>       METH_VARARGS|METH_KEYWORDS,
>       "get_ips(interface, family, scope) -> tuple\n"
> @@ -1205,7 +1257,7 @@ PyInit__lxc(void)
>  
>      /* add constants */
>      d = PyModule_GetDict(m);
> - 
> +
>      #define PYLXC_EXPORT_CONST(c) PyDict_SetItemString(d, #c, PyLong_FromLong(c))
>  
>      /* environment variable handling */
> diff --git a/src/python-lxc/lxc/__init__.py b/src/python-lxc/lxc/__init__.py
> index 3fb76dc..6a29903 100644
> --- a/src/python-lxc/lxc/__init__.py
> +++ b/src/python-lxc/lxc/__init__.py
> @@ -333,6 +333,14 @@ class Container(_lxc.Container):
>          else:
>              return value
>  
> +    def get_interfaces(self):
> +        """
> +            Get a tuple of interfaces for the container.
> +        """
> +
> +        return _lxc.Container.get_interfaces(self)
> +
> +
>      def get_ips(self, interface=None, family=None, scope=None, timeout=0):
>          """
>              Get a tuple of IPs for the container.
> -- 
> 1.8.1.2
> 
> 
> ------------------------------------------------------------------------------
> LIMITED TIME SALE - Full Year of Microsoft Training For Just $49.99!
> 1,500+ hours of tutorials including VisualStudio 2012, Windows 8, SharePoint
> 2013, SQL 2012, MVC 4, more. BEST VALUE: New Multi-Library Power Pack includes
> Mobile, Cloud, Java, and UX Design. Lowest price ever! Ends 9/20/13. 
> http://pubads.g.doubleclick.net/gampad/clk?id=58041151&iu=/4140/ostg.clktrk
> _______________________________________________
> Lxc-devel mailing list
> Lxc-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20130918/409e3592/attachment.pgp>


More information about the lxc-devel mailing list