Re: [PATCH v6] automatic create tap device with network type ethernet

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx>
> ---
>   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

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]