Dan Smith wrote:
# HG changeset patch
# User Dave Leskovec <dlesko(a)linux.vnet.ibm.com>
# Date 1213891164 25200
# Node ID 386c067de8995028dd11f70602081c31682dd293
# Parent 8d2afc533c91c4796512e1e71c8283e86eafd18a
[LXC] Add functions to manage veth device pairs
This gives us the ability to create a veth pair so that we can move one
into the network namespace of an LXC container.
diff -r 8d2afc533c91 -r 386c067de899 configure.in
--- a/configure.in Tue Jun 17 15:55:03 2008 +0000
+++ b/configure.in Thu Jun 19 08:59:24 2008 -0700
@@ -301,6 +301,20 @@
if test "$with_qemu" = "yes" ; then
AC_CHECK_HEADERS([linux/param.h linux/sockios.h linux/if_bridge.h linux/if_tun.h],,
AC_MSG_ERROR([You must install kernel-headers in order to compile
libvirt]))
+fi
+
+dnl
+dnl check for patched iproute2 for lxc network support
+dnl
+if test "$with_lxc" = "yes" ; then
+ AC_MSG_CHECKING([for NETNS support])
+ if ip link help 2>&1 | grep -q netns; then
+ with_lxc_netns="yes"
+ AC_DEFINE([HAVE_NETNS], [], [Kernel has NETNS support])
+ else
+ with_lxc_netns="no"
+ fi
+ AC_MSG_RESULT($with_lxc_netns)
fi
dnl Need to test if pkg-config exists
diff -r 8d2afc533c91 -r 386c067de899 src/Makefile.am
--- a/src/Makefile.am Tue Jun 17 15:55:03 2008 +0000
+++ b/src/Makefile.am Thu Jun 19 08:59:24 2008 -0700
@@ -64,6 +64,7 @@
lxc_driver.c lxc_driver.h \
lxc_conf.c lxc_conf.h \
lxc_container.c lxc_container.h \
+ veth.c veth.h \
nodeinfo.h nodeinfo.c \
util.c util.h
diff -r 8d2afc533c91 -r 386c067de899 src/veth.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/veth.c Thu Jun 19 08:59:24 2008 -0700
@@ -0,0 +1,247 @@
+/*
+ * Copyright IBM Corp. 2008
+ *
+ * veth.c: file description
+ *
+ * Authors:
+ * David L. Leskovec <dlesko at linux.vnet.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <config.h>
+
+#ifdef HAVE_NETNS
+
+#include <string.h>
+
+#include "veth.h"
+#include "internal.h"
+#include "memory.h"
+#include "util.h"
+
+#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
+#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
Do you know ##__VA_ARGS ?
+/* Functions */
+/**
+ * getFreeVethName:
+ * @veth: name for veth device (NULL to find first open)
+ * @maxLen: max length of veth name
+ * @startDev: device number to start at (x in vethx)
+ *
+ * Looks in /sys/class/net/ to find the first available veth device
+ * name.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int getFreeVethName(char *veth, int maxLen, int startDev)
+{
+ int rc = -1;
+ int devNum = startDev;
+ char path[PATH_MAX];
+
+ snprintf(path, PATH_MAX, "/sys/class/net/veth%d/", devNum);
You can perhaps, use do { ... } while () here.
+ while (virFileExists(path)) {
+ ++devNum;
+ sprintf(path, "/sys/class/net/veth%d/", devNum);
+ }
Is this function safe for concurrent access ? eg. getFreeVethName called
in parallel by two processes or another process creates a pair device
just after you exit the loop ?
+ snprintf(veth, maxLen, "veth%d", devNum);
+
+ rc = devNum;
+
+ return rc;
+}
+
+/**
+ * vethCreate:
+ * @veth1: name for one end of veth pair
+ * @veth1MaxLen: max length of veth1 name
+ * @veth2: name for one end of veth pair
+ * @veth2MaxLen: max length of veth1 name
+ *
+ * Creates a veth device pair using the ip command:
+ * ip link add veth1 type veth peer name veth2
+ * NOTE: If veth1 and veth2 names are not specified, ip will auto assign
+ * names. There seems to be two problems here -
+ * 1) There doesn't seem to be a way to determine the names of the
+ * devices that it creates. They show up in ip link show and
+ * under /sys/class/net/ however there is no guarantee that they
+ * are the devices that this process just created.
+ * 2) Once one of the veth devices is moved to another namespace, it
+ * is no longer visible in the parent namespace. This seems to
+ * confuse the name assignment causing it to fail with File exists.
+ * Because of these issues, this function currently forces the caller
+ * to fully specify the veth device names.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+int vethCreate(char* veth1, int veth1MaxLen,
+ char* veth2, int veth2MaxLen)
No need of the veth1MaxLen parameter, you already have it, it is
IF_NAMESIZE.
+{
+ int rc = -1;
+ const char *argv[] = {
+ "ip", "link", "add", veth1, "type",
"veth", "peer", "name", veth2, NULL
+ };
+ int cmdResult;
+ int vethDev = 0;
+
+ if ((NULL == veth1) || (NULL == veth2)) {
+ goto error_out;
+ }
+
+ DEBUG("veth1: %s veth2: %s", veth1, veth2);
+
+ if (1 > strlen(veth1)) {
Why do you check with strlen > 1 ?
+ vethDev = getFreeVethName(veth1, veth1MaxLen, 0);
+ ++vethDev;
+ DEBUG("assigned veth1: %s", veth1);
+ }
+
+ if (1 > strlen(veth2)) {
+ vethDev = getFreeVethName(veth2, veth2MaxLen, vethDev);
+ DEBUG("assigned veth2: %s", veth2);
+ }
+
+ rc = virRun(NULL, (char**)argv, &cmdResult);
+
+ if (0 == rc) {
+ rc = cmdResult;
+ }
+
+error_out:
+ return rc;
+}
+
+/**
+ * vethDelete:
+ * @veth: name for one end of veth pair
+ *
+ * This will delete both veth devices in a pair. Only one end needs to
+ * be specified. The ip command will identify and delete the other veth
+ * device as well.
+ * ip link del veth
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+int vethDelete(const char *veth)
+{
+ int rc = -1;
+ const char *argv[] = {"ip", "link", "del", veth,
NULL};
+ int cmdResult;
+
+ if (NULL == veth) {
+ goto error_out;
+ }
+
+ DEBUG("veth: %s", veth);
+
+ rc = virRun(NULL, (char**)argv, &cmdResult);
+
+ if (0 == rc) {
+ rc = cmdResult;
+ }
+
+error_out:
+ return rc;
+}
+
+/**
+ * vethInterfaceUpOrDown:
+ * @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.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+int vethInterfaceUpOrDown(const char* veth, int upOrDown)
+{
+ int rc = -1;
+ char upOrDownString[8];
+ const char *argv[] = {"ifconfig", veth, upOrDownString, NULL};
+ int cmdResult;
+
+ if (NULL == veth) {
+ goto error_out;
+ }
+
+ if (0 == upOrDown) {
+ strcpy(upOrDownString, "down");
+ } else {
+ strcpy(upOrDownString, "up");
+ }
You don't need to copy the string, a const char *upOrDownString and
upOrDownString = "down" will work.
+
+ rc = virRun(NULL, (char**)argv, &cmdResult);
+
+ if (0 == rc) {
+ rc = cmdResult;
+ }
+
+error_out:
+ return rc;
+}
+
+/**
+ * moveInterfaceToNetNs:
+ * @interface: name of device
+ * @pidInNs: PID of process in target net namespace
+ *
+ * Moves the given device into the target net namespace specified by the given
+ * pid using this command:
+ * ip link set interface netns pidInNs
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+int moveInterfaceToNetNs(const char* interface, int pidInNs)
+{
+ int rc;
+ /* offset of the pid field in the following args */
+ const int pidArgvOffset = 5;
+ const char *argv[] = {
+ "ip", "link", "set", interface, "netns",
NULL, NULL
+ };
+ int cmdResult;
+ int len;
+
+ if (NULL == interface) {
+ goto error_out;
+ }
+
+ if (0 != VIR_ALLOC_N(argv[pidArgvOffset], (sizeof(int) * 3) + 1)) {
+ goto error_out;
+ }
+ len = snprintf(argv[pidArgvOffset], (sizeof(int) * 3) + 1, "%d",
pidInNs);
+ if (len >= (sizeof(int) * 3) + 1) {
+ goto cleanup;
+ }
Why don't you just do:
char pidstr[PIDSTRLEN];
const char *argv[] = { "ip", "link", "set", interface,
"netns", pidstr,
NULL };
snprintf(pidstr, PIDSTRLEN, "%d", pidInNs);
That should work, no ?
+
+ rc = virRun(NULL, (char**)argv, &cmdResult);
+
+ if (0 == rc) {
+ rc = cmdResult;
+ }
+
+cleanup:
+ VIR_FREE(argv[pidArgvOffset]);
+
+error_out:
+ return rc;
+}
+
+#endif /* HAVE_NETNS */
+
diff -r 8d2afc533c91 -r 386c067de899 src/veth.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/veth.h Thu Jun 19 08:59:24 2008 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright IBM Corp. 2008
+ *
+ * veth.h: file description
+ *
+ * Authors:
+ * David L. Leskovec <dlesko at linux.vnet.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef VETH_H
+#define VETH_H
+
+#include <config.h>
+
+#ifdef HAVE_NETNS
+
+/* Function declarations */
+int vethCreate(char* veth1, int veth1MaxLen, char* veth2,
+ int veth2MaxLen);
+int vethDelete(const char* veth);
+int vethInterfaceUpOrDown(const char* veth, int upOrDown);
+int moveInterfaceToNetNs(const char *interface, int pidInNs);
+
+#endif /* HAVE_NETNS */
+#endif /* VETH_H */