mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
autocreate tap device for ethernet network type
If a user specify network type ethernet, then create it via libvirt and run script if it provided. After this commit user does not need to run external script to create tap device or add root permissions to qemu process. Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
This commit is contained in:
parent
ee07c9802b
commit
9c17d665fd
@ -3220,6 +3220,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
|
|||||||
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
||||||
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
||||||
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
||||||
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
||||||
virBufferAsprintf(&buf, "tap%c", type_sep);
|
virBufferAsprintf(&buf, "tap%c", type_sep);
|
||||||
/* for one tapfd 'fd=' shall be used,
|
/* for one tapfd 'fd=' shall be used,
|
||||||
* for more than one 'fds=' is the right choice */
|
* for more than one 'fds=' is the right choice */
|
||||||
@ -3237,20 +3238,6 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
|
|||||||
is_tap = true;
|
is_tap = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
|
||||||
virBufferAddLit(&buf, "tap");
|
|
||||||
if (net->ifname) {
|
|
||||||
virBufferAsprintf(&buf, "%cifname=%s", type_sep, net->ifname);
|
|
||||||
type_sep = ',';
|
|
||||||
}
|
|
||||||
if (net->script) {
|
|
||||||
virBufferAsprintf(&buf, "%cscript=%s", type_sep,
|
|
||||||
net->script);
|
|
||||||
type_sep = ',';
|
|
||||||
}
|
|
||||||
is_tap = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
||||||
virBufferAsprintf(&buf, "socket%cconnect=%s:%d",
|
virBufferAsprintf(&buf, "socket%cconnect=%s:%d",
|
||||||
type_sep,
|
type_sep,
|
||||||
@ -7792,7 +7779,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
|
|||||||
if (net->driver.virtio.queues > 0 &&
|
if (net->driver.virtio.queues > 0 &&
|
||||||
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
||||||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
||||||
actualType == VIR_DOMAIN_NET_TYPE_DIRECT)) {
|
actualType == VIR_DOMAIN_NET_TYPE_DIRECT ||
|
||||||
|
actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("Multiqueue network is not supported for: %s"),
|
_("Multiqueue network is not supported for: %s"),
|
||||||
virDomainNetTypeToString(actualType));
|
virDomainNetTypeToString(actualType));
|
||||||
@ -7802,7 +7790,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
|
|||||||
/* and only TAP devices support nwfilter rules */
|
/* and only TAP devices support nwfilter rules */
|
||||||
if (net->filter &&
|
if (net->filter &&
|
||||||
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
||||||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
||||||
|
actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("filterref is not supported for "
|
_("filterref is not supported for "
|
||||||
"network interfaces of type %s"),
|
"network interfaces of type %s"),
|
||||||
@ -7812,7 +7801,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
|
|||||||
|
|
||||||
if (net->backend.tap &&
|
if (net->backend.tap &&
|
||||||
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
||||||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
||||||
|
actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("Custom tap device path is not supported for: %s"),
|
_("Custom tap device path is not supported for: %s"),
|
||||||
virDomainNetTypeToString(actualType));
|
virDomainNetTypeToString(actualType));
|
||||||
@ -7850,6 +7840,20 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
|
|||||||
if (qemuInterfaceDirectConnect(def, driver, net,
|
if (qemuInterfaceDirectConnect(def, driver, net,
|
||||||
tapfd, tapfdSize, vmop) < 0)
|
tapfd, tapfdSize, vmop) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
} else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {
|
||||||
|
tapfdSize = net->driver.virtio.queues;
|
||||||
|
if (!tapfdSize)
|
||||||
|
tapfdSize = 1;
|
||||||
|
|
||||||
|
if (VIR_ALLOC_N(tapfd, tapfdSize) < 0 ||
|
||||||
|
VIR_ALLOC_N(tapfdName, tapfdSize) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
memset(tapfd, -1, tapfdSize * sizeof(tapfd[0]));
|
||||||
|
|
||||||
|
if (qemuInterfaceEthernetConnect(def, driver, net,
|
||||||
|
tapfd, tapfdSize) < 0)
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For types whose implementations use a netdev on the host, add
|
/* For types whose implementations use a netdev on the host, add
|
||||||
|
@ -895,7 +895,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
|
|||||||
if (net->driver.virtio.queues > 0 &&
|
if (net->driver.virtio.queues > 0 &&
|
||||||
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
||||||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
||||||
actualType == VIR_DOMAIN_NET_TYPE_DIRECT)) {
|
actualType == VIR_DOMAIN_NET_TYPE_DIRECT ||
|
||||||
|
actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("Multiqueue network is not supported for: %s"),
|
_("Multiqueue network is not supported for: %s"),
|
||||||
virDomainNetTypeToString(actualType));
|
virDomainNetTypeToString(actualType));
|
||||||
@ -905,7 +906,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
|
|||||||
/* and only TAP devices support nwfilter rules */
|
/* and only TAP devices support nwfilter rules */
|
||||||
if (net->filter &&
|
if (net->filter &&
|
||||||
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
||||||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
||||||
|
actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("filterref is not supported for "
|
_("filterref is not supported for "
|
||||||
"network interfaces of type %s"),
|
"network interfaces of type %s"),
|
||||||
@ -950,10 +952,19 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
|
|||||||
vhostfd, &vhostfdSize) < 0)
|
vhostfd, &vhostfdSize) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {
|
} else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {
|
||||||
vhostfdSize = 1;
|
tapfdSize = vhostfdSize = net->driver.virtio.queues;
|
||||||
if (VIR_ALLOC(vhostfd) < 0)
|
if (!tapfdSize)
|
||||||
|
tapfdSize = vhostfdSize = 1;
|
||||||
|
if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
*vhostfd = -1;
|
memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
|
||||||
|
if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
|
||||||
|
if (qemuInterfaceEthernetConnect(vm->def, driver, net,
|
||||||
|
tapfd, tapfdSize) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
iface_connected = true;
|
||||||
if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps,
|
if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps,
|
||||||
vhostfd, &vhostfdSize) < 0)
|
vhostfd, &vhostfdSize) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -2204,6 +2215,21 @@ int qemuDomainChangeNetLinkState(virQEMUDriverPtr driver,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
if (virDomainNetGetActualType(dev) == VIR_DOMAIN_NET_TYPE_ETHERNET) {
|
||||||
|
switch (linkstate) {
|
||||||
|
case VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP:
|
||||||
|
case VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DEFAULT:
|
||||||
|
if ((ret = virNetDevSetOnline(dev->ifname, true)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN:
|
||||||
|
if ((ret = virNetDevSetOnline(dev->ifname, false)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* modify the device configuration */
|
/* modify the device configuration */
|
||||||
dev->linkstate = linkstate;
|
dev->linkstate = linkstate;
|
||||||
|
|
||||||
|
@ -387,6 +387,124 @@ qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg,
|
|||||||
return *tapfd < 0 ? -1 : 0;
|
return *tapfd < 0 ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qemuExecuteEthernetScript:
|
||||||
|
* @ifname: the interface name
|
||||||
|
* @script: the script name
|
||||||
|
*
|
||||||
|
* This function executes script for new tap device created by libvirt.
|
||||||
|
* Returns 0 in case of success or -1 on failure
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
qemuExecuteEthernetScript(const char *ifname, const char *script)
|
||||||
|
{
|
||||||
|
virCommandPtr cmd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cmd = virCommandNew(script);
|
||||||
|
virCommandAddArgFormat(cmd, "%s", ifname);
|
||||||
|
virCommandClearCaps(cmd);
|
||||||
|
#ifdef CAP_NET_ADMIN
|
||||||
|
virCommandAllowCap(cmd, CAP_NET_ADMIN);
|
||||||
|
#endif
|
||||||
|
virCommandAddEnvPassCommon(cmd);
|
||||||
|
|
||||||
|
ret = virCommandRun(cmd, NULL);
|
||||||
|
|
||||||
|
virCommandFree(cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qemuInterfaceEthernetConnect:
|
||||||
|
* @def: the definition of the VM
|
||||||
|
* @driver: qemu driver data
|
||||||
|
* @net: pointer to the VM's interface description
|
||||||
|
* @tapfd: array of file descriptor return value for the new device
|
||||||
|
* @tapfdsize: number of file descriptors in @tapfd
|
||||||
|
*
|
||||||
|
* Called *only* called if actualType is VIR_DOMAIN_NET_TYPE_ETHERNET
|
||||||
|
* (i.e. if the connection is made with a tap device)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
qemuInterfaceEthernetConnect(virDomainDefPtr def,
|
||||||
|
virQEMUDriverPtr driver,
|
||||||
|
virDomainNetDefPtr net,
|
||||||
|
int *tapfd,
|
||||||
|
size_t tapfdSize)
|
||||||
|
{
|
||||||
|
virMacAddr tapmac;
|
||||||
|
int ret = -1;
|
||||||
|
unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP;
|
||||||
|
bool template_ifname = false;
|
||||||
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
||||||
|
const char *tunpath = "/dev/net/tun";
|
||||||
|
|
||||||
|
if (net->backend.tap) {
|
||||||
|
tunpath = net->backend.tap;
|
||||||
|
if (!virQEMUDriverIsPrivileged(driver)) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("cannot use custom tap device in session mode"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!net->ifname ||
|
||||||
|
STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
|
||||||
|
strchr(net->ifname, '%')) {
|
||||||
|
VIR_FREE(net->ifname);
|
||||||
|
if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_PREFIX "%d") < 0)
|
||||||
|
goto cleanup;
|
||||||
|
/* avoid exposing vnet%d in getXMLDesc or error outputs */
|
||||||
|
template_ifname = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net->model && STREQ(net->model, "virtio"))
|
||||||
|
tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
|
||||||
|
|
||||||
|
if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize,
|
||||||
|
tap_create_flags) < 0) {
|
||||||
|
virDomainAuditNetDevice(def, net, tunpath, false);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
virDomainAuditNetDevice(def, net, tunpath, true);
|
||||||
|
virMacAddrSet(&tapmac, &net->mac);
|
||||||
|
tapmac.addr[0] = 0xFE;
|
||||||
|
|
||||||
|
if (virNetDevSetMAC(net->ifname, &tapmac) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (net->script &&
|
||||||
|
qemuExecuteEthernetScript(net->ifname, net->script) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (cfg->macFilter &&
|
||||||
|
ebtablesAddForwardAllowIn(driver->ebtables,
|
||||||
|
net->ifname,
|
||||||
|
&net->mac) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (net->filter &&
|
||||||
|
virDomainConfNWFilterInstantiate(def->uuid, net) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (ret < 0) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < tapfdSize && tapfd[i] >= 0; i++)
|
||||||
|
VIR_FORCE_CLOSE(tapfd[i]);
|
||||||
|
if (template_ifname)
|
||||||
|
VIR_FREE(net->ifname);
|
||||||
|
}
|
||||||
|
virObjectUnref(cfg);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* qemuInterfaceBridgeConnect:
|
/* qemuInterfaceBridgeConnect:
|
||||||
* @def: the definition of the VM
|
* @def: the definition of the VM
|
||||||
* @driver: qemu driver data
|
* @driver: qemu driver data
|
||||||
|
@ -40,6 +40,11 @@ int qemuInterfaceDirectConnect(virDomainDefPtr def,
|
|||||||
int *tapfd,
|
int *tapfd,
|
||||||
size_t tapfdSize,
|
size_t tapfdSize,
|
||||||
virNetDevVPortProfileOp vmop);
|
virNetDevVPortProfileOp vmop);
|
||||||
|
int qemuInterfaceEthernetConnect(virDomainDefPtr def,
|
||||||
|
virQEMUDriverPtr driver,
|
||||||
|
virDomainNetDefPtr net,
|
||||||
|
int *tapfd,
|
||||||
|
size_t tapfdSize);
|
||||||
|
|
||||||
int qemuInterfaceBridgeConnect(virDomainDefPtr def,
|
int qemuInterfaceBridgeConnect(virDomainDefPtr def,
|
||||||
virQEMUDriverPtr driver,
|
virQEMUDriverPtr driver,
|
||||||
|
@ -5847,6 +5847,12 @@ void qemuProcessStop(virQEMUDriverPtr driver,
|
|||||||
virDomainNetGetActualVirtPortProfile(net),
|
virDomainNetGetActualVirtPortProfile(net),
|
||||||
cfg->stateDir));
|
cfg->stateDir));
|
||||||
break;
|
break;
|
||||||
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
||||||
|
if (net->ifname) {
|
||||||
|
ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap));
|
||||||
|
VIR_FREE(net->ifname);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
||||||
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
||||||
#ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP
|
#ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP
|
||||||
|
Loading…
Reference in New Issue
Block a user