[libvirt] [PATCH v4] automatic create tap device with network type ethernet

If user not specify network type ethernet, assume that user needs simple tap device created with libvirt. This patch does not need to run external script to create tap device or add root to qemu process. Also libvirt runs script after device creating, if user provide it. Difference with v3 that script runs only if it provided. Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru> --- src/qemu/qemu_command.c | 119 +++++++++++++++++++++++++++++++++++------------- src/qemu/qemu_hotplug.c | 10 +--- src/qemu/qemu_process.c | 4 ++ 3 files changed, 93 insertions(+), 40 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1831323..78614d5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -276,6 +276,40 @@ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg, 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); + + if (virCommandRun(cmd, NULL) < 0) { + ret = -1; + } else { + ret = 0; + } + + cleanup: + virCommandFree(cmd); + return ret; +} + + int qemuNetworkIfaceConnect(virDomainDefPtr def, virConnectPtr conn, @@ -313,7 +347,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, } else if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0) return ret; - } else { + } else if (actualType != VIR_DOMAIN_NET_TYPE_ETHERNET) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Network type %d is not supported"), virDomainNetGetActualType(net)); @@ -335,30 +369,44 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR; } - if (cfg->privileged) { - if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, - def->uuid, tunpath, tapfd, *tapfdSize, - virDomainNetGetActualVirtPortProfile(net), - virDomainNetGetActualVlan(net), - tap_create_flags) < 0) { + if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { + if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, *tapfdSize, + tap_create_flags) < 0) { virDomainAuditNetDevice(def, net, tunpath, false); goto cleanup; } - } else { - if (qemuCreateInBridgePortWithHelper(cfg, brname, - &net->ifname, - tapfd, tap_create_flags) < 0) { - virDomainAuditNetDevice(def, net, tunpath, false); + if (net->script) { + if (qemuExecuteEthernetScript(net->ifname, net->script) < 0) goto cleanup; } - /* qemuCreateInBridgePortWithHelper can only create a single FD */ - if (*tapfdSize > 1) { - VIR_WARN("Ignoring multiqueue network request"); - *tapfdSize = 1; + if (virNetDevSetOnline(net->ifname, !!(tap_create_flags & VIR_NETDEV_TAP_CREATE_IFUP)) < 0) + goto cleanup; + } else { + if (cfg->privileged) { + if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, + def->uuid, tunpath, tapfd, *tapfdSize, + virDomainNetGetActualVirtPortProfile(net), + virDomainNetGetActualVlan(net), + tap_create_flags) < 0) { + virDomainAuditNetDevice(def, net, tunpath, false); + goto cleanup; + } + } else { + if (qemuCreateInBridgePortWithHelper(cfg, brname, + &net->ifname, + tapfd, tap_create_flags) < 0) { + virDomainAuditNetDevice(def, net, tunpath, false); + goto cleanup; + } + /* qemuCreateInBridgePortWithHelper can only create a single FD */ + if (*tapfdSize > 1) { + VIR_WARN("Ignoring multiqueue network request"); + *tapfdSize = 1; + } } - } - virDomainAuditNetDevice(def, net, tunpath, true); + virDomainAuditNetDevice(def, net, tunpath, true); + } if (cfg->macFilter && ebtablesAddForwardAllowIn(driver->ebtables, @@ -4534,18 +4582,23 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, 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; + virBufferAddLit(&buf, "tap"); + type_sep = ','; + /* for one tapfd 'fd=' shall be used, + * for more than one 'fds=' is the right choice */ + if (tapfdSize == 1) { + virBufferAsprintf(&buf, "%cfd=%s", type_sep, tapfd[0]); + } else { + virBufferAsprintf(&buf, "%cfds=", type_sep); + for (i = 0; i < tapfdSize; i++) { + if (i) + virBufferAddChar(&buf, ':'); + virBufferAdd(&buf, tapfd[i], -1); + } + } + type_sep = ','; + is_tap = true; + break; case VIR_DOMAIN_NET_TYPE_CLIENT: virBufferAsprintf(&buf, "socket%cconnect=%s:%d", @@ -7366,7 +7419,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, /* Currently nothing besides TAP devices supports multiqueue. */ if (net->driver.virtio.queues > 0 && !(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, _("Multiqueue network is not supported for: %s"), virDomainNetTypeToString(actualType)); @@ -7374,7 +7428,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, } if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || - actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { + actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || + actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { tapfdSize = net->driver.virtio.queues; if (!tapfdSize) tapfdSize = 1; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 9467d7d..1175259 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -908,7 +908,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, } if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || - actualType == VIR_DOMAIN_NET_TYPE_NETWORK) { + actualType == VIR_DOMAIN_NET_TYPE_NETWORK || + actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { tapfdSize = vhostfdSize = net->driver.virtio.queues; if (!tapfdSize) tapfdSize = vhostfdSize = 1; @@ -939,13 +940,6 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, iface_connected = true; if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) goto cleanup; - } else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { - vhostfdSize = 1; - if (VIR_ALLOC(vhostfd) < 0) - goto cleanup; - *vhostfd = -1; - if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) - goto cleanup; } /* Set Bandwidth */ diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index a14b6f7..0dbf7fb 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5064,6 +5064,10 @@ void qemuProcessStop(virQEMUDriverPtr driver, cfg->stateDir)); VIR_FREE(net->ifname); break; + case VIR_DOMAIN_NET_TYPE_ETHERNET: + ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap)); + VIR_FREE(net->ifname); + break; case VIR_DOMAIN_NET_TYPE_BRIDGE: case VIR_DOMAIN_NET_TYPE_NETWORK: #ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP -- 2.1.3

On 08.12.2014 11:48, Vasiliy Tolstov wrote:
If user not specify network type ethernet, assume that user needs simple tap device created with libvirt. This patch does not need to run external script to create tap device or add root to qemu process. Also libvirt runs script after device creating, if user provide it.
Difference with v3 that script runs only if it provided.
Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru> --- src/qemu/qemu_command.c | 119 +++++++++++++++++++++++++++++++++++------------- src/qemu/qemu_hotplug.c | 10 +--- src/qemu/qemu_process.c | 4 ++ 3 files changed, 93 insertions(+), 40 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1831323..78614d5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -276,6 +276,40 @@ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg, 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); + + if (virCommandRun(cmd, NULL) < 0) { + ret = -1; + } else { + ret = 0; + } + + cleanup: + virCommandFree(cmd); + return ret; +} + + int qemuNetworkIfaceConnect(virDomainDefPtr def, virConnectPtr conn, @@ -313,7 +347,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, } else if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0) return ret; - } else { + } else if (actualType != VIR_DOMAIN_NET_TYPE_ETHERNET) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Network type %d is not supported"), virDomainNetGetActualType(net)); @@ -335,30 +369,44 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR; }
- if (cfg->privileged) { - if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, - def->uuid, tunpath, tapfd, *tapfdSize, - virDomainNetGetActualVirtPortProfile(net), - virDomainNetGetActualVlan(net), - tap_create_flags) < 0) { + if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { + if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, *tapfdSize, + tap_create_flags) < 0) {
It seems like your MTA mangled the patch. Moreover, how is this different to v3 that I've sent? Michal

V3 have unconditional running script , v4 check for net->script before running script 09 дек. 2014 г. 11:47 пользователь "Michal Privoznik" <mprivozn@redhat.com> написал:
On 08.12.2014 11:48, Vasiliy Tolstov wrote:
If user not specify network type ethernet, assume that user needs simple tap device created with libvirt. This patch does not need to run external script to create tap device or add root to qemu process. Also libvirt runs script after device creating, if user provide it.
Difference with v3 that script runs only if it provided.
Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru> --- src/qemu/qemu_command.c | 119 ++++++++++++++++++++++++++++++ +++++------------- src/qemu/qemu_hotplug.c | 10 +--- src/qemu/qemu_process.c | 4 ++ 3 files changed, 93 insertions(+), 40 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1831323..78614d5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -276,6 +276,40 @@ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg, 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); + + if (virCommandRun(cmd, NULL) < 0) { + ret = -1; + } else { + ret = 0; + } + + cleanup: + virCommandFree(cmd); + return ret; +} + + int qemuNetworkIfaceConnect(virDomainDefPtr def, virConnectPtr conn, @@ -313,7 +347,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, } else if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0) return ret; - } else { + } else if (actualType != VIR_DOMAIN_NET_TYPE_ETHERNET) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Network type %d is not supported"), virDomainNetGetActualType(net)); @@ -335,30 +369,44 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR; }
- if (cfg->privileged) { - if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, - def->uuid, tunpath, tapfd, *tapfdSize, - virDomainNetGetActualVirtPortProfile(net), - virDomainNetGetActualVlan(net) , - tap_create_flags) < 0) { + if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { + if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, *tapfdSize, + tap_create_flags) < 0) {
It seems like your MTA mangled the patch. Moreover, how is this different to v3 that I've sent?
Michal

2014-12-09 11:33 GMT+03:00 Michal Privoznik <mprivozn@redhat.com>:
It seems like your MTA mangled the patch. Moreover, how is this different to v3 that I've sent?
What is the best way to send patches to mailing lists ? Via git send-email or via git imap-send and after corrections send it via mail client? -- Vasiliy Tolstov, e-mail: v.tolstov@selfip.ru jabber: vase@selfip.ru

On Tue, Dec 09, 2014 at 03:58:19PM +0400, Vasiliy Tolstov wrote:
2014-12-09 11:33 GMT+03:00 Michal Privoznik <mprivozn@redhat.com>:
It seems like your MTA mangled the patch. Moreover, how is this different to v3 that I've sent?
What is the best way to send patches to mailing lists ? Via git send-email or via git imap-send and after corrections send it via mail client?
The majority of us are using git send-email eg, if I'm on a branch, I'll use this to spam all patches on that branch vs master $ git send-email --cover-letter --annotate --to libvir-list@redhat.com \ --smtp-server=<my local smtp server> --no-chain-reply-to \ master.. I have this long command line hidden behind a script so I just normally run the simpler 'git-spam libvir-list@redhat.com master..' Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

2014-12-09 15:03 GMT+03:00 Daniel P. Berrange <berrange@redhat.com>:
The majority of us are using git send-email
eg, if I'm on a branch, I'll use this to spam all patches on that branch vs master
$ git send-email --cover-letter --annotate --to libvir-list@redhat.com \ --smtp-server=<my local smtp server> --no-chain-reply-to \ master..
I have this long command line hidden behind a script so I just normally run the simpler 'git-spam libvir-list@redhat.com master..'
Thanks, if i have new version of patch, what i need to specify in git send-email ? -- Vasiliy Tolstov, e-mail: v.tolstov@selfip.ru jabber: vase@selfip.ru

On 12/09/2014 07:27 AM, Vasiliy Tolstov wrote:
2014-12-09 15:03 GMT+03:00 Daniel P. Berrange <berrange@redhat.com>:
The majority of us are using git send-email
eg, if I'm on a branch, I'll use this to spam all patches on that branch vs master
$ git send-email --cover-letter --annotate --to libvir-list@redhat.com \ --smtp-server=<my local smtp server> --no-chain-reply-to \ master..
I have this long command line hidden behind a script so I just normally run the simpler 'git-spam libvir-list@redhat.com master..'
Thanks, if i have new version of patch, what i need to specify in git send-email ?
--subject-prefix="PATCHv5" (or whatever version it is)

On 12/09/2014 05:37 AM, Laine Stump wrote:
On 12/09/2014 07:27 AM, Vasiliy Tolstov wrote:
2014-12-09 15:03 GMT+03:00 Daniel P. Berrange <berrange@redhat.com>:
The majority of us are using git send-email
eg, if I'm on a branch, I'll use this to spam all patches on that branch vs master
$ git send-email --cover-letter --annotate --to libvir-list@redhat.com \ --smtp-server=<my local smtp server> --no-chain-reply-to \ master..
I have this long command line hidden behind a script so I just normally run the simpler 'git-spam libvir-list@redhat.com master..'
Thanks, if i have new version of patch, what i need to specify in git send-email ?
--subject-prefix="PATCHv5" (or whatever version it is)
or shorter, -v5 -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

If user not specify network type ethernet, assume that user needs simple tap device created with libvirt. This patch does not need to run external script to create tap device or add root to qemu process. Also libvirt runs script after device creating, if user provide it. Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru> --- src/qemu/qemu_command.c | 119 +++++++++++++++++++++++++++++++++++------------- src/qemu/qemu_hotplug.c | 10 +--- src/qemu/qemu_process.c | 4 ++ 3 files changed, 93 insertions(+), 40 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1831323..78614d5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -276,6 +276,40 @@ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg, 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); + + if (virCommandRun(cmd, NULL) < 0) { + ret = -1; + } else { + ret = 0; + } + + cleanup: + virCommandFree(cmd); + return ret; +} + + int qemuNetworkIfaceConnect(virDomainDefPtr def, virConnectPtr conn, @@ -313,7 +347,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, } else if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0) return ret; - } else { + } else if (actualType != VIR_DOMAIN_NET_TYPE_ETHERNET) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Network type %d is not supported"), virDomainNetGetActualType(net)); @@ -335,30 +369,44 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR; } - if (cfg->privileged) { - if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, - def->uuid, tunpath, tapfd, *tapfdSize, - virDomainNetGetActualVirtPortProfile(net), - virDomainNetGetActualVlan(net), - tap_create_flags) < 0) { + if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { + if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, *tapfdSize, + tap_create_flags) < 0) { virDomainAuditNetDevice(def, net, tunpath, false); goto cleanup; } - } else { - if (qemuCreateInBridgePortWithHelper(cfg, brname, - &net->ifname, - tapfd, tap_create_flags) < 0) { - virDomainAuditNetDevice(def, net, tunpath, false); + if (net->script) { + if (qemuExecuteEthernetScript(net->ifname, net->script) < 0) goto cleanup; } - /* qemuCreateInBridgePortWithHelper can only create a single FD */ - if (*tapfdSize > 1) { - VIR_WARN("Ignoring multiqueue network request"); - *tapfdSize = 1; + if (virNetDevSetOnline(net->ifname, !!(tap_create_flags & VIR_NETDEV_TAP_CREATE_IFUP)) < 0) + goto cleanup; + } else { + if (cfg->privileged) { + if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, + def->uuid, tunpath, tapfd, *tapfdSize, + virDomainNetGetActualVirtPortProfile(net), + virDomainNetGetActualVlan(net), + tap_create_flags) < 0) { + virDomainAuditNetDevice(def, net, tunpath, false); + goto cleanup; + } + } else { + if (qemuCreateInBridgePortWithHelper(cfg, brname, + &net->ifname, + tapfd, tap_create_flags) < 0) { + virDomainAuditNetDevice(def, net, tunpath, false); + goto cleanup; + } + /* qemuCreateInBridgePortWithHelper can only create a single FD */ + if (*tapfdSize > 1) { + VIR_WARN("Ignoring multiqueue network request"); + *tapfdSize = 1; + } } - } - virDomainAuditNetDevice(def, net, tunpath, true); + virDomainAuditNetDevice(def, net, tunpath, true); + } if (cfg->macFilter && ebtablesAddForwardAllowIn(driver->ebtables, @@ -4534,18 +4582,23 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, 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; + virBufferAddLit(&buf, "tap"); + type_sep = ','; + /* for one tapfd 'fd=' shall be used, + * for more than one 'fds=' is the right choice */ + if (tapfdSize == 1) { + virBufferAsprintf(&buf, "%cfd=%s", type_sep, tapfd[0]); + } else { + virBufferAsprintf(&buf, "%cfds=", type_sep); + for (i = 0; i < tapfdSize; i++) { + if (i) + virBufferAddChar(&buf, ':'); + virBufferAdd(&buf, tapfd[i], -1); + } + } + type_sep = ','; + is_tap = true; + break; case VIR_DOMAIN_NET_TYPE_CLIENT: virBufferAsprintf(&buf, "socket%cconnect=%s:%d", @@ -7366,7 +7419,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, /* Currently nothing besides TAP devices supports multiqueue. */ if (net->driver.virtio.queues > 0 && !(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, _("Multiqueue network is not supported for: %s"), virDomainNetTypeToString(actualType)); @@ -7374,7 +7428,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, } if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || - actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { + actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || + actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { tapfdSize = net->driver.virtio.queues; if (!tapfdSize) tapfdSize = 1; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 9467d7d..1175259 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -908,7 +908,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, } if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || - actualType == VIR_DOMAIN_NET_TYPE_NETWORK) { + actualType == VIR_DOMAIN_NET_TYPE_NETWORK || + actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { tapfdSize = vhostfdSize = net->driver.virtio.queues; if (!tapfdSize) tapfdSize = vhostfdSize = 1; @@ -939,13 +940,6 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, iface_connected = true; if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) goto cleanup; - } else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { - vhostfdSize = 1; - if (VIR_ALLOC(vhostfd) < 0) - goto cleanup; - *vhostfd = -1; - if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) - goto cleanup; } /* Set Bandwidth */ diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index a14b6f7..0dbf7fb 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5064,6 +5064,10 @@ void qemuProcessStop(virQEMUDriverPtr driver, cfg->stateDir)); VIR_FREE(net->ifname); break; + case VIR_DOMAIN_NET_TYPE_ETHERNET: + ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap)); + VIR_FREE(net->ifname); + break; case VIR_DOMAIN_NET_TYPE_BRIDGE: case VIR_DOMAIN_NET_TYPE_NETWORK: #ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP -- 2.1.3

2014-12-10 17:34 GMT+03:00 Vasiliy Tolstov <v.tolstov@selfip.ru>:
If user not specify network type ethernet, assume that user needs simple tap device created with libvirt. This patch does not need to run external script to create tap device or add root to qemu process. Also libvirt runs script after device creating, if user provide it.
Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
Does it possible to include this in current planned libvirt release? Thanks -- Vasiliy Tolstov, e-mail: v.tolstov@selfip.ru jabber: vase@selfip.ru

On 12.12.2014 14:09, Vasiliy Tolstov wrote:
2014-12-10 17:34 GMT+03:00 Vasiliy Tolstov <v.tolstov@selfip.ru>:
If user not specify network type ethernet, assume that user needs simple tap device created with libvirt. This patch does not need to run external script to create tap device or add root to qemu process. Also libvirt runs script after device creating, if user provide it.
Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
Does it possible to include this in current planned libvirt release? Thanks
Well, while trying to review the patch, it seems like you haven't sent rebased version. I mean, Laine pushed a patchset on Dec 8, that reworks qemuNetworkIfaceConnect() so that it's called only on a few occasions. However, the patch you've sent on Dec 10 doesn't even apply cleanly. I had to go to before his patches to be able to apply it cleanly. However, since the function semantics has changed since then, can you rebase to the current HEAD and resend? Thanks! Michal

2014-12-12 18:31 GMT+03:00 Michal Privoznik <mprivozn@redhat.com>:
Well, while trying to review the patch, it seems like you haven't sent rebased version. I mean, Laine pushed a patchset on Dec 8, that reworks qemuNetworkIfaceConnect() so that it's called only on a few occasions. However, the patch you've sent on Dec 10 doesn't even apply cleanly. I had to go to before his patches to be able to apply it cleanly. However, since the function semantics has changed since then, can you rebase to the current HEAD and resend? Thanks!
I'm rebase and resend. Thanks -- Vasiliy Tolstov, e-mail: v.tolstov@selfip.ru jabber: vase@selfip.ru

On 12/12/2014 09:02 AM, Vasiliy Tolstov wrote:
2014-12-12 18:31 GMT+03:00 Michal Privoznik <mprivozn@redhat.com>:
Well, while trying to review the patch, it seems like you haven't sent rebased version. I mean, Laine pushed a patchset on Dec 8, that reworks qemuNetworkIfaceConnect() so that it's called only on a few occasions. However, the patch you've sent on Dec 10 doesn't even apply cleanly. I had to go to before his patches to be able to apply it cleanly. However, since the function semantics has changed since then, can you rebase to the current HEAD and resend? Thanks!
I'm rebase and resend. Thanks
When resending a series, it's better to make a new top-level thread, rather than trying to bury the updated patch in-reply-to an existing deeply-nested thread. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

2014-12-12 19:33 GMT+03:00 Eric Blake <eblake@redhat.com>:
When resending a series, it's better to make a new top-level thread, rather than trying to bury the updated patch in-reply-to an existing deeply-nested thread.
Oh. Ok. Sorry for my mistakes. -- Vasiliy Tolstov, e-mail: v.tolstov@selfip.ru jabber: vase@selfip.ru

Does this patch now looks ok? 2014-12-12 19:34 GMT+03:00 Vasiliy Tolstov <v.tolstov@selfip.ru>:
2014-12-12 19:33 GMT+03:00 Eric Blake <eblake@redhat.com>:
When resending a series, it's better to make a new top-level thread, rather than trying to bury the updated patch in-reply-to an existing deeply-nested thread.
Oh. Ok. Sorry for my mistakes.
-- Vasiliy Tolstov, e-mail: v.tolstov@selfip.ru jabber: vase@selfip.ru
-- Vasiliy Tolstov, e-mail: v.tolstov@selfip.ru jabber: vase@selfip.ru

If user not specify network type ethernet, assume that user needs simple tap device created with libvirt. This patch does not need to run external script to create tap device or add root to qemu process. Also libvirt runs script after device creating, if user provide it. Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru> --- src/qemu/qemu_command.c | 157 ++++++++++++++++++++++++++++++++---------------- src/qemu/qemu_hotplug.c | 10 +-- src/qemu/qemu_process.c | 4 ++ 3 files changed, 111 insertions(+), 60 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 48bdf4e..98c2ba1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -278,9 +278,9 @@ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg, } /* qemuNetworkIfaceConnect - *only* called if actualType is - * VIR_DOMAIN_NET_TYPE_NETWORK or VIR_DOMAIN_NET_TYPE_BRIDGE (i.e. if - * the connection is made with a tap device connecting to a bridge - * device) + * VIR_DOMAIN_NET_TYPE_NETWORK, VIR_DOMAIN_NET_TYPE_BRIDGE or + * VIR_DOMAIN_NET_TYPE_ETHERNET (i.e. if the connection is + * made with a tap device) */ int qemuNetworkIfaceConnect(virDomainDefPtr def, @@ -321,49 +321,61 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR; } - if (cfg->privileged) { - if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, - def->uuid, tunpath, tapfd, *tapfdSize, - virDomainNetGetActualVirtPortProfile(net), - virDomainNetGetActualVlan(net), - tap_create_flags) < 0) { + if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { + if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, *tapfdSize, + tap_create_flags) < 0) { virDomainAuditNetDevice(def, net, tunpath, false); goto cleanup; } - if (virDomainNetGetActualBridgeMACTableManager(net) - == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) { - /* libvirt is managing the FDB of the bridge this device - * is attaching to, so we need to turn off learning and - * unicast_flood on the device to prevent the kernel from - * adding any FDB entries for it, then add an fdb entry - * outselves, using the MAC address from the interface - * config. - */ - if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0) - goto cleanup; - if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0) - goto cleanup; - if (virNetDevBridgeFDBAdd(&net->mac, net->ifname, - VIR_NETDEVBRIDGE_FDB_FLAG_MASTER | - VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0) + if (net->script) { + if (qemuExecuteEthernetScript(net->ifname, net->script) < 0) goto cleanup; } - } else { - if (qemuCreateInBridgePortWithHelper(cfg, brname, - &net->ifname, - tapfd, tap_create_flags) < 0) { - virDomainAuditNetDevice(def, net, tunpath, false); + if (virNetDevSetOnline(net->ifname, !!(tap_create_flags & VIR_NETDEV_TAP_CREATE_IFUP)) < 0) goto cleanup; + } else { + if (cfg->privileged) { + if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, + def->uuid, tunpath, tapfd, *tapfdSize, + virDomainNetGetActualVirtPortProfile(net), + virDomainNetGetActualVlan(net), + tap_create_flags) < 0) { + virDomainAuditNetDevice(def, net, tunpath, false); + goto cleanup; + } + if (virDomainNetGetActualBridgeMACTableManager(net) + == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) { + /* libvirt is managing the FDB of the bridge this device + * is attaching to, so we need to turn off learning and + * unicast_flood on the device to prevent the kernel from + * adding any FDB entries for it, then add an fdb entry + * outselves, using the MAC address from the interface + * config. + */ + if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0) + goto cleanup; + if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0) + goto cleanup; + if (virNetDevBridgeFDBAdd(&net->mac, net->ifname, + VIR_NETDEVBRIDGE_FDB_FLAG_MASTER | + VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0) + goto cleanup; + } + } else { + if (qemuCreateInBridgePortWithHelper(cfg, brname, + &net->ifname, + tapfd, tap_create_flags) < 0) { + virDomainAuditNetDevice(def, net, tunpath, false); + goto cleanup; + } + /* qemuCreateInBridgePortWithHelper can only create a single FD */ + if (*tapfdSize > 1) { + VIR_WARN("Ignoring multiqueue network request"); + *tapfdSize = 1; + } } - /* qemuCreateInBridgePortWithHelper can only create a single FD */ - if (*tapfdSize > 1) { - VIR_WARN("Ignoring multiqueue network request"); - *tapfdSize = 1; - } + virDomainAuditNetDevice(def, net, tunpath, true); } - - virDomainAuditNetDevice(def, net, tunpath, true); - if (cfg->macFilter && ebtablesAddForwardAllowIn(driver->ebtables, net->ifname, @@ -510,6 +522,40 @@ qemuOpenVhostNet(virDomainDefPtr def, return -1; } +/** + * 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); + + if (virCommandRun(cmd, NULL) < 0) { + ret = -1; + } else { + ret = 0; + } + + cleanup: + virCommandFree(cmd); + return ret; +} + + int qemuNetworkPrepareDevices(virDomainDefPtr def) { @@ -4537,18 +4583,23 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, 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; + virBufferAddLit(&buf, "tap"); + type_sep = ','; + /* for one tapfd 'fd=' shall be used, + * for more than one 'fds=' is the right choice */ + if (tapfdSize == 1) { + virBufferAsprintf(&buf, "%cfd=%s", type_sep, tapfd[0]); + } else { + virBufferAsprintf(&buf, "%cfds=", type_sep); + for (i = 0; i < tapfdSize; i++) { + if (i) + virBufferAddChar(&buf, ':'); + virBufferAdd(&buf, tapfd[i], -1); + } + } + type_sep = ','; + is_tap = true; + break; case VIR_DOMAIN_NET_TYPE_CLIENT: virBufferAsprintf(&buf, "socket%cconnect=%s:%d", @@ -7369,7 +7420,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, /* Currently nothing besides TAP devices supports multiqueue. */ if (net->driver.virtio.queues > 0 && !(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, _("Multiqueue network is not supported for: %s"), virDomainNetTypeToString(actualType)); @@ -7377,7 +7429,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, } if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || - actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { + actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || + actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { tapfdSize = net->driver.virtio.queues; if (!tapfdSize) tapfdSize = 1; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 8c0642e..6d6f6c4 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -904,7 +904,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, } if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || - actualType == VIR_DOMAIN_NET_TYPE_NETWORK) { + actualType == VIR_DOMAIN_NET_TYPE_NETWORK || + actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { tapfdSize = vhostfdSize = net->driver.virtio.queues; if (!tapfdSize) tapfdSize = vhostfdSize = 1; @@ -935,13 +936,6 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, iface_connected = true; if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) goto cleanup; - } else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { - vhostfdSize = 1; - if (VIR_ALLOC(vhostfd) < 0) - goto cleanup; - *vhostfd = -1; - if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) - goto cleanup; } /* Set device online immediately */ diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index ab4df9b..1ca10b3 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5071,6 +5071,10 @@ void qemuProcessStop(virQEMUDriverPtr driver, cfg->stateDir)); VIR_FREE(net->ifname); break; + case VIR_DOMAIN_NET_TYPE_ETHERNET: + ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap)); + VIR_FREE(net->ifname); + break; case VIR_DOMAIN_NET_TYPE_BRIDGE: case VIR_DOMAIN_NET_TYPE_NETWORK: #ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP -- 2.1.3

On 12.12.2014 17:08, Vasiliy Tolstov wrote:
If user not specify network type ethernet, assume that user needs simple tap device created with libvirt. This patch does not need to run external script to create tap device or add root to qemu process. Also libvirt runs script after device creating, if user provide it.
Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru> --- src/qemu/qemu_command.c | 157 ++++++++++++++++++++++++++++++++---------------- src/qemu/qemu_hotplug.c | 10 +-- src/qemu/qemu_process.c | 4 ++ 3 files changed, 111 insertions(+), 60 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 48bdf4e..98c2ba1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -278,9 +278,9 @@ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg, }
/* qemuNetworkIfaceConnect - *only* called if actualType is - * VIR_DOMAIN_NET_TYPE_NETWORK or VIR_DOMAIN_NET_TYPE_BRIDGE (i.e. if - * the connection is made with a tap device connecting to a bridge - * device) + * VIR_DOMAIN_NET_TYPE_NETWORK, VIR_DOMAIN_NET_TYPE_BRIDGE or + * VIR_DOMAIN_NET_TYPE_ETHERNET (i.e. if the connection is + * made with a tap device) */ int qemuNetworkIfaceConnect(virDomainDefPtr def, @@ -321,49 +321,61 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR; }
- if (cfg->privileged) { - if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, - def->uuid, tunpath, tapfd, *tapfdSize, - virDomainNetGetActualVirtPortProfile(net), - virDomainNetGetActualVlan(net), - tap_create_flags) < 0) { + if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {
I wonder how this can even work. I mean, not shown in the context, but a few lines above there's check for @net's bridge name. If there's none (and there really is none for ETHERNET), an error is thrown and control returns immediately after that.
+ if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, *tapfdSize, + tap_create_flags) < 0) { virDomainAuditNetDevice(def, net, tunpath, false); goto cleanup; } - if (virDomainNetGetActualBridgeMACTableManager(net) - == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) { - /* libvirt is managing the FDB of the bridge this device - * is attaching to, so we need to turn off learning and - * unicast_flood on the device to prevent the kernel from - * adding any FDB entries for it, then add an fdb entry - * outselves, using the MAC address from the interface - * config. - */ - if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0) - goto cleanup; - if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0) - goto cleanup; - if (virNetDevBridgeFDBAdd(&net->mac, net->ifname, - VIR_NETDEVBRIDGE_FDB_FLAG_MASTER | - VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0) + if (net->script) { + if (qemuExecuteEthernetScript(net->ifname, net->script) < 0)
And here I wonder how this can even compile. qemuExecuteEthernetScript() is undefined here as you declare it a few hundred lines below.
goto cleanup; } - } else { - if (qemuCreateInBridgePortWithHelper(cfg, brname, - &net->ifname, - tapfd, tap_create_flags) < 0) { - virDomainAuditNetDevice(def, net, tunpath, false); + if (virNetDevSetOnline(net->ifname, !!(tap_create_flags & VIR_NETDEV_TAP_CREATE_IFUP)) < 0) goto cleanup; + } else { + if (cfg->privileged) { + if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, + def->uuid, tunpath, tapfd, *tapfdSize, + virDomainNetGetActualVirtPortProfile(net), + virDomainNetGetActualVlan(net), + tap_create_flags) < 0) { + virDomainAuditNetDevice(def, net, tunpath, false); + goto cleanup; + } + if (virDomainNetGetActualBridgeMACTableManager(net) + == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) { + /* libvirt is managing the FDB of the bridge this device + * is attaching to, so we need to turn off learning and + * unicast_flood on the device to prevent the kernel from + * adding any FDB entries for it, then add an fdb entry + * outselves, using the MAC address from the interface + * config. + */ + if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0) + goto cleanup; + if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0) + goto cleanup; + if (virNetDevBridgeFDBAdd(&net->mac, net->ifname, + VIR_NETDEVBRIDGE_FDB_FLAG_MASTER | + VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0) + goto cleanup; + } + } else { + if (qemuCreateInBridgePortWithHelper(cfg, brname, + &net->ifname, + tapfd, tap_create_flags) < 0) { + virDomainAuditNetDevice(def, net, tunpath, false); + goto cleanup; + } + /* qemuCreateInBridgePortWithHelper can only create a single FD */ + if (*tapfdSize > 1) { + VIR_WARN("Ignoring multiqueue network request"); + *tapfdSize = 1; + } } - /* qemuCreateInBridgePortWithHelper can only create a single FD */ - if (*tapfdSize > 1) { - VIR_WARN("Ignoring multiqueue network request"); - *tapfdSize = 1; - } + virDomainAuditNetDevice(def, net, tunpath, true); } - - virDomainAuditNetDevice(def, net, tunpath, true); - if (cfg->macFilter && ebtablesAddForwardAllowIn(driver->ebtables, net->ifname, @@ -510,6 +522,40 @@ qemuOpenVhostNet(virDomainDefPtr def, return -1; }
+/** + * 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); + + if (virCommandRun(cmd, NULL) < 0) { + ret = -1; + } else { + ret = 0; + } + + cleanup:
This ^^ label is not used anywhere.
+ virCommandFree(cmd); + return ret; +} + + int qemuNetworkPrepareDevices(virDomainDefPtr def) { @@ -4537,18 +4583,23 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, 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; + virBufferAddLit(&buf, "tap"); + type_sep = ',';
This is not needed yet. I prefer the style that's used in other cases.
+ /* for one tapfd 'fd=' shall be used, + * for more than one 'fds=' is the right choice */ + if (tapfdSize == 1) { + virBufferAsprintf(&buf, "%cfd=%s", type_sep, tapfd[0]); + } else { + virBufferAsprintf(&buf, "%cfds=", type_sep); + for (i = 0; i < tapfdSize; i++) { + if (i) + virBufferAddChar(&buf, ':'); + virBufferAdd(&buf, tapfd[i], -1); + } + } + type_sep = ','; + is_tap = true; + break;
case VIR_DOMAIN_NET_TYPE_CLIENT: virBufferAsprintf(&buf, "socket%cconnect=%s:%d", @@ -7369,7 +7420,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, /* Currently nothing besides TAP devices supports multiqueue. */ if (net->driver.virtio.queues > 0 && !(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, _("Multiqueue network is not supported for: %s"), virDomainNetTypeToString(actualType)); @@ -7377,7 +7429,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, }
if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || - actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { + actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || + actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { tapfdSize = net->driver.virtio.queues; if (!tapfdSize) tapfdSize = 1; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 8c0642e..6d6f6c4 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -904,7 +904,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, }
if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || - actualType == VIR_DOMAIN_NET_TYPE_NETWORK) { + actualType == VIR_DOMAIN_NET_TYPE_NETWORK || + actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { tapfdSize = vhostfdSize = net->driver.virtio.queues; if (!tapfdSize) tapfdSize = vhostfdSize = 1; @@ -935,13 +936,6 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, iface_connected = true; if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) goto cleanup; - } else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { - vhostfdSize = 1; - if (VIR_ALLOC(vhostfd) < 0) - goto cleanup; - *vhostfd = -1; - if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) - goto cleanup; }
/* Set device online immediately */ diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index ab4df9b..1ca10b3 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5071,6 +5071,10 @@ void qemuProcessStop(virQEMUDriverPtr driver, cfg->stateDir)); VIR_FREE(net->ifname); break; + case VIR_DOMAIN_NET_TYPE_ETHERNET: + ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap)); + VIR_FREE(net->ifname); + break;
I think this call should be conditional. Otherwise I'm getting SIGSEGV: ==21845== 1 errors in context 1 of 24: ==21845== Thread 6: ==21845== Invalid read of size 1 ==21845== at 0x4C2D282: strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==21845== by 0x5312BE8: virStrcpy (virstring.c:543) ==21845== by 0x52F356C: virNetDevTapDelete (virnetdevtap.c:344) ==21845== by 0x1E05B3E7: qemuProcessStop (qemu_process.c:5075) ==21845== by 0x1E05A7D9: qemuProcessStart (qemu_process.c:4855) ==21845== by 0x1E0A26F2: qemuDomainObjStart (qemu_driver.c:6668) ==21845== by 0x1E0A2940: qemuDomainCreateWithFlags (qemu_driver.c:6723) ==21845== by 0x1E0A29A9: qemuDomainCreate (qemu_driver.c:6742) ==21845== by 0x53E7F07: virDomainCreate (libvirt-domain.c:6787) ==21845== by 0x125C0C: remoteDispatchDomainCreate (remote_dispatch.h:3177) ==21845== by 0x125B39: remoteDispatchDomainCreateHelper (remote_dispatch.h:3155) ==21845== by 0x545E0FD: virNetServerProgramDispatchCall (virnetserverprogram.c:437) ==21845== Address 0x0 is not stack'd, malloc'd or (recently) free'd
case VIR_DOMAIN_NET_TYPE_BRIDGE: case VIR_DOMAIN_NET_TYPE_NETWORK: #ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP
And I'm getting a few of 'make check' errors too. Michal
participants (5)
-
Daniel P. Berrange
-
Eric Blake
-
Laine Stump
-
Michal Privoznik
-
Vasiliy Tolstov