提交 c0d74ed4 编写于 作者: D Daniel P. Berrange

Support networking in UML driver

上级 7cce4768
Wed Jun 3 12:03:52 BST 2009 Daniel P. Berrange <berrange@redhat.com>
Support networking in UML driver
* src/bridge.c: Add new brDeleteTap function. Allow brAddTap
to create a persistent tap devices.
* src/bridge.h, src/libvirt_bridge.syms: Add brDeleteTap
* src/domain_conf.c: Fix missing 'break' in network XML formatter
* src/uml_conf.c, src/uml_conf.h, src/uml_driver.c: Add support
for bridge, network, mcast and user mode network interfaces
Wed Jun 3 11:53:52 BST 2009 Daniel P. Berrange <berrange@redhat.com>
Misc User Mode Linux startup/shutdown bugs
......
......@@ -451,8 +451,11 @@ brProbeVnetHdr(int tapfd)
*
* This function creates a new tap device on a bridge. @ifname can be either
* a fixed name or a name template with '%d' for dynamic name allocation.
* in either case the final name for the bridge will be stored in @ifname
* and the associated file descriptor in @tapfd.
* in either case the final name for the bridge will be stored in @ifname.
* If the @tapfd parameter is supplied, the open tap device file
* descriptor will be returned, otherwise the TAP device will be made
* persistent and closed. The caller must use brDeleteTap to remove
* a persistent TAP devices when it is no longer needed.
*
* Returns 0 in case of success or an errno code in case of failure.
*/
......@@ -465,7 +468,7 @@ brAddTap(brControl *ctl,
{
int id, subst, fd;
if (!ctl || !ctl->fd || !bridge || !ifname || !tapfd)
if (!ctl || !ctl->fd || !bridge || !ifname)
return EINVAL;
subst = id = 0;
......@@ -520,10 +523,14 @@ brAddTap(brControl *ctl,
goto error;
if ((errno = brSetInterfaceUp(ctl, try.ifr_name, 1)))
goto error;
if (!tapfd &&
(errno = ioctl(fd, TUNSETPERSIST, 1)))
goto error;
VIR_FREE(*ifname);
if (!(*ifname = strdup(try.ifr_name)))
goto error;
*tapfd = fd;
if (tapfd)
*tapfd = fd;
return 0;
}
......@@ -536,6 +543,43 @@ brAddTap(brControl *ctl,
return errno;
}
int brDeleteTap(brControl *ctl,
const char *ifname)
{
struct ifreq try;
int len;
int fd;
if (!ctl || !ctl->fd || !ifname)
return EINVAL;
if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
return errno;
memset(&try, 0, sizeof(struct ifreq));
try.ifr_flags = IFF_TAP|IFF_NO_PI;
len = strlen(ifname);
if (len >= BR_IFNAME_MAXLEN - 1) {
errno = EINVAL;
goto error;
}
strncpy(try.ifr_name, ifname, len);
try.ifr_name[len] = '\0';
if (ioctl(fd, TUNSETIFF, &try) == 0) {
if ((errno = ioctl(fd, TUNSETPERSIST, 0)))
goto error;
}
error:
close(fd);
return errno;
}
/**
* brSetInterfaceUp:
* @ctl: bridge control pointer
......
......@@ -60,12 +60,20 @@ int brDeleteInterface (brControl *ctl,
const char *bridge,
const char *iface);
enum {
BR_TAP_VNET_HDR = (1 << 0),
BR_TAP_PERSIST = (1 << 1),
};
int brAddTap (brControl *ctl,
const char *bridge,
char **ifname,
int vnet_hdr,
int features,
int *tapfd);
int brDeleteTap (brControl *ctl,
const char *ifname);
int brSetInterfaceUp (brControl *ctl,
const char *ifname,
int up);
......
......@@ -3146,6 +3146,7 @@ virDomainNetDefFormat(virConnectPtr conn,
else
virBufferVSprintf(buf, " <source port='%d'/>\n",
def->data.socket.port);
break;
case VIR_DOMAIN_NET_TYPE_INTERNAL:
virBufferEscapeString(buf, " <source name='%s'/>\n",
......
......@@ -8,6 +8,7 @@
brAddBridge;
brAddInterface;
brAddTap;
brDeleteTap;
brDeleteBridge;
brHasBridge;
brInit;
......
......@@ -44,6 +44,7 @@
#include "memory.h"
#include "nodeinfo.h"
#include "verify.h"
#include "bridge.h"
#define VIR_FROM_THIS VIR_FROM_UML
......@@ -91,6 +92,172 @@ virCapsPtr umlCapsInit(void) {
}
static int
umlConnectTapDevice(virConnectPtr conn,
virDomainNetDefPtr net,
const char *bridge)
{
int tapfd = -1;
int err;
brControl *brctl = NULL;
if (!net->ifname ||
STRPREFIX(net->ifname, "vnet") ||
strchr(net->ifname, '%')) {
VIR_FREE(net->ifname);
if (!(net->ifname = strdup("vnet%d")))
goto no_memory;
}
if ((err = brInit(&brctl))) {
char ebuf[1024];
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("cannot initialize bridge support: %s"),
virStrerror(err, ebuf, sizeof ebuf));
goto error;
}
if ((err = brAddTap(brctl, bridge,
&net->ifname, BR_TAP_PERSIST, &tapfd))) {
if (errno == ENOTSUP) {
/* In this particular case, give a better diagnostic. */
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("Failed to add tap interface to bridge. "
"%s is not a bridge device"), bridge);
} else {
char ebuf[1024];
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("Failed to add tap interface '%s' "
"to bridge '%s' : %s"),
net->ifname, bridge, virStrerror(err, ebuf, sizeof ebuf));
}
goto error;
}
close(tapfd);
brShutdown(brctl);
return 0;
no_memory:
virReportOOMError(conn);
error:
brShutdown(brctl);
return -1;
}
static char *
umlBuildCommandLineNet(virConnectPtr conn,
virDomainNetDefPtr def,
int idx)
{
char *ret;
virBuffer buf = VIR_BUFFER_INITIALIZER;
/* General format: ethNN=type,options */
virBufferVSprintf(&buf, "eth%d=", idx);
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_USER:
/* ethNNN=slirp,macaddr */
virBufferAddLit(&buf, "slirp");
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
/* ethNNN=tuntap,tapname,macaddr,gateway */
virBufferAddLit(&buf, "tuntap");
if (def->data.ethernet.ipaddr) {
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
_("IP address not supported for ethernet inteface"));
goto error;
}
if (def->data.ethernet.script) {
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
_("script execution not supported for ethernet inteface"));
goto error;
}
break;
case VIR_DOMAIN_NET_TYPE_SERVER:
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
_("TCP server networking type not supported"));
goto error;
case VIR_DOMAIN_NET_TYPE_CLIENT:
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
_("TCP client networking type not supported"));
goto error;
case VIR_DOMAIN_NET_TYPE_MCAST:
/* ethNNN=tuntap,macaddr,ipaddr,port */
virBufferAddLit(&buf, "mcast");
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:
{
char *bridge;
virNetworkPtr network = virNetworkLookupByName(conn,
def->data.network.name);
if (!network) {
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("Network '%s' not found"),
def->data.network.name);
goto error;
}
bridge = virNetworkGetBridgeName(network);
virNetworkFree(network);
if (bridge == NULL) {
goto error;
}
if (umlConnectTapDevice(conn, def, bridge) < 0) {
VIR_FREE(bridge);
goto error;
}
/* ethNNN=tuntap,tapname,macaddr,gateway */
virBufferVSprintf(&buf, "tuntap,%s", def->ifname);
break;
}
case VIR_DOMAIN_NET_TYPE_BRIDGE:
if (umlConnectTapDevice(conn, def, def->data.bridge.brname) < 0)
goto error;
/* ethNNN=tuntap,tapname,macaddr,gateway */
virBufferVSprintf(&buf, "tuntap,%s", def->ifname);
break;
case VIR_DOMAIN_NET_TYPE_INTERNAL:
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
_("internal networking type not supported"));
goto error;
}
virBufferVSprintf(&buf, ",%02x:%02x:%02x:%02x:%02x:%02x",
def->mac[0], def->mac[1], def->mac[2],
def->mac[3], def->mac[4], def->mac[5]);
if (def->type == VIR_DOMAIN_NET_TYPE_MCAST) {
virBufferVSprintf(&buf, ",%s,%d",
def->data.socket.address,
def->data.socket.port);
}
if (virBufferError(&buf)) {
virReportOOMError(conn);
return NULL;
}
return virBufferContentAndReset(&buf);
error:
ret = virBufferContentAndReset(&buf);
VIR_FREE(ret);
return NULL;
}
static char *
umlBuildCommandLineChr(virConnectPtr conn,
virDomainChrDefPtr def,
......@@ -166,9 +333,8 @@ int umlBuildCommandLine(virConnectPtr conn,
struct uml_driver *driver ATTRIBUTE_UNUSED,
virDomainObjPtr vm,
const char ***retargv,
const char ***retenv,
int **tapfds,
int *ntapfds) {
const char ***retenv)
{
int i, j;
char memory[50];
struct utsname ut;
......@@ -277,6 +443,13 @@ int umlBuildCommandLine(virConnectPtr conn,
ADD_ARG_PAIR(disk->dst, disk->src);
}
for (i = 0 ; i < vm->def->nnets ; i++) {
char *ret = umlBuildCommandLineNet(conn, vm->def->nets[i], i);
if (!ret)
goto error;
ADD_ARG(ret);
}
for (i = 0 ; i < UML_MAX_CHAR_DEVICE ; i++) {
char *ret;
if (i == 0 && vm->def->console)
......@@ -311,13 +484,7 @@ int umlBuildCommandLine(virConnectPtr conn,
no_memory:
virReportOOMError(conn);
error:
if (tapfds &&
*tapfds) {
for (i = 0; i < *ntapfds; i++)
close((*tapfds)[i]);
VIR_FREE(*tapfds);
*ntapfds = 0;
}
if (qargv) {
for (i = 0 ; i < qargc ; i++)
VIR_FREE((qargv)[i]);
......
......@@ -70,8 +70,6 @@ int umlBuildCommandLine (virConnectPtr conn,
struct uml_driver *driver,
virDomainObjPtr dom,
const char ***retargv,
const char ***retenv,
int **tapfds,
int *ntapfds);
const char ***retenv);
#endif /* __UML_CONF_H */
......@@ -722,6 +722,35 @@ error:
}
static int umlCleanupTapDevices(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainObjPtr vm) {
int i;
int err;
int ret = 0;
brControl *brctl = NULL;
VIR_ERROR0("Cleanup tap");
if (brInit(&brctl) < 0)
return -1;
for (i = 0 ; i < vm->def->nnets ; i++) {
virDomainNetDefPtr def = vm->def->nets[i];
if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
def->type != VIR_DOMAIN_NET_TYPE_NETWORK)
continue;
VIR_ERROR("Cleanup '%s'", def->ifname);
err = brDeleteTap(brctl, def->ifname);
if (err) {
VIR_ERROR("Cleanup failed %d", err);
ret = -1;
}
}
VIR_ERROR0("Cleanup tap done");
brShutdown(brctl);
return ret;
}
static int umlStartVMDaemon(virConnectPtr conn,
struct uml_driver *driver,
virDomainObjPtr vm) {
......@@ -732,8 +761,6 @@ static int umlStartVMDaemon(virConnectPtr conn,
char *logfile;
int logfd = -1;
struct stat sb;
int *tapfds = NULL;
int ntapfds = 0;
fd_set keepfd;
char ebuf[1024];
......@@ -792,9 +819,9 @@ static int umlStartVMDaemon(virConnectPtr conn,
}
if (umlBuildCommandLine(conn, driver, vm,
&argv, &progenv,
&tapfds, &ntapfds) < 0) {
&argv, &progenv) < 0) {
close(logfd);
umlCleanupTapDevices(conn, vm);
return -1;
}
......@@ -824,9 +851,6 @@ static int umlStartVMDaemon(virConnectPtr conn,
vm->monitor = -1;
for (i = 0 ; i < ntapfds ; i++)
FD_SET(tapfds[i], &keepfd);
ret = virExecDaemonize(conn, argv, progenv, &keepfd, &pid,
-1, &logfd, &logfd,
0, NULL, NULL, NULL);
......@@ -840,15 +864,14 @@ static int umlStartVMDaemon(virConnectPtr conn,
VIR_FREE(progenv[i]);
VIR_FREE(progenv);
if (tapfds) {
for (i = 0 ; i < ntapfds ; i++) {
close(tapfds[i]);
}
VIR_FREE(tapfds);
}
if (ret < 0)
umlCleanupTapDevices(conn, vm);
/* NB we don't mark it running here - we do that async
with inotify */
/* XXX what if someone else tries to start it again
before we get the inotification ? Sounds like
trouble.... */
return ret;
}
......@@ -879,6 +902,8 @@ static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
VIR_FREE(vm->vcpupids);
vm->nvcpupids = 0;
umlCleanupTapDevices(conn, vm);
if (vm->newDef) {
virDomainDefFree(vm->def);
vm->def = vm->newDef;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册