mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 21:34:54 +03:00
util:veth: Create veth device pair by netlink
When netlink is supported, use netlink to create veth device pair rather than 'ip link' command. Signed-off-by: Shi Lei <shi_lei@massclouds.com> Reviewed-by: Laine Stump <laine@redhat.com>
This commit is contained in:
parent
1e0e535b02
commit
87502a35ae
@ -27,93 +27,45 @@
|
||||
#include "virfile.h"
|
||||
#include "virstring.h"
|
||||
#include "virnetdev.h"
|
||||
#include "virnetlink.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||
|
||||
VIR_LOG_INIT("util.netdevveth");
|
||||
|
||||
|
||||
/**
|
||||
* virNetDevVethCreate:
|
||||
* @veth1: pointer to name for parent end of veth pair
|
||||
* @veth2: pointer to return name for container end of veth pair
|
||||
*
|
||||
* Creates a veth device pair using the ip command:
|
||||
* ip link add veth1 type veth peer name veth2
|
||||
* If veth1 points to NULL on entry, it will be a valid interface on
|
||||
* return. veth2 should point to NULL on entry.
|
||||
*
|
||||
* 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 allocates names
|
||||
* prior to using the ip command, and returns any allocated names
|
||||
* to the caller.
|
||||
*
|
||||
* Returns 0 on success or -1 in case of error
|
||||
*/
|
||||
int virNetDevVethCreate(char** veth1, char** veth2)
|
||||
#if defined(WITH_LIBNL)
|
||||
static int
|
||||
virNetDevVethCreateInternal(const char *veth1, const char *veth2)
|
||||
{
|
||||
int status;
|
||||
g_autofree char *veth1auto = NULL;
|
||||
g_autofree char *veth2auto = NULL;
|
||||
g_autoptr(virCommand) cmd = NULL;
|
||||
int status; /* Just ignore it */
|
||||
virNetlinkNewLinkData data = { .veth_peer = veth2 };
|
||||
|
||||
if (virNetDevGenerateName(&veth1auto, VIR_NET_DEV_GEN_NAME_VNET) < 0)
|
||||
return -1;
|
||||
|
||||
if (virNetDevGenerateName(&veth2auto, VIR_NET_DEV_GEN_NAME_VNET) < 0)
|
||||
return -1;
|
||||
|
||||
cmd = virCommandNew("ip");
|
||||
virCommandAddArgList(cmd, "link", "add",
|
||||
*veth1 ? *veth1 : veth1auto,
|
||||
"type", "veth", "peer", "name",
|
||||
*veth2 ? *veth2 : veth2auto,
|
||||
NULL);
|
||||
|
||||
if (virCommandRun(cmd, &status) < 0 || status) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("Failed to allocate free veth pair"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
VIR_DEBUG("create veth host: %s guest: %s: %d",
|
||||
*veth1 ? *veth1 : veth1auto,
|
||||
*veth2 ? *veth2 : veth2auto,
|
||||
status);
|
||||
|
||||
if (veth1auto)
|
||||
*veth1 = g_steal_pointer(&veth1auto);
|
||||
if (veth2auto)
|
||||
*veth2 = g_steal_pointer(&veth2auto);
|
||||
|
||||
VIR_DEBUG("Create Host: %s guest: %s", *veth1, *veth2);
|
||||
return 0;
|
||||
return virNetlinkNewLink(veth1, "veth", &data, &status);
|
||||
}
|
||||
|
||||
/**
|
||||
* virNetDevVethDelete:
|
||||
* @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 virNetDevVethDelete(const char *veth)
|
||||
static int
|
||||
virNetDevVethDeleteInternal(const char *veth)
|
||||
{
|
||||
return virNetlinkDelLink(veth, NULL);
|
||||
}
|
||||
#else
|
||||
static int
|
||||
virNetDevVethCreateInternal(const char *veth1, const char *veth2)
|
||||
{
|
||||
g_autoptr(virCommand) cmd = virCommandNew("ip");
|
||||
virCommandAddArgList(cmd, "link", "add", veth1, "type", "veth",
|
||||
"peer", "name", veth2, NULL);
|
||||
|
||||
return virCommandRun(cmd, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
virNetDevVethDeleteInternal(const char *veth)
|
||||
{
|
||||
int status;
|
||||
g_autoptr(virCommand) cmd = virCommandNewArgList("ip", "link",
|
||||
"del", veth, NULL);
|
||||
"del", veth, NULL);
|
||||
|
||||
if (virCommandRun(cmd, &status) < 0)
|
||||
return -1;
|
||||
@ -130,3 +82,69 @@ int virNetDevVethDelete(const char *veth)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_LIBNL */
|
||||
|
||||
/**
|
||||
* virNetDevVethCreate:
|
||||
* @veth1: pointer to name for one end of veth pair
|
||||
* @veth2: pointer to name for another end of veth pair
|
||||
*
|
||||
* Creates a veth device pair.
|
||||
*
|
||||
* 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 allocates names
|
||||
* prior to using the ip command, and returns any allocated names
|
||||
* to the caller.
|
||||
*
|
||||
* Returns 0 on success or -1 in case of error
|
||||
*/
|
||||
int virNetDevVethCreate(char **veth1, char **veth2)
|
||||
{
|
||||
const char *orig1 = *veth1;
|
||||
const char *orig2 = *veth2;
|
||||
|
||||
if (virNetDevGenerateName(veth1, VIR_NET_DEV_GEN_NAME_VNET) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virNetDevGenerateName(veth2, VIR_NET_DEV_GEN_NAME_VNET) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virNetDevVethCreateInternal(*veth1, *veth2) < 0)
|
||||
goto cleanup;
|
||||
|
||||
VIR_DEBUG("Create Host: %s guest: %s", *veth1, *veth2);
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
if (orig1 == NULL)
|
||||
VIR_FREE(*veth1);
|
||||
|
||||
if (orig2 == NULL)
|
||||
VIR_FREE(*veth2);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* virNetDevVethDelete:
|
||||
* @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 virNetDevVethDelete(const char *veth)
|
||||
{
|
||||
return virNetDevVethDeleteInternal(veth);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user