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

Stéphane Graber stgraber at ubuntu.com
Wed Sep 18 19:41:53 UTC 2013


On Wed, Sep 18, 2013 at 03:11:28PM -0400, S.Çağlar Onur wrote:
> Not at all as I already did it on my tree, sending in a minute as v4...

Thanks, and pushed!

> 
> 
> On Wed, Sep 18, 2013 at 2:58 PM, Stéphane Graber <stgraber at ubuntu.com>wrote:
> 
> > On Wed, Sep 18, 2013 at 02:53:33PM -0400, S.Çağlar Onur wrote:
> > > Do you want me to sync this on top of staging and re-send?I think they
> > are
> > > conflicting right now.
> >
> > Ah, if you don't mind, that'd be great (I started doing it but I'm
> > getting interrupted quite a bit since I'm attending a conference)!
> >
> > > On Wed, Sep 18, 2013 at 2:47 PM, Stéphane Graber <stgraber at ubuntu.com
> > >wrote:
> > >
> > > > 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
> > > >
> > >
> > >
> > >
> > > --
> > > S.Çağlar Onur <caglar at 10ur.org>
> >
> > --
> > Stéphane Graber
> > Ubuntu developer
> > http://www.ubuntu.com
> >
> 
> 
> 
> -- 
> S.Çağlar Onur <caglar at 10ur.org>

-- 
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/04017b8a/attachment.pgp>


More information about the lxc-devel mailing list