Skip to content

Commit

Permalink
Add get_interfaces to the API
Browse files Browse the repository at this point in the history
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@10ur.org>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
  • Loading branch information
caglar10ur authored and stgraber committed Sep 18, 2013
1 parent 025ed0f commit 799f29a
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 41 deletions.
133 changes: 97 additions & 36 deletions src/lxc/lxccontainer.c
Expand Up @@ -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;
}
Expand All @@ -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)) {
Expand Down Expand Up @@ -1269,30 +1349,10 @@ char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, in
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;
}
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/lxc/lxccontainer.h
Expand Up @@ -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).
Expand Down
22 changes: 21 additions & 1 deletion src/lxc/utils.c
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
1 change: 1 addition & 0 deletions src/lxc/utils.h
Expand Up @@ -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
5 changes: 5 additions & 0 deletions src/python-lxc/examples/api_test.py
Expand Up @@ -89,6 +89,11 @@
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")

Expand Down
60 changes: 56 additions & 4 deletions src/python-lxc/lxc.c
Expand Up @@ -410,6 +410,52 @@ Container_get_keys(Container *self, PyObject *args, PyObject *kwds)
return ret;
}

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)
{
Expand Down Expand Up @@ -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.");
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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 */
Expand Down
8 changes: 8 additions & 0 deletions src/python-lxc/lxc/__init__.py
Expand Up @@ -333,6 +333,14 @@ def get_keys(self, key=None):
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.
Expand Down

0 comments on commit 799f29a

Please sign in to comment.