/* * veth.c: Tools for managing veth pairs * * Copyright IBM Corp. 2008 * * See COPYING.LIB for the License of this software * * Authors: * David L. Leskovec */ #include #include #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; }