You need to sign in or sign up before continuing.
bhyve_command.c 9.2 KB
Newer Older
R
Roman Bogorodskiy 已提交
1
/*
2
 * bhyve_command.c: bhyve command generation
R
Roman Bogorodskiy 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *
 * Copyright (C) 2014 Roman Bogorodskiy
 *
 * 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/types.h>
#include <net/if.h>
#include <net/if_tap.h>

#include "bhyve_command.h"
#include "viralloc.h"
#include "virfile.h"
#include "virstring.h"
#include "virlog.h"
#include "virnetdev.h"
#include "virnetdevbridge.h"
#include "virnetdevtap.h"

#define VIR_FROM_THIS VIR_FROM_BHYVE

39 40
VIR_LOG_INIT("bhyve.bhyve_command");

R
Roman Bogorodskiy 已提交
41
static int
42 43 44 45
bhyveBuildNetArgStr(const virDomainDef *def,
                    virDomainNetDefPtr net,
                    virCommandPtr cmd,
                    bool dryRun)
R
Roman Bogorodskiy 已提交
46
{
47
    char macaddr[VIR_MAC_STRING_BUFLEN];
R
Roman Bogorodskiy 已提交
48 49
    char *realifname = NULL;
    int *tapfd = NULL;
50 51
    char *brname = NULL;
    int actualType = virDomainNetGetActualType(net);
R
Roman Bogorodskiy 已提交
52

53 54 55 56 57 58 59
    if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
        if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0)
            return -1;
    } else {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Network type %d is not supported"),
                       virDomainNetGetActualType(net));
R
Roman Bogorodskiy 已提交
60 61 62
        return -1;
    }

63 64 65 66 67 68
    if (!net->ifname ||
        STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
        strchr(net->ifname, '%')) {
        VIR_FREE(net->ifname);
        if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_PREFIX "%d") < 0) {
            VIR_FREE(brname);
R
Roman Bogorodskiy 已提交
69 70
            return -1;
        }
71
    }
R
Roman Bogorodskiy 已提交
72

73 74 75 76 77 78
    if (!dryRun) {
        if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,
                                           def->uuid, tapfd, 1,
                                           virDomainNetGetActualVirtPortProfile(net),
                                           virDomainNetGetActualVlan(net),
                                           VIR_NETDEV_TAP_CREATE_IFUP | VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
R
Roman Bogorodskiy 已提交
79
            VIR_FREE(net->ifname);
80 81
            VIR_FREE(brname);
            return -1;
R
Roman Bogorodskiy 已提交
82 83
        }

84 85 86
        realifname = virNetDevTapGetRealDeviceName(net->ifname);

        if (realifname == NULL) {
R
Roman Bogorodskiy 已提交
87 88 89 90 91
            VIR_FREE(net->ifname);
            VIR_FREE(brname);
            return -1;
        }

92 93 94 95 96 97
        VIR_DEBUG("%s -> %s", net->ifname, realifname);
        /* hack on top of other hack: we need to set
         * interface to 'UP' again after re-opening to find its
         * name
         */
        if (virNetDevSetOnline(net->ifname, true) != 0) {
98
            VIR_FREE(realifname);
99 100 101 102 103 104 105
            VIR_FREE(net->ifname);
            VIR_FREE(brname);
            return -1;
        }
    } else {
        if (VIR_STRDUP(realifname, "tap0") < 0)
            return -1;
R
Roman Bogorodskiy 已提交
106 107 108 109
    }


    virCommandAddArg(cmd, "-s");
110 111
    virCommandAddArgFormat(cmd, "%d:0,virtio-net,%s,mac=%s",
                           net->info.addr.pci.slot,
112
                           realifname, virMacAddrFormat(&net->mac, macaddr));
113
    VIR_FREE(realifname);
R
Roman Bogorodskiy 已提交
114 115 116 117

    return 0;
}

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
static int
bhyveBuildConsoleArgStr(const virDomainDef *def, virCommandPtr cmd)
{

    virDomainChrDefPtr chr = NULL;

    if (!def->nserials)
        return 0;

    chr = def->serials[0];

    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_NMDM) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("only nmdm console types are supported"));
        return -1;
    }

    /* bhyve supports only two ports: com1 and com2 */
    if (chr->target.port > 2) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("only two serial ports are supported"));
        return -1;
    }

142
    virCommandAddArgList(cmd, "-s", "1,lpc", NULL);
143 144 145 146 147 148 149
    virCommandAddArg(cmd, "-l");
    virCommandAddArgFormat(cmd, "com%d,%s",
                           chr->target.port + 1, chr->source.data.file.path);

    return 0;
}

R
Roman Bogorodskiy 已提交
150
static int
151 152 153
bhyveBuildDiskArgStr(const virDomainDef *def ATTRIBUTE_UNUSED,
                     virDomainDiskDefPtr disk,
                     virCommandPtr cmd)
R
Roman Bogorodskiy 已提交
154
{
155
    const char *bus_type;
R
Roman Bogorodskiy 已提交
156

157 158 159 160 161 162 163 164
    switch (disk->bus) {
    case VIR_DOMAIN_DISK_BUS_SATA:
        bus_type = "ahci-hd";
        break;
    case VIR_DOMAIN_DISK_BUS_VIRTIO:
        bus_type = "virtio-blk";
        break;
    default:
R
Roman Bogorodskiy 已提交
165 166 167 168 169 170 171 172 173 174 175
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("unsupported disk bus type"));
        return -1;
    }

    if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("unsupported disk device"));
        return -1;
    }

E
Eric Blake 已提交
176
    if (virDomainDiskGetType(disk) != VIR_STORAGE_TYPE_FILE) {
R
Roman Bogorodskiy 已提交
177 178 179 180 181 182
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("unsupported disk type"));
        return -1;
    }

    virCommandAddArg(cmd, "-s");
183 184
    virCommandAddArgFormat(cmd, "%d:0,%s,%s",
                           disk->info.addr.pci.slot, bus_type,
185
                           virDomainDiskGetSource(disk));
R
Roman Bogorodskiy 已提交
186 187 188 189 190 191

    return 0;
}

virCommandPtr
virBhyveProcessBuildBhyveCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
192
                             virDomainDefPtr def, bool dryRun)
R
Roman Bogorodskiy 已提交
193 194 195 196 197 198 199 200 201
{
    /*
     * /usr/sbin/bhyve -c 2 -m 256 -AI -H -P \
     *            -s 0:0,hostbridge \
     *            -s 1:0,virtio-net,tap0 \
     *            -s 2:0,ahci-hd,${IMG} \
     *            -S 31,uart,stdio \
     *            vm0
     */
202 203
    size_t i;

R
Roman Bogorodskiy 已提交
204 205 206 207
    virCommandPtr cmd = virCommandNew(BHYVE);

    /* CPUs */
    virCommandAddArg(cmd, "-c");
208
    virCommandAddArgFormat(cmd, "%d", def->vcpus);
R
Roman Bogorodskiy 已提交
209 210 211 212

    /* Memory */
    virCommandAddArg(cmd, "-m");
    virCommandAddArgFormat(cmd, "%llu",
213
                           VIR_DIV_UP(def->mem.max_balloon, 1024));
R
Roman Bogorodskiy 已提交
214 215

    /* Options */
216
    if (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_DOMAIN_FEATURE_STATE_ON)
R
Roman Bogorodskiy 已提交
217
        virCommandAddArg(cmd, "-A"); /* Create an ACPI table */
218
    if (def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_DOMAIN_FEATURE_STATE_ON)
R
Roman Bogorodskiy 已提交
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
        virCommandAddArg(cmd, "-I"); /* Present ioapic to the guest */

    /* Clarification about -H and -P flags from Peter Grehan:
     * -H and -P flags force the guest to exit when it executes IA32 HLT and PAUSE
     * instructions respectively.
     *
     * For the HLT exit, bhyve uses that to infer that the guest is idling and can
     * be put to sleep until an external event arrives. If this option is not used,
     * the guest will always use 100% of CPU on the host.
     *
     * The PAUSE exit is most useful when there are large numbers of guest VMs running,
     * since it forces the guest to exit when it spins on a lock acquisition.
     */
    virCommandAddArg(cmd, "-H"); /* vmexit from guest on hlt */
    virCommandAddArg(cmd, "-P"); /* vmexit from guest on pause */

235
    virCommandAddArgList(cmd, "-s", "0:0,hostbridge", NULL);
R
Roman Bogorodskiy 已提交
236
    /* Devices */
237 238 239 240 241 242 243 244 245 246 247
    for (i = 0; i < def->nnets; i++) {
        virDomainNetDefPtr net = def->nets[i];
        if (bhyveBuildNetArgStr(def, net, cmd, dryRun) < 0)
            goto error;
    }
    for (i = 0; i < def->ndisks; i++) {
        virDomainDiskDefPtr disk = def->disks[i];

        if (bhyveBuildDiskArgStr(def, disk, cmd) < 0)
            goto error;
    }
248
    if (bhyveBuildConsoleArgStr(def, cmd) < 0)
249
        goto error;
250
    virCommandAddArg(cmd, def->name);
R
Roman Bogorodskiy 已提交
251 252 253

    return cmd;

254
 error:
R
Roman Bogorodskiy 已提交
255 256 257 258 259 260
    virCommandFree(cmd);
    return NULL;
}

virCommandPtr
virBhyveProcessBuildDestroyCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
261
                               virDomainDefPtr def)
R
Roman Bogorodskiy 已提交
262 263 264 265
{
    virCommandPtr cmd = virCommandNew(BHYVECTL);

    virCommandAddArg(cmd, "--destroy");
266
    virCommandAddArgPair(cmd, "--vm", def->name);
R
Roman Bogorodskiy 已提交
267 268 269 270 271 272

    return cmd;
}

virCommandPtr
virBhyveProcessBuildLoadCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
273
                            virDomainDefPtr def)
R
Roman Bogorodskiy 已提交
274 275 276 277
{
    virCommandPtr cmd;
    virDomainDiskDefPtr disk;

278
    if (def->ndisks < 1) {
R
Roman Bogorodskiy 已提交
279
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
280
                       _("domain should have at least one disk defined"));
R
Roman Bogorodskiy 已提交
281 282 283
        return NULL;
    }

284
    disk = def->disks[0];
R
Roman Bogorodskiy 已提交
285 286 287 288 289 290 291

    if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("unsupported disk device"));
        return NULL;
    }

E
Eric Blake 已提交
292
    if (virDomainDiskGetType(disk) != VIR_STORAGE_TYPE_FILE) {
R
Roman Bogorodskiy 已提交
293 294 295 296 297 298 299 300 301 302
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("unsupported disk type"));
        return NULL;
    }

    cmd = virCommandNew(BHYVELOAD);

    /* Memory */
    virCommandAddArg(cmd, "-m");
    virCommandAddArgFormat(cmd, "%llu",
303
                           VIR_DIV_UP(def->mem.max_balloon, 1024));
R
Roman Bogorodskiy 已提交
304 305 306

    /* Image path */
    virCommandAddArg(cmd, "-d");
307
    virCommandAddArg(cmd, virDomainDiskGetSource(disk));
R
Roman Bogorodskiy 已提交
308 309

    /* VM name */
310
    virCommandAddArg(cmd, def->name);
R
Roman Bogorodskiy 已提交
311 312 313

    return cmd;
}