<p dir="ltr">Ping...</p>
<div class="gmail_quote">27 февр. 2015 г. 16:30 пользователь "Vasiliy Tolstov" <<a href="mailto:v.tolstov@selfip.ru">v.tolstov@selfip.ru</a>> написал:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">If a user specify ehernet device create it via libvirt and run<br>
script if it provided. After this commit user does not need to<br>
run external script to create tap device or add root to qemu<br>
process.<br>
<br>
Signed-off-by: Vasiliy Tolstov <<a href="mailto:v.tolstov@selfip.ru">v.tolstov@selfip.ru</a>><br>
---<br>
src/qemu/qemu_command.c | 135 +++++++++++++++++++++++++++++-------------------<br>
src/qemu/qemu_hotplug.c | 13 ++---<br>
src/qemu/qemu_process.c | 6 +++<br>
3 files changed, 93 insertions(+), 61 deletions(-)<br>
<br>
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c<br>
index 24b2ad9..284a97c 100644<br>
--- a/src/qemu/qemu_command.c<br>
+++ b/src/qemu/qemu_command.c<br>
@@ -278,10 +278,41 @@ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg,<br>
return *tapfd < 0 ? -1 : 0;<br>
}<br>
<br>
+/**<br>
+ * qemuExecuteEthernetScript:<br>
+ * @ifname: the interface name<br>
+ * @script: the script name<br>
+ * This function executes script for new tap device created by libvirt.<br>
+ * Returns 0 in case of success or -1 on failure<br>
+ */<br>
+static int qemuExecuteEthernetScript(const char *ifname, const char *script)<br>
+{<br>
+ virCommandPtr cmd;<br>
+ int ret;<br>
+<br>
+ cmd = virCommandNew(script);<br>
+ virCommandAddArgFormat(cmd, "%s", ifname);<br>
+ virCommandClearCaps(cmd);<br>
+#ifdef CAP_NET_ADMIN<br>
+ virCommandAllowCap(cmd, CAP_NET_ADMIN);<br>
+#endif<br>
+ virCommandAddEnvPassCommon(cmd);<br>
+<br>
+ if (virCommandRun(cmd, NULL) < 0) {<br>
+ ret = -1;<br>
+ } else {<br>
+ ret = 0;<br>
+ }<br>
+<br>
+ virCommandFree(cmd);<br>
+ return ret;<br>
+}<br>
+<br>
/* qemuNetworkIfaceConnect - *only* called if actualType is<br>
- * VIR_DOMAIN_NET_TYPE_NETWORK or VIR_DOMAIN_NET_TYPE_BRIDGE (i.e. if<br>
- * the connection is made with a tap device connecting to a bridge<br>
- * device)<br>
+ * VIR_DOMAIN_NET_TYPE_NETWORK, VIR_DOMAIN_NET_TYPE_BRIDGE or<br>
+ * VIR_DOMAIN_NET_TYPE_ETHERNET (i.e. if the connection is<br>
+ * made with a tap device connecting to a bridge device or<br>
+ * used ethernet tap device)<br>
*/<br>
int<br>
qemuNetworkIfaceConnect(virDomainDefPtr def,<br>
@@ -307,11 +338,6 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,<br>
}<br>
}<br>
<br>
- if (!(brname = virDomainNetGetActualBridgeName(net))) {<br>
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));<br>
- goto cleanup;<br>
- }<br>
-<br>
if (!net->ifname ||<br>
STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||<br>
strchr(net->ifname, '%')) {<br>
@@ -327,45 +353,61 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,<br>
tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;<br>
}<br>
<br>
- if (cfg->privileged) {<br>
- if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,<br>
- def->uuid, tunpath, tapfd, *tapfdSize,<br>
- virDomainNetGetActualVirtPortProfile(net),<br>
- virDomainNetGetActualVlan(net),<br>
- tap_create_flags) < 0) {<br>
+ if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {<br>
+ if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, *tapfdSize,<br>
+ tap_create_flags) < 0) {<br>
virDomainAuditNetDevice(def, net, tunpath, false);<br>
goto cleanup;<br>
}<br>
- if (virDomainNetGetActualBridgeMACTableManager(net)<br>
- == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {<br>
- /* libvirt is managing the FDB of the bridge this device<br>
- * is attaching to, so we need to turn off learning and<br>
- * unicast_flood on the device to prevent the kernel from<br>
- * adding any FDB entries for it. We will add add an fdb<br>
- * entry ourselves (during qemuInterfaceStartDevices(),<br>
- * using the MAC address from the interface config.<br>
- */<br>
- if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)<br>
- goto cleanup;<br>
- if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0)<br>
+ if (net->script) {<br>
+ if (qemuExecuteEthernetScript(net->ifname, net->script) < 0)<br>
goto cleanup;<br>
}<br>
} else {<br>
- if (qemuCreateInBridgePortWithHelper(cfg, brname,<br>
- &net->ifname,<br>
- tapfd, tap_create_flags) < 0) {<br>
- virDomainAuditNetDevice(def, net, tunpath, false);<br>
+ if (!(brname = virDomainNetGetActualBridgeName(net))) {<br>
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));<br>
goto cleanup;<br>
}<br>
- /* qemuCreateInBridgePortWithHelper can only create a single FD */<br>
- if (*tapfdSize > 1) {<br>
- VIR_WARN("Ignoring multiqueue network request");<br>
- *tapfdSize = 1;<br>
+<br>
+ if (cfg->privileged) {<br>
+ if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,<br>
+ def->uuid, tunpath, tapfd, *tapfdSize,<br>
+ virDomainNetGetActualVirtPortProfile(net),<br>
+ virDomainNetGetActualVlan(net),<br>
+ tap_create_flags) < 0) {<br>
+ virDomainAuditNetDevice(def, net, tunpath, false);<br>
+ goto cleanup;<br>
+ }<br>
+ if (virDomainNetGetActualBridgeMACTableManager(net)<br>
+ == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {<br>
+ /* libvirt is managing the FDB of the bridge this device<br>
+ * is attaching to, so we need to turn off learning and<br>
+ * unicast_flood on the device to prevent the kernel from<br>
+ * adding any FDB entries for it. We will add add an fdb<br>
+ * entry ourselves (during qemuInterfaceStartDevices(),<br>
+ * using the MAC address from the interface config.<br>
+ */<br>
+ if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)<br>
+ goto cleanup;<br>
+ if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0)<br>
+ goto cleanup;<br>
+ }<br>
+ } else {<br>
+ if (qemuCreateInBridgePortWithHelper(cfg, brname,<br>
+ &net->ifname,<br>
+ tapfd, tap_create_flags) < 0) {<br>
+ virDomainAuditNetDevice(def, net, tunpath, false);<br>
+ goto cleanup;<br>
+ }<br>
+ /* qemuCreateInBridgePortWithHelper can only create a single FD */<br>
+ if (*tapfdSize > 1) {<br>
+ VIR_WARN("Ignoring multiqueue network request");<br>
+ *tapfdSize = 1;<br>
+ }<br>
}<br>
+ virDomainAuditNetDevice(def, net, tunpath, true);<br>
}<br>
<br>
- virDomainAuditNetDevice(def, net, tunpath, true);<br>
-<br>
if (cfg->macFilter &&<br>
ebtablesAddForwardAllowIn(driver->ebtables,<br>
net->ifname,<br>
@@ -4959,6 +5001,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,<br>
case VIR_DOMAIN_NET_TYPE_BRIDGE:<br>
case VIR_DOMAIN_NET_TYPE_NETWORK:<br>
case VIR_DOMAIN_NET_TYPE_DIRECT:<br>
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:<br>
virBufferAsprintf(&buf, "tap%c", type_sep);<br>
/* for one tapfd 'fd=' shall be used,<br>
* for more than one 'fds=' is the right choice */<br>
@@ -4976,20 +5019,6 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,<br>
is_tap = true;<br>
break;<br>
<br>
- case VIR_DOMAIN_NET_TYPE_ETHERNET:<br>
- virBufferAddLit(&buf, "tap");<br>
- if (net->ifname) {<br>
- virBufferAsprintf(&buf, "%cifname=%s", type_sep, net->ifname);<br>
- type_sep = ',';<br>
- }<br>
- if (net->script) {<br>
- virBufferAsprintf(&buf, "%cscript=%s", type_sep,<br>
- net->script);<br>
- type_sep = ',';<br>
- }<br>
- is_tap = true;<br>
- break;<br>
-<br>
case VIR_DOMAIN_NET_TYPE_CLIENT:<br>
virBufferAsprintf(&buf, "socket%cconnect=%s:%d",<br>
type_sep,<br>
@@ -7785,7 +7814,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,<br>
/* Currently nothing besides TAP devices supports multiqueue. */<br>
if (net->driver.virtio.queues > 0 &&<br>
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||<br>
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {<br>
+ actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||<br>
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {<br>
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,<br>
_("Multiqueue network is not supported for: %s"),<br>
virDomainNetTypeToString(actualType));<br>
@@ -7802,7 +7832,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,<br>
}<br>
<br>
if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||<br>
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {<br>
+ actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||<br>
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {<br>
tapfdSize = net->driver.virtio.queues;<br>
if (!tapfdSize)<br>
tapfdSize = 1;<br>
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c<br>
index 08047ce..c34486a 100644<br>
--- a/src/qemu/qemu_hotplug.c<br>
+++ b/src/qemu/qemu_hotplug.c<br>
@@ -896,7 +896,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,<br>
/* Currently nothing besides TAP devices supports multiqueue. */<br>
if (net->driver.virtio.queues > 0 &&<br>
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||<br>
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {<br>
+ actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||<br>
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {<br>
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,<br>
_("Multiqueue network is not supported for: %s"),<br>
virDomainNetTypeToString(actualType));<br>
@@ -904,7 +905,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,<br>
}<br>
<br>
if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||<br>
- actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {<br>
+ actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||<br>
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {<br>
tapfdSize = vhostfdSize = net->driver.virtio.queues;<br>
if (!tapfdSize)<br>
tapfdSize = vhostfdSize = 1;<br>
@@ -935,13 +937,6 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,<br>
iface_connected = true;<br>
if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)<br>
goto cleanup;<br>
- } else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {<br>
- vhostfdSize = 1;<br>
- if (VIR_ALLOC(vhostfd) < 0)<br>
- goto cleanup;<br>
- *vhostfd = -1;<br>
- if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)<br>
- goto cleanup;<br>
}<br>
<br>
/* Set device online immediately */<br>
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c<br>
index 515402e..468e509 100644<br>
--- a/src/qemu/qemu_process.c<br>
+++ b/src/qemu/qemu_process.c<br>
@@ -5288,6 +5288,12 @@ void qemuProcessStop(virQEMUDriverPtr driver,<br>
cfg->stateDir));<br>
VIR_FREE(net->ifname);<br>
break;<br>
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:<br>
+ if (net->ifname) {<br>
+ ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap));<br>
+ VIR_FREE(net->ifname);<br>
+ }<br>
+ break;<br>
case VIR_DOMAIN_NET_TYPE_BRIDGE:<br>
case VIR_DOMAIN_NET_TYPE_NETWORK:<br>
#ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP<br>
--<br>
2.2.2<br>
<br>
</blockquote></div>