[libvirt] [[PATCH v6] autocreate tap device for VIR_DOMAIN_NET_TYPE_ETHERNET] autocreate tap device for VIR_DOMAIN_NET_TYPE_ETHERNET

Daniel P. Berrange berrange at redhat.com
Fri Jun 19 08:46:32 UTC 2015


On Fri, Jun 19, 2015 at 11:21:15AM +0300, Vasiliy Tolstov wrote:
> If a user specify ehernet device 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 to qemu
> process.
> 
> Signed-off-by: Vasiliy Tolstov <v.tolstov at selfip.ru>
> ---
>  src/qemu/qemu_command.c | 142 +++++++++++++++++++++++++++++++-----------------
>  src/qemu/qemu_hotplug.c |  13 ++---
>  src/qemu/qemu_process.c |   6 ++
>  3 files changed, 101 insertions(+), 60 deletions(-)
> 
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 3886b4f..6d26d28 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -332,10 +332,39 @@ 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);

Nitpick - not need for %s - just use virCommandAddArg()

> +    virCommandClearCaps(cmd);
> +#ifdef CAP_NET_ADMIN
> +    virCommandAllowCap(cmd, CAP_NET_ADMIN);
> +#endif
> +    virCommandAddEnvPassCommon(cmd);
> +
> +    ret = virCommandRun(cmd, NULL);
> +
> +    virCommandFree(cmd);
> +    return ret;
> +}
> +
>  /* 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
> + * VIR_DOMAIN_NET_TYPE_ETHERNET (i.e. if the connection is
> + * made with a tap device connecting to a bridge device or
> + * use plain tap device)
>   */
>  int
>  qemuNetworkIfaceConnect(virDomainDefPtr def,
> @@ -351,6 +380,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
>      bool template_ifname = false;
>      virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
>      const char *tunpath = "/dev/net/tun";
> +    virMacAddr tapmac;
>  
>      if (net->backend.tap) {
>          tunpath = net->backend.tap;
> @@ -361,11 +391,6 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
>          }
>      }
>  
> -    if (!(brname = virDomainNetGetActualBridgeName(net))) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
> -        goto cleanup;
> -    }
> -
>      if (!net->ifname ||
>          STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
>          strchr(net->ifname, '%')) {
> @@ -381,40 +406,65 @@ 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 (virDomainNetGetActualType(net) == 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. We will add add an fdb
> -             * entry ourselves (during qemuInterfaceStartDevices(),
> -             * using the MAC address from the interface config.
> -             */
> -            if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)
> -                goto cleanup;
> -            if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0)
> +        virMacAddrSet(&tapmac, &net->mac);
> +
> +        if (virNetDevSetMAC(net->ifname, &tapmac) < 0)
> +            goto cleanup;
> +
> +        if (virNetDevSetOnline(net->ifname, true) < 0)
> +            goto cleanup;
> +
> +        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 (!(brname = virDomainNetGetActualBridgeName(net))) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
>              goto cleanup;
>          }
> -        /* qemuCreateInBridgePortWithHelper can only create a single FD */
> -        if (*tapfdSize > 1) {
> -            VIR_WARN("Ignoring multiqueue network request");
> -            *tapfdSize = 1;
> +
> +        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. We will add add an fdb
> +                 * entry ourselves (during qemuInterfaceStartDevices(),
> +                 * 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;
> +            }
> +        } 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;
> +            }
>          }
>      }
>  
> @@ -5221,6 +5271,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
>      case VIR_DOMAIN_NET_TYPE_BRIDGE:
>      case VIR_DOMAIN_NET_TYPE_NETWORK:
>      case VIR_DOMAIN_NET_TYPE_DIRECT:
> +    case VIR_DOMAIN_NET_TYPE_ETHERNET:
>          virBufferAsprintf(&buf, "tap%c", type_sep);
>          /* for one tapfd 'fd=' shall be used,
>           * for more than one 'fds=' is the right choice */
> @@ -5238,20 +5289,6 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
>          is_tap = true;
>          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:
>         virBufferAsprintf(&buf, "socket%cconnect=%s:%d",
>                           type_sep,
> @@ -8226,7 +8263,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));
> @@ -8235,7 +8273,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
>  
>      if (net->backend.tap &&
>          !(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,
>                         _("Custom tap device path is not supported for: %s"),
>                         virDomainNetTypeToString(actualType));
> @@ -8245,7 +8284,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
>      cfg = virQEMUDriverGetConfig(driver);
>  
>      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 cc86a3b..21ea3fd 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -908,7 +908,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
>      /* 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));
> @@ -916,7 +917,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;
> @@ -947,13 +949,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 64ee049..d866e44 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -5205,6 +5205,12 @@ void qemuProcessStop(virQEMUDriverPtr driver,
>                               cfg->stateDir));
>              VIR_FREE(net->ifname);
>              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_NETWORK:
>  #ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP

Aside from one nitpick inline, I think this looks good to merge.

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 :|




More information about the libvir-list mailing list