mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 06:05:27 +00:00
[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.
This commit is contained in:
parent
99ded85f45
commit
e59eb52fad
@ -64,6 +64,7 @@ CLIENT_SOURCES = \
|
||||
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
|
||||
|
||||
|
219
src/veth.c
Normal file
219
src/veth.c
Normal file
@ -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;
|
||||
}
|
24
src/veth.h
Normal file
24
src/veth.h
Normal file
@ -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 */
|
Loading…
Reference in New Issue
Block a user