You need to sign in or sign up before continuing.
bhyve_capabilities.c 10.0 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
    caps->disk.diskDevice.report = true;
    caps->disk.bus.report = true;
    caps->disk.model.report = true;
82 83 84 85 86 87 88 89
    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);

90
    caps->os.supported = VIR_TRISTATE_BOOL_YES;
91

92
    caps->os.loader.supported = VIR_TRISTATE_BOOL_NO;
93
    if (bhyvecaps & BHYVE_CAP_LPC_BOOTROM) {
94 95
        caps->os.loader.type.report = true;
        caps->os.loader.readonly.report = true;
96
        caps->os.loader.supported = VIR_TRISTATE_BOOL_YES;
97 98 99 100 101 102 103 104 105 106
        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;
    }


107 108
    caps->graphics.supported = VIR_TRISTATE_BOOL_NO;
    caps->video.supported = VIR_TRISTATE_BOOL_NO;
109
    if (bhyvecaps & BHYVE_CAP_FBUF) {
110
        caps->graphics.supported = VIR_TRISTATE_BOOL_YES;
111
        caps->graphics.type.report = true;
112
        caps->video.supported = VIR_TRISTATE_BOOL_YES;
113
        caps->video.modelType.report = true;
114 115 116
        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);
    }
117 118

    caps->hostdev.supported = VIR_TRISTATE_BOOL_NO;
119
    virDomainCapsFeaturesInitUnsupported(caps);
120 121
    caps->gic.supported = VIR_TRISTATE_BOOL_NO;

122 123 124 125
    return 0;
}


126
virDomainCapsPtr
127 128
virBhyveDomainCapsBuild(bhyveConnPtr conn,
                        const char *emulatorbin,
129 130 131 132 133
                        const char *machine,
                        virArch arch,
                        virDomainVirtType virttype)
{
    virDomainCapsPtr caps = NULL;
F
Fabian Freyer 已提交
134
    unsigned int bhyve_caps = 0;
F
Fabian Freyer 已提交
135 136 137
    DIR *dir;
    struct dirent *entry;
    size_t firmwares_alloc = 0;
138 139
    virBhyveDriverConfigPtr cfg = virBhyveDriverGetConfig(conn);
    const char *firmware_dir = cfg->firmwareDir;
140
    virDomainCapsStringValuesPtr firmwares = NULL;
141 142 143 144

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

F
Fabian Freyer 已提交
145 146 147 148 149 150
    if (virBhyveProbeCaps(&bhyve_caps)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("failed probing capabilities"));
        goto cleanup;
    }

151 152
    if (VIR_ALLOC(firmwares) < 0)
        goto cleanup;
F
Fabian Freyer 已提交
153 154 155

    if (virDirOpenIfExists(&dir, firmware_dir) > 0) {
        while ((virDirRead(dir, &entry, firmware_dir)) > 0) {
156 157
            if (VIR_RESIZE_N(firmwares->values,
                firmwares_alloc, firmwares->nvalues, 1) < 0)
F
Fabian Freyer 已提交
158 159
                goto cleanup;

160 161
            firmwares->values[firmwares->nvalues] = g_strdup_printf("%s/%s",
                                                    firmware_dir, entry->d_name);
162
            firmwares->nvalues++;
F
Fabian Freyer 已提交
163
        }
164 165
    } else {
        VIR_WARN("Cannot open firmware directory %s", firmware_dir);
F
Fabian Freyer 已提交
166
    }
167

168 169
    if (virBhyveDomainCapsFill(caps, bhyve_caps, firmwares) < 0)
        goto cleanup;
170 171

 cleanup:
172
    VIR_FREE(firmwares);
F
Fabian Freyer 已提交
173
    VIR_DIR_CLOSE(dir);
174
    virObjectUnref(cfg);
175 176 177
    return caps;
}

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
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 已提交
211

212
static int
213 214 215 216 217 218
bhyveProbeCapsDeviceHelper(unsigned int *caps,
                           char *binary,
                           const char *bus,
                           const char *device,
                           const char *errormsg,
                           unsigned int flag)
R
Roman Bogorodskiy 已提交
219
{
220
    char *error;
R
Roman Bogorodskiy 已提交
221
    virCommandPtr cmd = NULL;
222
    int ret = -1, exit;
R
Roman Bogorodskiy 已提交
223 224

    cmd = virCommandNew(binary);
225 226 227 228
    virCommandAddArgList(cmd, bus, device, NULL);
    virCommandSetErrorBuffer(cmd, &error);
    if (virCommandRun(cmd, &exit) < 0)
        goto cleanup;
R
Roman Bogorodskiy 已提交
229

230 231
    if (strstr(error, errormsg) == NULL)
        *caps |= flag;
R
Roman Bogorodskiy 已提交
232

233 234 235
    ret = 0;
 cleanup:
    VIR_FREE(error);
R
Roman Bogorodskiy 已提交
236
    virCommandFree(cmd);
237 238 239 240
    return ret;
}

static int
241
bhyveProbeCapsFromHelp(unsigned int *caps, char *binary)
242
{
243
    char *help;
244 245 246 247
    virCommandPtr cmd = NULL;
    int ret = 0, exit;

    cmd = virCommandNew(binary);
248 249
    virCommandAddArg(cmd, "-h");
    virCommandSetErrorBuffer(cmd, &help);
250 251 252 253 254
    if (virCommandRun(cmd, &exit) < 0) {
        ret = -1;
        goto out;
    }

255 256
    if (strstr(help, "-u:") != NULL)
        *caps |= BHYVE_CAP_RTC_UTC;
257

258 259 260 261 262 263
    /* "-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;

264
 out:
265
    VIR_FREE(help);
266 267 268 269
    virCommandFree(cmd);
    return ret;
}

R
Roman Bogorodskiy 已提交
270
static int
271
bhyveProbeCapsAHCI32Slot(unsigned int *caps, char *binary)
R
Roman Bogorodskiy 已提交
272
{
273 274 275 276 277 278
    return bhyveProbeCapsDeviceHelper(caps, binary,
                                      "-s",
                                      "0,ahci",
                                      "pci slot 0:0: unknown device \"ahci\"",
                                      BHYVE_CAP_AHCI32SLOT);
}
R
Roman Bogorodskiy 已提交
279 280


281 282 283 284 285 286 287 288
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 已提交
289
}
290

291 292 293
static int
bhyveProbeCapsLPC_Bootrom(unsigned int *caps, char *binary)
{
294 295 296 297 298
    return bhyveProbeCapsDeviceHelper(caps, binary,
                                      "-l",
                                      "bootrom",
                                      "bhyve: invalid lpc device configuration 'bootrom'",
                                      BHYVE_CAP_LPC_BOOTROM);
299 300
}

F
Fabian Freyer 已提交
301 302 303 304

static int
bhyveProbeCapsFramebuffer(unsigned int *caps, char *binary)
{
305 306 307 308 309
    return bhyveProbeCapsDeviceHelper(caps, binary,
                                      "-s",
                                      "0,fbuf",
                                      "pci slot 0:0: unknown device \"fbuf\"",
                                      BHYVE_CAP_FBUF);
F
Fabian Freyer 已提交
310 311
}

312 313 314 315 316 317 318 319 320 321 322 323

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


324 325 326 327 328 329 330 331 332 333
int
virBhyveProbeCaps(unsigned int *caps)
{
    char *binary;
    int ret = 0;

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

334
    if ((ret = bhyveProbeCapsFromHelp(caps, binary)))
335 336 337 338 339
        goto out;

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

R
Roman Bogorodskiy 已提交
340 341 342
    if ((ret = bhyveProbeCapsNetE1000(caps, binary)))
        goto out;

343 344 345
    if ((ret = bhyveProbeCapsLPC_Bootrom(caps, binary)))
        goto out;

F
Fabian Freyer 已提交
346 347 348
    if ((ret = bhyveProbeCapsFramebuffer(caps, binary)))
        goto out;

349 350 351
    if ((ret = bhyveProbeCapsXHCIController(caps, binary)))
        goto out;

352
 out:
R
Roman Bogorodskiy 已提交
353 354 355
    VIR_FREE(binary);
    return ret;
}