Currently, the lxc implementation invokes 'ip' and 'ifconfig' commands
inside a container using 'virRun'. That has the side effect of requiring
those commands to be present and to function in a manner consistent with
the usage. Some small roots (such as ttylinux) may not have 'ip' or
'ifconfig'.
This patch replaces the use of these commands with usage of
netdevice. The result is that lxc containers do not have to implement
those commands, and lxc in libvirt is only dependent on the netdevice
interface.
I've tested this patch locally against the ubuntu libvirt version enough
to verify its generally sane. I attempted to build upstream today, but
failed with:
/usr/bin/ld:
../src/.libs/libvirt_driver_qemu.a(libvirt_driver_qemu_la-qemu_domain.o):
undefined reference to symbol 'xmlXPathRegisterNs@(a)LIBXML2_2.4.30
Thats probably a local issue only, but I wanted to get this patch up and
see what others thought of it. This is ubuntu bug
https://bugs.launchpad.net/ubuntu/+source/libvirt/+bug/828211 .
diff --git a/src/lxc/veth.c b/src/lxc/veth.c
index 34cb804..c24df91 100644
--- a/src/lxc/veth.c
+++ b/src/lxc/veth.c
@@ -12,8 +12,11 @@
#include <config.h>
+#include <linux/sockios.h>
+#include <net/if.h>
#include <string.h>
#include <stdio.h>
+#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -186,41 +189,49 @@ int vethDelete(const char *veth)
* @veth: name of veth device
* @upOrDown: 0 => down, 1 => up
*
- * Enables a veth device using the ifconfig command. A NULL inetAddress
- * will cause it to be left off the command line.
+ * Enables a veth device using SIOCSIFFLAGS
*
- * Returns 0 on success or -1 in case of error
+ * Returns 0 on success, -1 on failure, with errno set
*/
int vethInterfaceUpOrDown(const char* veth, int upOrDown)
{
- int rc;
- const char *argv[] = {"ifconfig", veth, NULL, NULL};
- int cmdResult = 0;
+ struct ifreq ifr;
+ int fd, ret;
- if (0 == upOrDown)
- argv[2] = "down";
- else
- argv[2] = "up";
+ if ((fd = socket(PF_PACKET, SOCK_DGRAM, 0)) == -1)
+ return(-1);
- rc = virRun(argv, &cmdResult);
+ memset(&ifr, 0, sizeof(struct ifreq));
- if (rc != 0 ||
- (WIFEXITED(cmdResult) && WEXITSTATUS(cmdResult) != 0)) {
- if (0 == upOrDown)
+ if (virStrcpyStatic(ifr.ifr_name, veth) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((ret = ioctl(fd, SIOCGIFFLAGS, &ifr)) == 0) {
+ if (upOrDown)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
+
+ ret = ioctl(fd, SIOCSIFFLAGS, &ifr);
+ }
+
+ close(fd);
+ if (ret == -1)
+ if (upOrDown == 0)
/*
* Prevent overwriting an error log which may be set
* where an actual failure occurs.
*/
- VIR_DEBUG("Failed to disable '%s' (%d)",
- veth, WEXITSTATUS(cmdResult));
+ VIR_DEBUG("Failed to disable '%s'", veth);
else
vethError(VIR_ERR_INTERNAL_ERROR,
- _("Failed to enable '%s' (%d)"),
- veth, WEXITSTATUS(cmdResult));
- rc = -1;
- }
+ _("Failed to enable '%s'"), veth);
+ else
+ ret = 0;
- return rc;
+ return(ret);
}
/**
@@ -279,17 +290,29 @@ int setMacAddr(const char* iface, const char* macaddr)
* @iface: name of device
* @new: new name of @iface
*
- * Changes the name of the given device with the
- * given new name using this command:
- * ip link set @iface name @new
+ * Changes the name of the given device.
*
- * Returns 0 on success or -1 in case of error
+ * Returns 0 on success, -1 on failure with errno set.
*/
int setInterfaceName(const char* iface, const char* new)
{
- const char *argv[] = {
- "ip", "link", "set", iface, "name", new,
NULL
- };
+ struct ifreq ifr;
+ int fd = socket(PF_PACKET, SOCK_DGRAM, 0);
- return virRun(argv, NULL);
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ if (virStrcpyStatic(ifr.ifr_name, iface) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (virStrcpyStatic(ifr.ifr_newname, new) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (ioctl(fd, SIOCSIFNAME, &ifr))
+ return -1;
+
+ return 0;
}