bhyve_capabilities.c 9.1 KB
Newer Older
1 2 3 4
/*
 * bhyve_capabilities.c: bhyve capabilities module
 *
 * Copyright (C) 2014 Roman Bogorodskiy
5
 * Copyright (C) 2014 Semihalf
6
 * Copyright (C) 2016 Fabian Freyer
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 */
#include <config.h>
#include <sys/utsname.h>
F
Fabian Freyer 已提交
25 26 27
#include <dirent.h>
#include <stdio.h>
#include <sys/types.h>
28 29

#include "viralloc.h"
30
#include "virfile.h"
31 32 33 34 35 36
#include "virlog.h"
#include "virstring.h"
#include "cpu/cpu.h"
#include "domain_conf.h"
#include "vircommand.h"
#include "bhyve_capabilities.h"
37
#include "bhyve_conf.h"
38 39 40 41 42 43 44 45 46 47 48 49 50

#define VIR_FROM_THIS   VIR_FROM_BHYVE

VIR_LOG_INIT("bhyve.bhyve_capabilities");


virCapsPtr
virBhyveCapsBuild(void)
{
    virCapsPtr caps;
    virCapsGuestPtr guest;

    if ((caps = virCapabilitiesNew(virArchFromHost(),
51
                                   false, false)) == NULL)
52 53
        return NULL;

54
    if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM,
55 56 57 58 59
                                         VIR_ARCH_X86_64,
                                         "bhyve",
                                         NULL, 0, NULL)) == NULL)
        goto error;

60 61
    if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_BHYVE,
                                      NULL, NULL, 0, NULL) == NULL)
62 63
        goto error;

M
Martin Kletzander 已提交
64 65
    if (!(caps->host.cpu = virCPUProbeHost(caps->host.arch)))
        VIR_WARN("Failed to get host CPU");
66 67 68 69 70 71 72

    return caps;

 error:
    virObjectUnref(caps);
    return NULL;
}
73

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
int
virBhyveDomainCapsFill(virDomainCapsPtr caps,
                       unsigned int bhyvecaps,
                       virDomainCapsStringValuesPtr firmwares)
{
    caps->disk.supported = true;
    VIR_DOMAIN_CAPS_ENUM_SET(caps->disk.diskDevice,
                             VIR_DOMAIN_DISK_DEVICE_DISK,
                             VIR_DOMAIN_DISK_DEVICE_CDROM);

    VIR_DOMAIN_CAPS_ENUM_SET(caps->disk.bus,
                             VIR_DOMAIN_DISK_BUS_SATA,
                             VIR_DOMAIN_DISK_BUS_VIRTIO);

    caps->os.supported = true;

    if (bhyvecaps & BHYVE_CAP_LPC_BOOTROM) {
        caps->os.loader.supported = true;
        VIR_DOMAIN_CAPS_ENUM_SET(caps->os.loader.type,
                                 VIR_DOMAIN_LOADER_TYPE_PFLASH);
        VIR_DOMAIN_CAPS_ENUM_SET(caps->os.loader.readonly,
                                 VIR_TRISTATE_BOOL_YES);

        caps->os.loader.values.values = firmwares->values;
        caps->os.loader.values.nvalues = firmwares->nvalues;
    }


    if (bhyvecaps & 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);
    }
    return 0;
}


112
virDomainCapsPtr
113 114
virBhyveDomainCapsBuild(bhyveConnPtr conn,
                        const char *emulatorbin,
115 116 117 118 119
                        const char *machine,
                        virArch arch,
                        virDomainVirtType virttype)
{
    virDomainCapsPtr caps = NULL;
F
Fabian Freyer 已提交
120
    unsigned int bhyve_caps = 0;
F
Fabian Freyer 已提交
121 122 123
    DIR *dir;
    struct dirent *entry;
    size_t firmwares_alloc = 0;
124 125
    virBhyveDriverConfigPtr cfg = virBhyveDriverGetConfig(conn);
    const char *firmware_dir = cfg->firmwareDir;
126
    virDomainCapsStringValuesPtr firmwares = NULL;
127 128 129 130

    if (!(caps = virDomainCapsNew(emulatorbin, machine, arch, virttype)))
        goto cleanup;

F
Fabian Freyer 已提交
131 132 133 134 135 136
    if (virBhyveProbeCaps(&bhyve_caps)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("failed probing capabilities"));
        goto cleanup;
    }

137 138
    if (VIR_ALLOC(firmwares) < 0)
        goto cleanup;
F
Fabian Freyer 已提交
139 140 141

    if (virDirOpenIfExists(&dir, firmware_dir) > 0) {
        while ((virDirRead(dir, &entry, firmware_dir)) > 0) {
142 143
            if (VIR_RESIZE_N(firmwares->values,
                firmwares_alloc, firmwares->nvalues, 1) < 0)
F
Fabian Freyer 已提交
144 145 146
                goto cleanup;

            if (virAsprintf(
147
                    &firmwares->values[firmwares->nvalues],
F
Fabian Freyer 已提交
148 149 150
                    "%s/%s", firmware_dir, entry->d_name) < 0)
                goto cleanup;

151
            firmwares->nvalues++;
F
Fabian Freyer 已提交
152
        }
153 154
    } else {
        VIR_WARN("Cannot open firmware directory %s", firmware_dir);
F
Fabian Freyer 已提交
155
    }
156

157 158
    if (virBhyveDomainCapsFill(caps, bhyve_caps, firmwares) < 0)
        goto cleanup;
159 160

 cleanup:
161
    VIR_FREE(firmwares);
F
Fabian Freyer 已提交
162
    VIR_DIR_CLOSE(dir);
163
    virObjectUnref(cfg);
164 165 166
    return caps;
}

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
int
virBhyveProbeGrubCaps(virBhyveGrubCapsFlags *caps)
{
    char *binary, *help;
    virCommandPtr cmd;
    int ret, exit;

    ret = 0;
    *caps = 0;
    cmd = NULL;
    help = NULL;

    binary = virFindFileInPath("grub-bhyve");
    if (binary == NULL)
        goto out;

    cmd = virCommandNew(binary);
    virCommandAddArg(cmd, "--help");
    virCommandSetOutputBuffer(cmd, &help);
    if (virCommandRun(cmd, &exit) < 0) {
        ret = -1;
        goto out;
    }

    if (strstr(help, "--cons-dev") != NULL)
        *caps |= BHYVE_GRUB_CAP_CONSDEV;

 out:
    VIR_FREE(help);
    virCommandFree(cmd);
    VIR_FREE(binary);
    return ret;
}
R
Roman Bogorodskiy 已提交
200

201
static int
202 203 204 205 206 207
bhyveProbeCapsDeviceHelper(unsigned int *caps,
                           char *binary,
                           const char *bus,
                           const char *device,
                           const char *errormsg,
                           unsigned int flag)
R
Roman Bogorodskiy 已提交
208
{
209
    char *error;
R
Roman Bogorodskiy 已提交
210
    virCommandPtr cmd = NULL;
211
    int ret = -1, exit;
R
Roman Bogorodskiy 已提交
212 213

    cmd = virCommandNew(binary);
214 215 216 217
    virCommandAddArgList(cmd, bus, device, NULL);
    virCommandSetErrorBuffer(cmd, &error);
    if (virCommandRun(cmd, &exit) < 0)
        goto cleanup;
R
Roman Bogorodskiy 已提交
218

219 220
    if (strstr(error, errormsg) == NULL)
        *caps |= flag;
R
Roman Bogorodskiy 已提交
221

222 223 224
    ret = 0;
 cleanup:
    VIR_FREE(error);
R
Roman Bogorodskiy 已提交
225
    virCommandFree(cmd);
226 227 228 229
    return ret;
}

static int
230
bhyveProbeCapsRTC_UTC(unsigned int *caps, char *binary)
231
{
232
    char *help;
233 234 235 236
    virCommandPtr cmd = NULL;
    int ret = 0, exit;

    cmd = virCommandNew(binary);
237 238
    virCommandAddArg(cmd, "-h");
    virCommandSetErrorBuffer(cmd, &help);
239 240 241 242 243
    if (virCommandRun(cmd, &exit) < 0) {
        ret = -1;
        goto out;
    }

244 245
    if (strstr(help, "-u:") != NULL)
        *caps |= BHYVE_CAP_RTC_UTC;
246 247

 out:
248
    VIR_FREE(help);
249 250 251 252
    virCommandFree(cmd);
    return ret;
}

R
Roman Bogorodskiy 已提交
253
static int
254
bhyveProbeCapsAHCI32Slot(unsigned int *caps, char *binary)
R
Roman Bogorodskiy 已提交
255
{
256 257 258 259 260 261
    return bhyveProbeCapsDeviceHelper(caps, binary,
                                      "-s",
                                      "0,ahci",
                                      "pci slot 0:0: unknown device \"ahci\"",
                                      BHYVE_CAP_AHCI32SLOT);
}
R
Roman Bogorodskiy 已提交
262 263


264 265 266 267 268 269 270 271
static int
bhyveProbeCapsNetE1000(unsigned int *caps, char *binary)
{
    return bhyveProbeCapsDeviceHelper(caps, binary,
                                      "-s",
                                      "0,e1000",
                                      "pci slot 0:0: unknown device \"e1000\"",
                                      BHYVE_CAP_NET_E1000);
R
Roman Bogorodskiy 已提交
272
}
273

274 275 276
static int
bhyveProbeCapsLPC_Bootrom(unsigned int *caps, char *binary)
{
277 278 279 280 281
    return bhyveProbeCapsDeviceHelper(caps, binary,
                                      "-l",
                                      "bootrom",
                                      "bhyve: invalid lpc device configuration 'bootrom'",
                                      BHYVE_CAP_LPC_BOOTROM);
282 283
}

F
Fabian Freyer 已提交
284 285 286 287

static int
bhyveProbeCapsFramebuffer(unsigned int *caps, char *binary)
{
288 289 290 291 292
    return bhyveProbeCapsDeviceHelper(caps, binary,
                                      "-s",
                                      "0,fbuf",
                                      "pci slot 0:0: unknown device \"fbuf\"",
                                      BHYVE_CAP_FBUF);
F
Fabian Freyer 已提交
293 294
}

295 296 297 298 299 300 301 302 303 304 305 306

static int
bhyveProbeCapsXHCIController(unsigned int *caps, char *binary)
{
    return bhyveProbeCapsDeviceHelper(caps, binary,
                                      "-s",
                                      "0,xhci",
                                      "pci slot 0:0: unknown device \"xhci\"",
                                      BHYVE_CAP_FBUF);
}


307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
int
virBhyveProbeCaps(unsigned int *caps)
{
    char *binary;
    int ret = 0;

    binary = virFindFileInPath("bhyve");
    if (binary == NULL)
        goto out;

    if ((ret = bhyveProbeCapsRTC_UTC(caps, binary)))
        goto out;

    if ((ret = bhyveProbeCapsAHCI32Slot(caps, binary)))
        goto out;

R
Roman Bogorodskiy 已提交
323 324 325
    if ((ret = bhyveProbeCapsNetE1000(caps, binary)))
        goto out;

326 327 328
    if ((ret = bhyveProbeCapsLPC_Bootrom(caps, binary)))
        goto out;

F
Fabian Freyer 已提交
329 330 331
    if ((ret = bhyveProbeCapsFramebuffer(caps, binary)))
        goto out;

332 333 334
    if ((ret = bhyveProbeCapsXHCIController(caps, binary)))
        goto out;

335
 out:
R
Roman Bogorodskiy 已提交
336 337 338
    VIR_FREE(binary);
    return ret;
}