bhyve_capabilities.c 9.4 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
#include <dirent.h>
#include <sys/types.h>
27 28

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

#define VIR_FROM_THIS   VIR_FROM_BHYVE

VIR_LOG_INIT("bhyve.bhyve_capabilities");


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

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

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

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

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

    return caps;

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

73 74 75 76 77
int
virBhyveDomainCapsFill(virDomainCapsPtr caps,
                       unsigned int bhyvecaps,
                       virDomainCapsStringValuesPtr firmwares)
{
78
    caps->disk.supported = VIR_TRISTATE_BOOL_YES;
79 80 81 82 83 84 85 86
    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);

87
    caps->os.supported = VIR_TRISTATE_BOOL_YES;
88 89

    if (bhyvecaps & BHYVE_CAP_LPC_BOOTROM) {
90
        caps->os.loader.supported = VIR_TRISTATE_BOOL_YES;
91 92 93 94 95 96 97 98 99 100 101
        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) {
102 103
        caps->graphics.supported = VIR_TRISTATE_BOOL_YES;
        caps->video.supported = VIR_TRISTATE_BOOL_YES;
104 105 106 107 108 109 110
        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;
}


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

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

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

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

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

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

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

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

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

166 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
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 已提交
199

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

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

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

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

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

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

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

246 247 248 249 250 251
    /* "-c vcpus" was there before CPU topology support was introduced,
     * then it became
     * "-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n] */
    if (strstr(help, "-c vcpus") == NULL)
        *caps |= BHYVE_CAP_CPUTOPOLOGY;

252
 out:
253
    VIR_FREE(help);
254 255 256 257
    virCommandFree(cmd);
    return ret;
}

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


269 270 271 272 273 274 275 276
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 已提交
277
}
278

279 280 281
static int
bhyveProbeCapsLPC_Bootrom(unsigned int *caps, char *binary)
{
282 283 284 285 286
    return bhyveProbeCapsDeviceHelper(caps, binary,
                                      "-l",
                                      "bootrom",
                                      "bhyve: invalid lpc device configuration 'bootrom'",
                                      BHYVE_CAP_LPC_BOOTROM);
287 288
}

F
Fabian Freyer 已提交
289 290 291 292

static int
bhyveProbeCapsFramebuffer(unsigned int *caps, char *binary)
{
293 294 295 296 297
    return bhyveProbeCapsDeviceHelper(caps, binary,
                                      "-s",
                                      "0,fbuf",
                                      "pci slot 0:0: unknown device \"fbuf\"",
                                      BHYVE_CAP_FBUF);
F
Fabian Freyer 已提交
298 299
}

300 301 302 303 304 305 306 307 308 309 310 311

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);
}


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

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

322
    if ((ret = bhyveProbeCapsFromHelp(caps, binary)))
323 324 325 326 327
        goto out;

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

R
Roman Bogorodskiy 已提交
328 329 330
    if ((ret = bhyveProbeCapsNetE1000(caps, binary)))
        goto out;

331 332 333
    if ((ret = bhyveProbeCapsLPC_Bootrom(caps, binary)))
        goto out;

F
Fabian Freyer 已提交
334 335 336
    if ((ret = bhyveProbeCapsFramebuffer(caps, binary)))
        goto out;

337 338 339
    if ((ret = bhyveProbeCapsXHCIController(caps, binary)))
        goto out;

340
 out:
R
Roman Bogorodskiy 已提交
341 342 343
    VIR_FREE(binary);
    return ret;
}