Move virBhyveTapGetRealDeviceName to virnetdevtap

To ease mocking for bhyve unit tests move virBhyveTapGetRealDeviceName()
out of bhyve_command.c to virnetdevtap and rename it to
virNetDevTapGetRealDeviceName().
This commit is contained in:
Roman Bogorodskiy 2014-03-26 20:53:48 +04:00
parent 6612d1adb7
commit a1bd8d2546
4 changed files with 90 additions and 73 deletions

View File

@ -21,10 +21,7 @@
#include <config.h>
#include <fcntl.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_tap.h>
@ -41,75 +38,6 @@
VIR_LOG_INIT("bhyve.bhyve_command");
static char*
virBhyveTapGetRealDeviceName(char *name)
{
/* This is an ugly hack, because if we rename
* tap device to vnet%d, its device name will be
* still /dev/tap%d, and bhyve tries to open /dev/tap%d,
* so we have to find the real name
*/
char *ret = NULL;
struct dirent *dp;
char *devpath = NULL;
int fd;
DIR *dirp = opendir("/dev");
if (dirp == NULL) {
virReportSystemError(errno,
_("Failed to opendir path '%s'"),
"/dev");
return NULL;
}
while ((dp = readdir(dirp)) != NULL) {
if (STRPREFIX(dp->d_name, "tap")) {
struct ifreq ifr;
if (virAsprintf(&devpath, "/dev/%s", dp->d_name) < 0) {
goto cleanup;
}
if ((fd = open(devpath, O_RDWR)) < 0) {
if (errno == EBUSY) {
VIR_FREE(devpath);
continue;
}
virReportSystemError(errno, _("Unable to open '%s'"), devpath);
goto cleanup;
}
if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) {
virReportSystemError(errno, "%s",
_("Unable to query tap interface name"));
goto cleanup;
}
if (STREQ(name, ifr.ifr_name)) {
/* we can ignore the return value
* because we still have nothing
* to do but return;
*/
ignore_value(VIR_STRDUP(ret, dp->d_name));
goto cleanup;
}
VIR_FREE(devpath);
VIR_FORCE_CLOSE(fd);
}
errno = 0;
}
if (errno != 0)
virReportSystemError(errno, "%s",
_("Unable to iterate over TAP devices"));
cleanup:
VIR_FREE(devpath);
VIR_FORCE_CLOSE(fd);
closedir(dirp);
return ret;
}
static int
bhyveBuildNetArgStr(const virDomainDef *def, virCommandPtr cmd)
{
@ -161,7 +89,7 @@ bhyveBuildNetArgStr(const virDomainDef *def, virCommandPtr cmd)
}
}
realifname = virBhyveTapGetRealDeviceName(net->ifname);
realifname = virNetDevTapGetRealDeviceName(net->ifname);
if (realifname == NULL) {
VIR_FREE(net->ifname);

View File

@ -1584,6 +1584,7 @@ virNetDevTapCreate;
virNetDevTapCreateInBridgePort;
virNetDevTapDelete;
virNetDevTapGetName;
virNetDevTapGetRealDeviceName;
# util/virnetdevveth.h

View File

@ -33,11 +33,15 @@
#include "virlog.h"
#include "virstring.h"
#include <dirent.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <fcntl.h>
#ifdef __linux__
# include <linux/if_tun.h> /* IFF_TUN, IFF_NO_PI */
#elif defined(__FreeBSD__)
# include <net/if_tap.h>
#endif
#define VIR_FROM_THIS VIR_FROM_NONE
@ -72,6 +76,87 @@ virNetDevTapGetName(int tapfd ATTRIBUTE_UNUSED, char **ifname ATTRIBUTE_UNUSED)
#endif
}
/**
* virNetDevTapGetRealDeviceName:
* @ifname: the interface name
*
* Lookup real interface name (i.e. name of the device entry in /dev),
* because e.g. on FreeBSD if we rename tap device to vnetN its device
* entry still remains unchanged (/dev/tapX), but bhyve needs a name
* that matches /dev entry.
*
* Returns the proper interface name or NULL if no corresponding interface
* found.
*/
char*
virNetDevTapGetRealDeviceName(char *ifname ATTRIBUTE_UNUSED)
{
#ifdef TAPGIFNAME
char *ret = NULL;
struct dirent *dp;
char *devpath = NULL;
int fd;
DIR *dirp = opendir("/dev");
if (dirp == NULL) {
virReportSystemError(errno,
_("Failed to opendir path '%s'"),
"/dev");
return NULL;
}
while ((dp = readdir(dirp)) != NULL) {
if (STRPREFIX(dp->d_name, "tap")) {
struct ifreq ifr;
if (virAsprintf(&devpath, "/dev/%s", dp->d_name) < 0) {
goto cleanup;
}
if ((fd = open(devpath, O_RDWR)) < 0) {
if (errno == EBUSY) {
VIR_FREE(devpath);
continue;
}
virReportSystemError(errno, _("Unable to open '%s'"), devpath);
goto cleanup;
}
if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) {
virReportSystemError(errno, "%s",
_("Unable to query tap interface name"));
goto cleanup;
}
if (STREQ(ifname, ifr.ifr_name)) {
/* we can ignore the return value
* because we still have nothing
* to do but return;
*/
ignore_value(VIR_STRDUP(ret, dp->d_name));
goto cleanup;
}
VIR_FREE(devpath);
VIR_FORCE_CLOSE(fd);
}
errno = 0;
}
if (errno != 0)
virReportSystemError(errno, "%s",
_("Unable to iterate over TAP devices"));
cleanup:
VIR_FREE(devpath);
VIR_FORCE_CLOSE(fd);
closedir(dirp);
return ret;
#else
return NULL;
#endif
}
/**
* virNetDevProbeVnetHdr:

View File

@ -45,6 +45,9 @@ int virNetDevTapDelete(const char *ifname)
int virNetDevTapGetName(int tapfd, char **ifname)
ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
char* virNetDevTapGetRealDeviceName(char *ifname)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
typedef enum {
VIR_NETDEV_TAP_CREATE_NONE = 0,
/* Bring the interface up */