[libvirt] [PATCH 5/6] bhyve: add video support

Roman Bogorodskiy bogorodskiy at gmail.com
Sun Feb 12 15:12:33 UTC 2017


From: Fabian Freyer <fabian.freyer at physik.tu-berlin.de>

bhyve supports 'gop' video device that allows clients to connect
to VMs using VNC clients. This commit adds support for that to
the bhyve driver:

 - Introducr 'gop' video device type
 - Add capabilities probing for the 'fbuf' device that's
   responsible for graphics
 - Update command builder routines to let users configure
   domain's VNC via gop graphics.

Signed-off-by: Roman Bogorodskiy <bogorodskiy at gmail.com>
---
 docs/formatdomain.html.in           |   3 +-
 docs/schemas/domaincommon.rng       |   1 +
 po/POTFILES.in                      |   1 +
 src/bhyve/bhyve_capabilities.c      |  40 +++++++++++++++
 src/bhyve/bhyve_capabilities.h      |   1 +
 src/bhyve/bhyve_command.c           | 100 ++++++++++++++++++++++++++++++++++++
 src/bhyve/bhyve_device.c            |  11 ++++
 src/conf/domain_conf.c              |   5 +-
 src/conf/domain_conf.h              |   1 +
 src/qemu/qemu_command.c             |   9 ++--
 src/qemu/qemu_domain_address.c      |   1 +
 tests/domaincapsschemadata/full.xml |   1 +
 12 files changed, 169 insertions(+), 5 deletions(-)

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 0a115f5dc..b853a7245 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -5812,8 +5812,9 @@ qemu-kvm -net nic,model=? /dev/null
         <p>
           The <code>model</code> element has a mandatory <code>type</code>
           attribute which takes the value "vga", "cirrus", "vmvga", "xen",
-          "vbox", "qxl" (<span class="since">since 0.8.6</span>) or
+          "vbox", "qxl" (<span class="since">since 0.8.6</span>),
           "virtio" (<span class="since">since 1.3.0</span>)
+          or "gop" (<span class="since">since 3.1.0</span>)
           depending on the hypervisor features available.
         </p>
         <p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index d715bff29..3e3793ea0 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3152,6 +3152,7 @@
                 <value>xen</value>
                 <value>vbox</value>
                 <value>virtio</value>
+                <value>gop</value>
               </choice>
             </attribute>
             <group>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 365ea662f..c6d350da7 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -12,6 +12,7 @@ gnulib/lib/getopt.c
 gnulib/lib/regcomp.c
 src/access/viraccessdriverpolkit.c
 src/access/viraccessmanager.c
+src/bhyve/bhyve_capabilities.c
 src/bhyve/bhyve_command.c
 src/bhyve/bhyve_device.c
 src/bhyve/bhyve_domain.c
diff --git a/src/bhyve/bhyve_capabilities.c b/src/bhyve/bhyve_capabilities.c
index 9dec66b11..5539d2978 100644
--- a/src/bhyve/bhyve_capabilities.c
+++ b/src/bhyve/bhyve_capabilities.c
@@ -117,6 +117,7 @@ virBhyveDomainCapsBuild(const char *emulatorbin,
                         virDomainVirtType virttype)
 {
     virDomainCapsPtr caps = NULL;
+    unsigned int bhyve_caps = 0;
     DIR *dir;
     struct dirent *entry;
     const char *firmware_dir = "/usr/local/share/uefi-firmware";
@@ -125,6 +126,12 @@ virBhyveDomainCapsBuild(const char *emulatorbin,
     if (!(caps = virDomainCapsNew(emulatorbin, machine, arch, virttype)))
         goto cleanup;
 
+    if (virBhyveProbeCaps(&bhyve_caps)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("failed probing capabilities"));
+        goto cleanup;
+    }
+
     caps->os.supported = true;
     caps->os.loader.supported = true;
     VIR_DOMAIN_CAPS_ENUM_SET(caps->os.loader.type,
@@ -155,6 +162,12 @@ virBhyveDomainCapsBuild(const char *emulatorbin,
                              VIR_DOMAIN_DISK_BUS_SATA,
                              VIR_DOMAIN_DISK_BUS_VIRTIO);
 
+    if (bhyve_caps & BHYVE_CAP_FBUF) {
+        caps->graphics.supported = true;
+        caps->video.supported = true;
+        VIR_DOMAIN_CAPS_ENUM_SET(caps->graphics.type, VIR_DOMAIN_GRAPHICS_TYPE_VNC);
+        VIR_DOMAIN_CAPS_ENUM_SET(caps->video.modelType, VIR_DOMAIN_VIDEO_TYPE_GOP);
+    }
  cleanup:
     VIR_DIR_CLOSE(dir);
     return caps;
@@ -289,6 +302,30 @@ bhyveProbeCapsLPC_Bootrom(unsigned int *caps, char *binary)
     return ret;
 }
 
+
+static int
+bhyveProbeCapsFramebuffer(unsigned int *caps, char *binary)
+{
+    char *error;
+    virCommandPtr cmd = NULL;
+    int ret = -1, exit;
+
+    cmd = virCommandNew(binary);
+    virCommandAddArgList(cmd, "-s", "0,fbuf", NULL);
+    virCommandSetErrorBuffer(cmd, &error);
+    if (virCommandRun(cmd, &exit) < 0)
+        goto cleanup;
+
+    if (strstr(error, "pci slot 0:0: unknown device \"fbuf\"") == NULL)
+        *caps |= BHYVE_CAP_FBUF;
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(error);
+    virCommandFree(cmd);
+    return ret;
+}
+
 int
 virBhyveProbeCaps(unsigned int *caps)
 {
@@ -313,6 +350,9 @@ virBhyveProbeCaps(unsigned int *caps)
     if ((ret = bhyveProbeCapsLPC_Bootrom(caps, binary)))
         goto out;
 
+    if ((ret = bhyveProbeCapsFramebuffer(caps, binary)))
+        goto out;
+
  out:
     VIR_FREE(binary);
     return ret;
diff --git a/src/bhyve/bhyve_capabilities.h b/src/bhyve/bhyve_capabilities.h
index 746c77181..8fb97d730 100644
--- a/src/bhyve/bhyve_capabilities.h
+++ b/src/bhyve/bhyve_capabilities.h
@@ -41,6 +41,7 @@ typedef enum {
     BHYVE_CAP_AHCI32SLOT = 1 << 1,
     BHYVE_CAP_NET_E1000 = 1 << 2,
     BHYVE_CAP_LPC_BOOTROM = 1 << 3,
+    BHYVE_CAP_FBUF = 1 << 4,
 } virBhyveCapsFlags;
 
 int virBhyveProbeGrubCaps(virBhyveGrubCapsFlags *caps);
diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c
index 450800920..ec7a71572 100644
--- a/src/bhyve/bhyve_command.c
+++ b/src/bhyve/bhyve_command.c
@@ -290,6 +290,94 @@ bhyveBuildLPCArgStr(const virDomainDef *def ATTRIBUTE_UNUSED,
     return 0;
 }
 
+static int
+bhyveBuildGraphicsArgStr(const virDomainDef *def ATTRIBUTE_UNUSED,
+                         virDomainGraphicsDefPtr graphics,
+                         virDomainVideoDefPtr video,
+                         virConnectPtr conn,
+                         virCommandPtr cmd)
+{
+    virBuffer opt = VIR_BUFFER_INITIALIZER;
+    virDomainGraphicsListenDefPtr glisten = NULL;
+    bool escapeAddr;
+
+    if (!(bhyveDriverGetCaps(conn) & BHYVE_CAP_LPC_BOOTROM) ||
+        def->os.bootloader ||
+        !def->os.loader) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Graphics are only supported"
+                         " when booting using UEFI"));
+        return -1;
+    }
+
+    if (!(bhyveDriverGetCaps(conn) & BHYVE_CAP_FBUF)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Bhyve version does not support framebuffer"));
+        return -1;
+    }
+
+    if (graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Only VNC supported"));
+        return -1;
+    }
+
+    if (!(glisten = virDomainGraphicsGetListen(graphics, 0))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Missing listen element"));
+        goto error;
+    }
+
+    virBufferAsprintf(&opt, "%d:%d,fbuf", video->info.addr.pci.slot, video->info.addr.pci.function);
+
+    switch (glisten->type) {
+    case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
+    case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
+        virBufferAddLit(&opt, ",tcp=");
+
+        if (!graphics->data.vnc.autoport &&
+            (graphics->data.vnc.port < 5900 ||
+             graphics->data.vnc.port > 65535)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("vnc port must be in range [5900,65535]"));
+            goto error;
+        }
+
+        if (graphics->data.vnc.auth.passwd) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("vnc password auth not supported"));
+            goto error;
+        } else {
+             /* Bhyve doesn't support VNC Auth yet, so print a warning about
+              * unauthenticated VNC sessions */
+             VIR_WARN("%s", _("Security warning: currently VNC auth is not"
+                              " supported."));
+        }
+
+        if (glisten->address) {
+            escapeAddr = strchr(glisten->address, ':') != NULL;
+            if (escapeAddr)
+                virBufferAsprintf(&opt, "[%s]", glisten->address);
+            else
+                virBufferAdd(&opt, glisten->address, -1);
+        }
+
+        virBufferAsprintf(&opt, ":%d", graphics->data.vnc.port);
+        break;
+    default:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Unsupported listen type"));
+    }
+
+    virCommandAddArg(cmd, "-s");
+    virCommandAddArgBuffer(cmd, &opt);
+    return 0;
+
+ error:
+    virBufferFreeAndReset(&opt);
+    return -1;
+}
+
 virCommandPtr
 virBhyveProcessBuildBhyveCmd(virConnectPtr conn,
                              virDomainDefPtr def, bool dryRun)
@@ -413,6 +501,18 @@ virBhyveProcessBuildBhyveCmd(virConnectPtr conn,
         }
     }
 
+    if (def->ngraphics && def->nvideos) {
+        if (def->ngraphics == 1 && def->nvideos == 1) {
+            if (bhyveBuildGraphicsArgStr(def, def->graphics[0], def->videos[0], conn, cmd) < 0)
+                goto error;
+            add_lpc = true;
+        } else {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("Multiple graphics devices are not supported"));
+             goto error;
+        }
+    }
+
     if (add_lpc || def->nserials)
         bhyveBuildLPCArgStr(def, cmd);
 
diff --git a/src/bhyve/bhyve_device.c b/src/bhyve/bhyve_device.c
index 55ce631ec..a3a263b7e 100644
--- a/src/bhyve/bhyve_device.c
+++ b/src/bhyve/bhyve_device.c
@@ -145,6 +145,17 @@ bhyveAssignDevicePCISlots(virDomainDefPtr def,
             goto error;
     }
 
+    for (i = 0; i < def->nvideos; i++) {
+        if (!virDeviceInfoPCIAddressWanted(&def->videos[i]->info))
+            continue;
+        if (virDomainPCIAddressReserveNextAddr(addrs,
+                                               &def->videos[i]->info,
+                                               VIR_PCI_CONNECT_TYPE_PCI_DEVICE,
+                                               -1) < 0)
+            goto error;
+    }
+
+
     return 0;
 
  error:
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 1bc72a4e9..77fe87582 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -545,7 +545,8 @@ VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
               "vbox",
               "qxl",
               "parallels",
-              "virtio")
+              "virtio",
+              "gop")
 
 VIR_ENUM_IMPL(virDomainInput, VIR_DOMAIN_INPUT_TYPE_LAST,
               "mouse",
@@ -13018,6 +13019,8 @@ virDomainVideoDefaultType(const virDomainDef *def)
             return VIR_DOMAIN_VIDEO_TYPE_VGA;
         else
             return VIR_DOMAIN_VIDEO_TYPE_PARALLELS;
+    case VIR_DOMAIN_VIRT_BHYVE:
+        return VIR_DOMAIN_VIDEO_TYPE_GOP;
     default:
         return -1;
     }
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index dd79206f6..0876eabbf 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1335,6 +1335,7 @@ typedef enum {
     VIR_DOMAIN_VIDEO_TYPE_QXL,
     VIR_DOMAIN_VIDEO_TYPE_PARALLELS, /* pseudo device for VNC in containers */
     VIR_DOMAIN_VIDEO_TYPE_VIRTIO,
+    VIR_DOMAIN_VIDEO_TYPE_GOP,
 
     VIR_DOMAIN_VIDEO_TYPE_LAST
 } virDomainVideoType;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index c00a47a91..aabdcdcee 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -100,7 +100,8 @@ VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
               "", /* don't support vbox */
               "qxl",
               "", /* don't support parallels */
-              "" /* no need for virtio */);
+              "", /* no need for virtio */
+              "" /* don't support gop */);
 
 VIR_ENUM_DECL(qemuDeviceVideo)
 
@@ -112,7 +113,8 @@ VIR_ENUM_IMPL(qemuDeviceVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
               "", /* don't support vbox */
               "qxl-vga",
               "", /* don't support parallels */
-              "virtio-vga");
+              "virtio-vga",
+              "" /* don't support gop */);
 
 VIR_ENUM_DECL(qemuDeviceVideoSecondary)
 
@@ -124,7 +126,8 @@ VIR_ENUM_IMPL(qemuDeviceVideoSecondary, VIR_DOMAIN_VIDEO_TYPE_LAST,
               "", /* don't support vbox */
               "qxl",
               "", /* don't support parallels */
-              "virtio-gpu-pci");
+              "virtio-gpu-pci",
+              "" /* don't support gop */);
 
 VIR_ENUM_DECL(qemuSoundCodec)
 
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 70482f224..e22adacb2 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -741,6 +741,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev,
         case VIR_DOMAIN_VIDEO_TYPE_PARALLELS:
             return pciFlags;
 
+        case VIR_DOMAIN_VIDEO_TYPE_GOP:
         case VIR_DOMAIN_VIDEO_TYPE_LAST:
             return 0;
         }
diff --git a/tests/domaincapsschemadata/full.xml b/tests/domaincapsschemadata/full.xml
index 6abd4995a..6a676253c 100644
--- a/tests/domaincapsschemadata/full.xml
+++ b/tests/domaincapsschemadata/full.xml
@@ -70,6 +70,7 @@
         <value>qxl</value>
         <value>parallels</value>
         <value>virtio</value>
+        <value>gop</value>
       </enum>
     </video>
     <hostdev supported='yes'>
-- 
2.11.0




More information about the libvir-list mailing list