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 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
bhyveProbeCapsFromHelp(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 248 249 250 251 252
    /* "-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;

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

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


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

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

F
Fabian Freyer 已提交
290 291 292 293

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

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

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


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;

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

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

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

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

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

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

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