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 <cag...@10ur.org>
---
 src/lxc/lxccontainer.c              | 133 ++++++++++++++++++++++++++----------
 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, 191 insertions(+), 41 deletions(-)

diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index d77ce37..e8dde91 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -1179,25 +1179,30 @@ 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");
+       process_lock();
+       if (*new_netns >= 0)
+               close(*new_netns);
+       if (*old_netns >= 0)
+               close(*old_netns);
+       process_unlock();
+}
+
+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 */
        process_lock();
-       old_netns = open("/proc/self/ns/net", O_RDONLY);
+       *old_netns = open("/proc/self/ns/net", O_RDONLY);
        process_unlock();
-       if (old_netns < 0) {
+       if (*old_netns < 0) {
                SYSERROR("failed to open /proc/self/ns/net");
                goto out;
        }
@@ -1208,17 +1213,92 @@ char** lxcapi_get_ips(struct lxc_container *c, char* 
interface, char* family, in
                goto out;
 
        process_lock();
-       new_netns = open(new_netns_path, O_RDONLY);
+       *new_netns = open(new_netns_path, O_RDONLY);
        process_unlock();
-       if (new_netns < 0) {
+       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)) {
@@ -1269,30 +1349,10 @@ out:
        if(interfaceArray)
                freeifaddrs(interfaceArray);
 
-       /* Switch back to original netns */
-       if (old_netns >= 0 && setns(old_netns, CLONE_NEWNET))
-               SYSERROR("failed to setns");
-       process_lock();
-       if (new_netns >= 0)
-               close(new_netns);
-       if (old_netns >= 0)
-               close(old_netns);
-       process_unlock();
+       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;
 }
@@ -2642,6 +2702,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 00e13d5..a908b5c 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -880,7 +880,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) {
@@ -935,3 +935,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@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel

Reply via email to