[libvirt] [PATCH 2 of 4] [LXC] Add functions to manage veth device pairs

Dan Smith danms at us.ibm.com
Tue Jun 24 15:51:34 UTC 2008


This gives us the ability to create a veth pair so that we can move one
into the network namespace of an LXC container.

Changes from last time:
 - Fixed use of sprintf()
 - Fixed up 'ip link...' argument synthesis
 - Fixed license headers
 - Fixed while() {...} to do {...} while()
 - Fixed copying of const string in vethInterfaceUpOrDown()

diff -r 405ae197cd7e -r 203dce381784 src/Makefile.am
--- a/src/Makefile.am	Mon Jun 23 11:43:03 2008 -0700
+++ b/src/Makefile.am	Mon Jun 23 11:53:42 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 405ae197cd7e -r 203dce381784 src/veth.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/veth.c	Mon Jun 23 11:53:42 2008 -0700
@@ -0,0 +1,219 @@
+/*
+ * veth.c: Tools for managing veth pairs
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Authors:
+ *  David L. Leskovec <dlesko at linux.vnet.ibm.com>
+ */
+
+#include <config.h>
+
+#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)
+
+/* 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];
+
+    do {
+        snprintf(path, PATH_MAX, "/sys/class/net/veth%d/", devNum);
+        ++devNum;
+    } while (virFileExists(path));
+
+    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)
+{
+    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)) {
+        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;
+    const char *argv[] = {"ifconfig", veth, NULL, NULL};
+    int cmdResult;
+
+    if (NULL == veth) {
+        goto error_out;
+    }
+
+    if (0 == upOrDown)
+        argv[2] = "down";
+    else
+        argv[2] = "up";
+
+    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 */
+    char *pid = NULL;
+    const char *argv[] = {
+        "ip", "link", "set", interface, "netns", NULL, NULL
+    };
+    int cmdResult;
+    int len;
+
+    if (NULL == interface) {
+        goto error_out;
+    }
+
+    if (asprintf(&pid, "%d", pidInNs) == -1)
+        goto error_out;
+
+    argv[5] = pid;
+    rc = virRun(NULL, (char**)argv, &cmdResult);
+    if (0 == rc)
+        rc = cmdResult;
+
+error_out:
+    VIR_FREE(pid);
+    return rc;
+}
diff -r 405ae197cd7e -r 203dce381784 src/veth.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/veth.h	Mon Jun 23 11:53:42 2008 -0700
@@ -0,0 +1,24 @@
+/*
+ * veth.h: Interface to tools for managing veth pairs
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Authors:
+ *  David L. Leskovec <dlesko at linux.vnet.ibm.com>
+ */
+
+#ifndef VETH_H
+#define VETH_H
+
+#include <config.h>
+
+/* 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 /* VETH_H */




More information about the libvir-list mailing list