Example #1
0
/**
 * virNetDevBandwidthClear:
 * @ifname: on which interface
 *
 * This function tries to disable QoS on specified interface
 * by deleting root and ingress qdisc. However, this may fail
 * if we try to remove the default one.
 *
 * Return 0 on success, -1 otherwise.
 */
int
virNetDevBandwidthClear(const char *ifname)
{
    int ret = 0;
    int dummy; /* for ignoring the exit status */
    virCommandPtr cmd = NULL;

    cmd = virCommandNew(TC);
    virCommandAddArgList(cmd, "qdisc", "del", "dev", ifname, "root", NULL);

    if (virCommandRun(cmd, &dummy) < 0)
        ret = -1;

    virCommandFree(cmd);

    cmd = virCommandNew(TC);
    virCommandAddArgList(cmd, "qdisc",  "del", "dev", ifname, "ingress", NULL);

    if (virCommandRun(cmd, &dummy) < 0)
        ret = -1;

    virCommandFree(cmd);

    return ret;
}
Example #2
0
static virCommandPtr
iptablesCommandNew(const char *table, const char *chain, int family, int action)
{
    virCommandPtr cmd = NULL;
    virIpTablesInitialize();
#if HAVE_FIREWALLD
    if (firewall_cmd_path) {
        cmd = virCommandNew(firewall_cmd_path);
        virCommandAddArgList(cmd, "--direct", "--passthrough",
                             (family == AF_INET6) ? "ipv6" : "ipv4", NULL);
    }
#endif

    if (cmd == NULL) {
        cmd = virCommandNew((family == AF_INET6)
                        ? IP6TABLES_PATH : IPTABLES_PATH);

        if (iptables_supports_xlock)
            virCommandAddArgList(cmd, "-w", NULL);
    }

    virCommandAddArgList(cmd, "--table", table,
                         action == ADD ? "--insert" : "--delete",
                         chain, NULL);
    return cmd;
}
Example #3
0
/* Allow all traffic coming from the bridge, with a valid network address
 * to proceed to WAN
 */
static int
iptablesForwardAllowOut(iptablesContext *ctx,
                        virSocketAddr *netaddr,
                        unsigned int prefix,
                        const char *iface,
                        const char *physdev,
                        int action)
{
    int ret;
    char *networkstr;
    virCommandPtr cmd = NULL;

    if (!(networkstr = iptablesFormatNetwork(netaddr, prefix)))
        return -1;

    cmd = iptablesCommandNew(ctx->forward_filter,
                             VIR_SOCKET_ADDR_FAMILY(netaddr),
                             action);
    virCommandAddArgList(cmd,
                         "--source", networkstr,
                         "--in-interface", iface, NULL);

    if (physdev && physdev[0])
        virCommandAddArgList(cmd, "--out-interface", physdev, NULL);

    virCommandAddArgList(cmd, "--jump", "ACCEPT", NULL);

    ret = iptablesCommandRunAndFree(cmd);
    VIR_FREE(networkstr);
    return ret;
}
Example #4
0
/* Don't masquerade traffic coming from the network associated with the bridge
 * if said traffic targets @destaddr.
 */
static int
iptablesForwardDontMasquerade(virSocketAddr *netaddr,
                              unsigned int prefix,
                              const char *physdev,
                              const char *destaddr,
                              int action)
{
    int ret = -1;
    char *networkstr = NULL;
    virCommandPtr cmd = NULL;

    if (!(networkstr = iptablesFormatNetwork(netaddr, prefix)))
        return -1;

    if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) {
        /* Higher level code *should* guaranteee it's impossible to get here. */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Attempted to NAT '%s'. NAT is only supported for IPv4."),
                       networkstr);
        goto cleanup;
    }

    cmd = iptablesCommandNew("nat", "POSTROUTING", AF_INET, action);

    if (physdev && physdev[0])
        virCommandAddArgList(cmd, "--out-interface", physdev, NULL);

    virCommandAddArgList(cmd, "--source", networkstr,
                         "--destination", destaddr, "--jump", "RETURN", NULL);
    ret = virCommandRun(cmd, NULL);
 cleanup:
    virCommandFree(cmd);
    VIR_FREE(networkstr);
    return ret;
}
Example #5
0
/*
 * virNetDevBandwidthUnplug:
 * @brname: from which bridge are we unplugging
 * @id: unique identifier (MUST be greater than 2)
 *
 * Remove QoS settings from bridge.
 *
 * Returns 0 on success, -1 otherwise.
 */
int
virNetDevBandwidthUnplug(const char *brname,
                         unsigned int id)
{
    int ret = -1;
    int cmd_ret = 0;
    virCommandPtr cmd = NULL;
    char *class_id = NULL;
    char *qdisc_id = NULL;
    char *filter_id = NULL;

    if (id <= 2) {
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid class ID %d"), id);
        return -1;
    }

    if (virAsprintf(&class_id, "1:%x", id) < 0 ||
        virAsprintf(&qdisc_id, "%x:", id) < 0 ||
        virAsprintf(&filter_id, "%u", id) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    cmd = virCommandNew(TC);
    virCommandAddArgList(cmd, "qdisc", "del", "dev", brname,
                         "handle", qdisc_id, NULL);

    /* Don't threat tc errors as fatal, but
     * try to remove as much as possible */
    if (virCommandRun(cmd, &cmd_ret) < 0)
        goto cleanup;

    virCommandFree(cmd);
    cmd = virCommandNew(TC);
    virCommandAddArgList(cmd, "filter", "del", "dev", brname,
                         "prio", filter_id, NULL);

    if (virCommandRun(cmd, &cmd_ret) < 0)
        goto cleanup;

    cmd = virCommandNew(TC);
    virCommandAddArgList(cmd, "class", "del", "dev", brname,
                         "classid", class_id, NULL);

    if (virCommandRun(cmd, &cmd_ret) < 0)
        goto cleanup;

    ret = 0;

cleanup:
    VIR_FREE(filter_id);
    VIR_FREE(qdisc_id);
    VIR_FREE(class_id);
    virCommandFree(cmd);
    return ret;
}
int
libxlDomainGetEmulatorType(const virDomainDef *def)
{
    int ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
    virCommandPtr cmd = NULL;
    char *output = NULL;

    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
        if (def->emulator) {
            if (!virFileExists(def->emulator))
                goto cleanup;

            cmd = virCommandNew(def->emulator);

            virCommandAddArgList(cmd, "-help", NULL);
            virCommandSetOutputBuffer(cmd, &output);

            if (virCommandRun(cmd, NULL) < 0)
                goto cleanup;

            if (strstr(output, LIBXL_QEMU_DM_STR))
                ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
        }
    }

 cleanup:
    VIR_FREE(output);
    virCommandFree(cmd);
    return ret;
}
Example #7
0
/**
 * virNetDevMidonetBindPort:
 * @ifname: the network interface name
 * @virtualport: the midonet specific fields
 *
 * Bind an interface to a Midonet virtual port
 *
 * Returns 0 in case of success or -1 in case of failure.
 */
int
virNetDevMidonetBindPort(const char *ifname,
                         virNetDevVPortProfilePtr virtualport)
{
    int ret = -1;
    virCommandPtr cmd = NULL;
    char virtportuuid[VIR_UUID_STRING_BUFLEN];

    virUUIDFormat(virtualport->interfaceID, virtportuuid);

    cmd = virCommandNew(MMCTL);

    virCommandAddArgList(cmd, "--bind-port", virtportuuid, ifname, NULL);

    if (virCommandRun(cmd, NULL) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to bind port %s to the virtual port %s"),
                       ifname, virtportuuid);
        goto cleanup;
    }

    ret = 0;
 cleanup:
    virCommandFree(cmd);
    return ret;
}
Example #8
0
/**
 * virNetDevBandwidthUpdateRate:
 * @ifname: interface name
 * @classid: ID of class to update
 * @new_rate: new rate
 *
 * This function updates the 'rate' attribute of HTB class.
 * It can be used whenever a new interface is plugged to a
 * bridge to adjust average throughput of non guaranteed
 * NICs.
 *
 * Returns 0 on success, -1 otherwise.
 */
int
virNetDevBandwidthUpdateRate(const char *ifname,
                             const char *class_id,
                             virNetDevBandwidthPtr bandwidth,
                             unsigned long long new_rate)
{
    int ret = -1;
    virCommandPtr cmd = NULL;
    char *rate = NULL;
    char *ceil = NULL;

    if (virAsprintf(&rate, "%llukbps", new_rate) < 0 ||
        virAsprintf(&ceil, "%llukbps", bandwidth->in->peak ?
                    bandwidth->in->peak :
                    bandwidth->in->average) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    cmd = virCommandNew(TC);
    virCommandAddArgList(cmd, "class", "change", "dev", ifname,
                         "classid", class_id, "htb", "rate", rate,
                         "ceil", ceil, NULL);

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;

cleanup:
    virCommandFree(cmd);
    VIR_FREE(rate);
    VIR_FREE(ceil);
    return ret;
}
Example #9
0
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;
    }

    virCommandAddArgList(cmd, "-s", "1,lpc", NULL);
    virCommandAddArg(cmd, "-l");
    virCommandAddArgFormat(cmd, "com%d,%s",
                           chr->target.port + 1, chr->source.data.file.path);

    return 0;
}
Example #10
0
virCommandPtr
virBhyveProcessBuildBhyveCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
                             virDomainObjPtr vm)
{
    /*
     * /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
     */
    virCommandPtr cmd = virCommandNew(BHYVE);

    /* CPUs */
    virCommandAddArg(cmd, "-c");
    virCommandAddArgFormat(cmd, "%d", vm->def->vcpus);

    /* Memory */
    virCommandAddArg(cmd, "-m");
    virCommandAddArgFormat(cmd, "%llu",
                           VIR_DIV_UP(vm->def->mem.max_balloon, 1024));

    /* Options */
    if (vm->def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_DOMAIN_FEATURE_STATE_ON)
        virCommandAddArg(cmd, "-A"); /* Create an ACPI table */
    if (vm->def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_DOMAIN_FEATURE_STATE_ON)
        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 */

    virCommandAddArgList(cmd, "-s", "0:0,hostbridge", NULL);
    /* Devices */
    if (bhyveBuildNetArgStr(vm->def, cmd) < 0)
        goto error;
    if (bhyveBuildDiskArgStr(vm->def, cmd) < 0)
        goto error;
    if (bhyveBuildConsoleArgStr(vm->def, cmd) < 0)
        goto error;
    virCommandAddArg(cmd, vm->def->name);

    return cmd;

 error:
    virCommandFree(cmd);
    return NULL;
}
Example #11
0
static int
virISCSIConnection(const char *portal,
                   const char *initiatoriqn,
                   const char *target,
                   const char **extraargv)
{
    int ret = -1;
    const char *const baseargv[] = {
        ISCSIADM,
        "--mode", "node",
        "--portal", portal,
        "--targetname", target,
        NULL
    };
    virCommandPtr cmd;
    char *ifacename = NULL;

    cmd = virCommandNewArgs(baseargv);
    virCommandAddArgSet(cmd, extraargv);

    if (initiatoriqn) {
        switch (virStorageBackendIQNFound(initiatoriqn, &ifacename)) {
        case IQN_FOUND:
            VIR_DEBUG("ifacename: '%s'", ifacename);
            break;
        case IQN_MISSING:
            if (virStorageBackendCreateIfaceIQN(initiatoriqn, &ifacename) != 0)
                goto cleanup;
            /*
             * iscsiadm doesn't let you send commands to the Interface IQN,
             * unless you've first issued a 'sendtargets' command to the
             * portal. Without the sendtargets all that is received is a
             * "iscsiadm: No records found"
             */
            if (virISCSIScanTargets(portal, NULL, NULL) < 0)
                goto cleanup;

            break;
        case IQN_ERROR:
        default:
            goto cleanup;
        }
        virCommandAddArgList(cmd, "--interface", ifacename, NULL);
    }

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    virCommandFree(cmd);
    VIR_FREE(ifacename);

    return ret;
}
Example #12
0
static int
virIpTablesOnceInit(void)
{
    virCommandPtr cmd;
    int status;

#if HAVE_FIREWALLD
    firewall_cmd_path = virFindFileInPath("firewall-cmd");
    if (!firewall_cmd_path) {
        VIR_INFO("firewall-cmd not found on system. "
                 "firewalld support disabled for iptables.");
    } else {
        cmd = virCommandNew(firewall_cmd_path);

        virCommandAddArgList(cmd, "--state", NULL);
        /* don't log non-zero status */
        if (virCommandRun(cmd, &status) < 0 || status != 0) {
            VIR_INFO("firewall-cmd found but disabled for iptables");
            VIR_FREE(firewall_cmd_path);
            firewall_cmd_path = NULL;
        } else {
            VIR_INFO("using firewalld for iptables commands");
        }
        virCommandFree(cmd);
    }

    if (firewall_cmd_path)
        return 0;

#endif

    cmd = virCommandNew(IPTABLES_PATH);
    virCommandAddArgList(cmd, "-w", "-L", "-n", NULL);
    /* don't log non-zero status */
    if (virCommandRun(cmd, &status) < 0 || status != 0) {
        VIR_INFO("xtables locking not supported by your iptables");
    } else {
        VIR_INFO("using xtables locking for iptables");
        iptables_supports_xlock = true;
    }
    virCommandFree(cmd);
    return 0;
}
Example #13
0
/*
 * load (add) a profile. Will create one if necessary
 */
static int
load_profile(virSecurityManagerPtr mgr,
             const char *profile,
             virDomainDefPtr def,
             const char *fn,
             bool append)
{
    int rc = -1;
    bool create = true;
    char *xml = NULL;
    virCommandPtr cmd = NULL;
    const char *probe = virSecurityManagerGetAllowDiskFormatProbing(mgr)
        ? "1" : "0";

    xml = virDomainDefFormat(def, VIR_DOMAIN_XML_SECURE);
    if (!xml)
        goto cleanup;

    if (profile_status_file(profile) >= 0)
        create = false;

    cmd = virCommandNewArgList(VIRT_AA_HELPER, "-p", probe,
                               create ? "-c" : "-r",
                               "-u", profile, NULL);
    if (!create && fn) {
        if (append) {
            virCommandAddArgList(cmd, "-F", fn, NULL);
        } else {
            virCommandAddArgList(cmd, "-f", fn, NULL);
        }
    }

    virCommandSetInputBuffer(cmd, xml);
    rc = virCommandRun(cmd, NULL);

 cleanup:
    VIR_FREE(xml);
    virCommandFree(cmd);

    return rc;
}
static int
virStorageBackendISCSIConnection(const char *portal,
                                 const char *initiatoriqn,
                                 const char *target,
                                 const char **extraargv)
{
    int ret = -1;
    const char *const baseargv[] = {
        ISCSIADM,
        "--mode", "node",
        "--portal", portal,
        "--targetname", target,
        NULL
    };
    virCommandPtr cmd;
    char *ifacename = NULL;

    cmd = virCommandNewArgs(baseargv);
    virCommandAddArgSet(cmd, extraargv);

    if (initiatoriqn) {
        switch (virStorageBackendIQNFound(initiatoriqn, &ifacename)) {
        case IQN_FOUND:
            VIR_DEBUG("ifacename: '%s'", ifacename);
            break;
        case IQN_MISSING:
            if (virStorageBackendCreateIfaceIQN(initiatoriqn,
                                                &ifacename) != 0) {
                goto cleanup;
            }
            break;
        case IQN_ERROR:
        default:
            goto cleanup;
        }
        virCommandAddArgList(cmd, "--interface", ifacename, NULL);
    }

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;

cleanup:
    virCommandFree(cmd);
    VIR_FREE(ifacename);

    return ret;
}
Example #15
0
int
qemuCapsProbeCPUModels(const char *qemu,
                       virBitmapPtr qemuCaps,
                       const char *arch,
                       unsigned int *count,
                       const char ***cpus)
{
    char *output = NULL;
    int ret = -1;
    qemuCapsParseCPUModels parse;
    virCommandPtr cmd;

    if (count)
        *count = 0;
    if (cpus)
        *cpus = NULL;

    if (STREQ(arch, "i686") || STREQ(arch, "x86_64"))
        parse = qemuCapsParseX86Models;
    else if (STREQ(arch, "ppc64"))
        parse = qemuCapsParsePPCModels;
    else {
        VIR_DEBUG("don't know how to parse %s CPU models", arch);
        return 0;
    }

    cmd = qemuCapsProbeCommand(qemu, qemuCaps);
    virCommandAddArgList(cmd, "-cpu", "?", NULL);
    virCommandSetOutputBuffer(cmd, &output);

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    if (parse(output, count, cpus) < 0)
        goto cleanup;

    ret = 0;

cleanup:
    VIR_FREE(output);
    virCommandFree(cmd);

    return ret;
}
Example #16
0
int
qemuCapsProbeMachineTypes(const char *binary,
                          virBitmapPtr qemuCaps,
                          virCapsGuestMachinePtr **machines,
                          int *nmachines)
{
    char *output;
    int ret = -1;
    virCommandPtr cmd;
    int status;

    /* Make sure the binary we are about to try exec'ing exists.
     * Technically we could catch the exec() failure, but that's
     * in a sub-process so it's hard to feed back a useful error.
     */
    if (!virFileIsExecutable(binary)) {
        virReportSystemError(errno, _("Cannot find QEMU binary %s"), binary);
        return -1;
    }

    cmd = qemuCapsProbeCommand(binary, qemuCaps);
    virCommandAddArgList(cmd, "-M", "?", NULL);
    virCommandSetOutputBuffer(cmd, &output);

    /* Ignore failure from older qemu that did not understand '-M ?'.  */
    if (virCommandRun(cmd, &status) < 0)
        goto cleanup;

    if (qemuCapsParseMachineTypesStr(output, machines, nmachines) < 0)
        goto cleanup;

    ret = 0;

cleanup:
    VIR_FREE(output);
    virCommandFree(cmd);

    return ret;
}
Example #17
0
static int
virEbTablesOnceInit(void)
{
    firewall_cmd_path = virFindFileInPath("firewall-cmd");
    if (!firewall_cmd_path) {
        VIR_INFO("firewall-cmd not found on system. "
                 "firewalld support disabled for ebtables.");
    } else {
        virCommandPtr cmd = virCommandNew(firewall_cmd_path);
        int status;

        virCommandAddArgList(cmd, "--state", NULL);
        if (virCommandRun(cmd, &status) < 0 || status != 0) {
            VIR_INFO("firewall-cmd found but disabled for ebtables");
            VIR_FREE(firewall_cmd_path);
            firewall_cmd_path = NULL;
        } else {
            VIR_INFO("using firewalld for ebtables commands");
        }
        virCommandFree(cmd);
    }
    return 0;
}
Example #18
0
/*
 * qemuTPMEmulatorStop
 * @swtpmStateDir: A directory where the socket is located
 * @shortName: short and unique name of the domain
 *
 * Gracefully stop the swptm
 */
static void
qemuTPMEmulatorStop(const char *swtpmStateDir,
                    const char *shortName)
{
    virCommandPtr cmd;
    char *pathname;
    char *errbuf = NULL;

    if (qemuTPMEmulatorInit() < 0)
        return;

    if (!(pathname = qemuTPMCreateEmulatorSocket(swtpmStateDir, shortName)))
        return;

    if (!virFileExists(pathname))
        goto cleanup;

    cmd = virCommandNew(swtpm_ioctl);
    if (!cmd)
        goto cleanup;

    virCommandAddArgList(cmd, "--unix", pathname, "-s", NULL);

    virCommandSetErrorBuffer(cmd, &errbuf);

    ignore_value(virCommandRun(cmd, NULL));

    virCommandFree(cmd);

    /* clean up the socket */
    unlink(pathname);

 cleanup:
    VIR_FREE(pathname);
    VIR_FREE(errbuf);
}
Example #19
0
/**
 * virNetDevOpenvswitchAddPort:
 * @brname: the bridge name
 * @ifname: the network interface name
 * @macaddr: the mac address of the virtual interface
 * @ovsport: the ovs specific fields
 *
 * Add an interface to the OVS bridge
 *
 * Returns 0 in case of success or -1 in case of failure.
 */
int virNetDevOpenvswitchAddPort(const char *brname, const char *ifname,
                                   const unsigned char *macaddr,
                                   virNetDevVPortProfilePtr ovsport)
{
    int ret = -1;
    virCommandPtr cmd = NULL;
    char macaddrstr[VIR_MAC_STRING_BUFLEN];
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    char *attachedmac_ex_id = NULL;
    char *ifaceid_ex_id = NULL;
    char *profile_ex_id = NULL;

    virMacAddrFormat(macaddr, macaddrstr);
    virUUIDFormat(ovsport->u.openvswitch.interfaceID, uuidstr);

    if (virAsprintf(&attachedmac_ex_id, "external-ids:attached-mac=\"%s\"",
                    macaddrstr) < 0)
        goto cleanup;
    if (virAsprintf(&ifaceid_ex_id, "external-ids:iface-id=\"%s\"",
                    uuidstr) < 0)
        goto cleanup;
    if (ovsport->u.openvswitch.profileID[0] != '\0') {
        if (virAsprintf(&profile_ex_id, "external-ids:port-profile=\"%s\"",
                        ovsport->u.openvswitch.profileID) < 0)
            goto cleanup;
    }

    cmd = virCommandNew(OVSVSCTL);
    if (ovsport->u.openvswitch.profileID[0] == '\0') {
        virCommandAddArgList(cmd, "--", "--may-exist", "add-port",
                        brname, ifname,
                        "--", "set", "Interface", ifname, attachedmac_ex_id,
                        "--", "set", "Interface", ifname, ifaceid_ex_id,
                        "--", "set", "Interface", ifname,
                        "external-ids:iface-status=active",
                        NULL);
    } else {
        virCommandAddArgList(cmd, "--", "--may-exist", "add-port",
                        brname, ifname,
                        "--", "set", "Interface", ifname, attachedmac_ex_id,
                        "--", "set", "Interface", ifname, ifaceid_ex_id,
                        "--", "set", "Interface", ifname, profile_ex_id,
                        "--", "set", "Interface", ifname,
                        "external-ids:iface-status=active",
                        NULL);
    }

    if (virCommandRun(cmd, NULL) < 0) {
        virReportSystemError(VIR_ERR_INTERNAL_ERROR,
                             _("Unable to add port %s to OVS bridge %s"),
                             ifname, brname);
        goto cleanup;
    }
    ret = 0;

    cleanup:
        VIR_FREE(attachedmac_ex_id);
        VIR_FREE(ifaceid_ex_id);
        VIR_FREE(profile_ex_id);
        virCommandFree(cmd);
        return ret;
}
Example #20
0
/**
 * virNetDevOpenvswitchAddPort:
 * @brname: the bridge name
 * @ifname: the network interface name
 * @macaddr: the mac address of the virtual interface
 * @vmuuid: the Domain UUID that has this interface
 * @ovsport: the ovs specific fields
 *
 * Add an interface to the OVS bridge
 *
 * Returns 0 in case of success or -1 in case of failure.
 */
int virNetDevOpenvswitchAddPort(const char *brname, const char *ifname,
                                   const virMacAddr *macaddr,
                                   const unsigned char *vmuuid,
                                   virNetDevVPortProfilePtr ovsport,
                                   virNetDevVlanPtr virtVlan)
{
    int ret = -1;
    size_t i = 0;
    virCommandPtr cmd = NULL;
    char macaddrstr[VIR_MAC_STRING_BUFLEN];
    char ifuuidstr[VIR_UUID_STRING_BUFLEN];
    char vmuuidstr[VIR_UUID_STRING_BUFLEN];
    char *attachedmac_ex_id = NULL;
    char *ifaceid_ex_id = NULL;
    char *profile_ex_id = NULL;
    char *vmid_ex_id = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virMacAddrFormat(macaddr, macaddrstr);
    virUUIDFormat(ovsport->interfaceID, ifuuidstr);
    virUUIDFormat(vmuuid, vmuuidstr);

    if (virAsprintf(&attachedmac_ex_id, "external-ids:attached-mac=\"%s\"",
                    macaddrstr) < 0)
        goto cleanup;
    if (virAsprintf(&ifaceid_ex_id, "external-ids:iface-id=\"%s\"",
                    ifuuidstr) < 0)
        goto cleanup;
    if (virAsprintf(&vmid_ex_id, "external-ids:vm-id=\"%s\"",
                    vmuuidstr) < 0)
        goto cleanup;
    if (ovsport->profileID[0] != '\0') {
        if (virAsprintf(&profile_ex_id, "external-ids:port-profile=\"%s\"",
                        ovsport->profileID) < 0)
            goto cleanup;
    }

    cmd = virCommandNew(OVSVSCTL);

    virCommandAddArgList(cmd, "--timeout=5", "--", "--if-exists", "del-port",
                         ifname, "--", "add-port", brname, ifname, NULL);

    if (virtVlan && virtVlan->nTags > 0) {

        switch (virtVlan->nativeMode) {
        case VIR_NATIVE_VLAN_MODE_TAGGED:
            virCommandAddArg(cmd, "vlan_mode=native-tagged");
            virCommandAddArgFormat(cmd, "tag=%d", virtVlan->nativeTag);
            break;
        case VIR_NATIVE_VLAN_MODE_UNTAGGED:
            virCommandAddArg(cmd, "vlan_mode=native-untagged");
            virCommandAddArgFormat(cmd, "tag=%d", virtVlan->nativeTag);
            break;
        case VIR_NATIVE_VLAN_MODE_DEFAULT:
        default:
            break;
        }

        if (virtVlan->trunk) {
            virBufferAddLit(&buf, "trunk=");

            /*
             * Trunk ports have at least one VLAN. Do the first one
             * outside the "for" loop so we can put a "," at the
             * start of the for loop if there are more than one VLANs
             * on this trunk port.
             */
            virBufferAsprintf(&buf, "%d", virtVlan->tag[i]);

            for (i = 1; i < virtVlan->nTags; i++) {
                virBufferAddLit(&buf, ",");
                virBufferAsprintf(&buf, "%d", virtVlan->tag[i]);
            }

            if (virBufferCheckError(&buf) < 0)
                goto cleanup;
            virCommandAddArg(cmd, virBufferCurrentContent(&buf));
        } else if (virtVlan->nTags) {
            virCommandAddArgFormat(cmd, "tag=%d", virtVlan->tag[0]);
        }
    }

    if (ovsport->profileID[0] == '\0') {
        virCommandAddArgList(cmd,
                        "--", "set", "Interface", ifname, attachedmac_ex_id,
                        "--", "set", "Interface", ifname, ifaceid_ex_id,
                        "--", "set", "Interface", ifname, vmid_ex_id,
                        "--", "set", "Interface", ifname,
                        "external-ids:iface-status=active",
                        NULL);
    } else {
        virCommandAddArgList(cmd,
                        "--", "set", "Interface", ifname, attachedmac_ex_id,
                        "--", "set", "Interface", ifname, ifaceid_ex_id,
                        "--", "set", "Interface", ifname, vmid_ex_id,
                        "--", "set", "Interface", ifname, profile_ex_id,
                        "--", "set", "Interface", ifname,
                        "external-ids:iface-status=active",
                        NULL);
    }

    if (virCommandRun(cmd, NULL) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to add port %s to OVS bridge %s"),
                       ifname, brname);
        goto cleanup;
    }

    ret = 0;
 cleanup:
    virBufferFreeAndReset(&buf);
    VIR_FREE(attachedmac_ex_id);
    VIR_FREE(ifaceid_ex_id);
    VIR_FREE(vmid_ex_id);
    VIR_FREE(profile_ex_id);
    virCommandFree(cmd);
    return ret;
}
Example #21
0
/*
 * virNetDevBandwidthPlug:
 * @brname: name of the bridge
 * @net_bandwidth: QoS settings on @brname
 * @ifmac: MAC of interface
 * @bandwidth: QoS settings for interface
 * @id: unique ID (MUST be greater than 2)
 *
 * Set bridge part of interface QoS settings, e.g. guaranteed
 * bandwidth.  @id is an unique ID (among @brname) from which
 * other identifiers for class, qdisc and filter are derived.
 * However, two classes were already set up (by
 * virNetDevBandwidthSet). That's why this @id MUST be greater
 * than 2. You may want to keep passed @id, as it is used later
 * by virNetDevBandwidthUnplug.
 *
 * Returns:
 * 0 if QoS set successfully
 * -1 otherwise.
 */
int
virNetDevBandwidthPlug(const char *brname,
                       virNetDevBandwidthPtr net_bandwidth,
                       const virMacAddrPtr ifmac_ptr,
                       virNetDevBandwidthPtr bandwidth,
                       unsigned int id)
{
    int ret = -1;
    virCommandPtr cmd = NULL;
    char *class_id = NULL;
    char *qdisc_id = NULL;
    char *filter_id = NULL;
    char *floor = NULL;
    char *ceil = NULL;
    unsigned char ifmac[VIR_MAC_BUFLEN];
    char ifmacStr[VIR_MAC_STRING_BUFLEN];
    char *mac[2] = {NULL, NULL};

    if (id <= 2) {
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid class ID %d"), id);
        return -1;
    }

    virMacAddrGetRaw(ifmac_ptr, ifmac);
    virMacAddrFormat(ifmac_ptr, ifmacStr);

    if (!net_bandwidth || !net_bandwidth->in) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Bridge '%s' has no QoS set, therefore "
                         "unable to set 'floor' on '%s'"),
                       brname, ifmacStr);
        return -1;
    }

    if (virAsprintf(&class_id, "1:%x", id) < 0 ||
        virAsprintf(&qdisc_id, "%x:", id) < 0 ||
        virAsprintf(&filter_id, "%u", id) < 0 ||
        virAsprintf(&mac[0], "0x%02x%02x%02x%02x", ifmac[2],
                    ifmac[3], ifmac[4], ifmac[5]) < 0 ||
        virAsprintf(&mac[1], "0x%02x%02x", ifmac[0], ifmac[1]) < 0 ||
        virAsprintf(&floor, "%llukbps", bandwidth->in->floor) < 0 ||
        virAsprintf(&ceil, "%llukbps", net_bandwidth->in->peak ?
                    net_bandwidth->in->peak :
                    net_bandwidth->in->average) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    cmd = virCommandNew(TC);
    virCommandAddArgList(cmd, "class", "add", "dev", brname, "parent", "1:1",
                         "classid", class_id, "htb", "rate", floor,
                         "ceil", ceil, NULL);

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    virCommandFree(cmd);
    cmd = virCommandNew(TC);
    virCommandAddArgList(cmd, "qdisc", "add", "dev", brname, "parent",
                         class_id, "handle", qdisc_id, "sfq", "perturb",
                         "10", NULL);

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    virCommandFree(cmd);
    cmd = virCommandNew(TC);
    /* Okay, this not nice. But since libvirt does not know anything about
     * interface IP address(es), and tc fw filter simply refuse to use ebtables
     * marks, we need to use u32 selector to match MAC address.
     * If libvirt will ever know something, remove this FIXME
     */
    virCommandAddArgList(cmd, "filter", "add", "dev", brname, "protocol", "ip",
                         "prio", filter_id, "u32",
                         "match", "u16", "0x0800", "0xffff", "at", "-2",
                         "match", "u32", mac[0], "0xffffffff", "at", "-12",
                         "match", "u16", mac[1], "0xffff", "at", "-14",
                         "flowid", class_id, NULL);

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;

cleanup:
    VIR_FREE(mac[1]);
    VIR_FREE(mac[0]);
    VIR_FREE(ceil);
    VIR_FREE(floor);
    VIR_FREE(filter_id);
    VIR_FREE(qdisc_id);
    VIR_FREE(class_id);
    virCommandFree(cmd);
    return ret;
}
Example #22
0
/**
 * virNetDevVethCreate:
 * @veth1: pointer to name for parent end of veth pair
 * @veth2: pointer to return name for container end of veth pair
 *
 * Creates a veth device pair using the ip command:
 * ip link add veth1 type veth peer name veth2
 * If veth1 points to NULL on entry, it will be a valid interface on
 * return.  veth2 should point to NULL on entry.
 *
 * NOTE: If veth1 and veth2 names are not specified, ip will auto assign
 *       names.  There seems to be two problems here -
 *       1) There doesn't seem to be a way to determine the names of the
 *          devices that it creates.  They show up in ip link show and
 *          under /sys/class/net/ however there is no guarantee that they
 *          are the devices that this process just created.
 *       2) Once one of the veth devices is moved to another namespace, it
 *          is no longer visible in the parent namespace.  This seems to
 *          confuse the name assignment causing it to fail with File exists.
 *       Because of these issues, this function currently allocates names
 *       prior to using the ip command, and returns any allocated names
 *       to the caller.
 *
 * Returns 0 on success or -1 in case of error
 */
int virNetDevVethCreate(char** veth1, char** veth2)
{
    int ret = -1;
    char *veth1auto = NULL;
    char *veth2auto = NULL;
    int vethNum = 0;
    virCommandPtr cmd = NULL;
    size_t i;

    /*
     * We might race with other containers, but this is reasonably
     * unlikely, so don't do too many retries for device creation
     */
    if (virNetDevVethCreateMutexInitialize() < 0)
        return -1;

    virMutexLock(&virNetDevVethCreateMutex);
#define MAX_VETH_RETRIES 10

    for (i = 0; i < MAX_VETH_RETRIES; i++) {
        int status;
        if (!*veth1) {
            int veth1num;
            if ((veth1num = virNetDevVethGetFreeNum(vethNum)) < 0)
                goto cleanup;

            if (virAsprintf(&veth1auto, "vnet%d", veth1num) < 0)
                goto cleanup;
            vethNum = veth1num + 1;
        }
        if (!*veth2) {
            int veth2num;
            if ((veth2num = virNetDevVethGetFreeNum(vethNum)) < 0)
                goto cleanup;

            if (virAsprintf(&veth2auto, "vnet%d", veth2num) < 0)
                goto cleanup;
            vethNum = veth2num + 1;
        }

        cmd = virCommandNew("ip");
        virCommandAddArgList(cmd, "link", "add",
                             *veth1 ? *veth1 : veth1auto,
                             "type", "veth", "peer", "name",
                             *veth2 ? *veth2 : veth2auto,
                             NULL);

        if (virCommandRun(cmd, &status) < 0)
            goto cleanup;

        if (status == 0) {
            if (veth1auto) {
                *veth1 = veth1auto;
                veth1auto = NULL;
            }
            if (veth2auto) {
                *veth2 = veth2auto;
                veth2auto = NULL;
            }
            VIR_DEBUG("Create Host: %s guest: %s", *veth1, *veth2);
            ret = 0;
            goto cleanup;
        }

        VIR_DEBUG("Failed to create veth host: %s guest: %s: %d",
                  *veth1 ? *veth1 : veth1auto,
                  *veth1 ? *veth1 : veth1auto,
                  status);
        VIR_FREE(veth1auto);
        VIR_FREE(veth2auto);
        virCommandFree(cmd);
        cmd = NULL;
    }

    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Failed to allocate free veth pair after %d attempts"),
                   MAX_VETH_RETRIES);

cleanup:
    virMutexUnlock(&virNetDevVethCreateMutex);
    virCommandFree(cmd);
    VIR_FREE(veth1auto);
    VIR_FREE(veth2auto);
    return ret;
}
Example #23
0
/**
 * virNetDevBandwidthSet:
 * @ifname: on which interface
 * @bandwidth: rates to set (may be NULL)
 * @hierarchical_class: whether to create hierarchical class
 *
 * This function enables QoS on specified interface
 * and set given traffic limits for both, incoming
 * and outgoing traffic. Any previous setting get
 * overwritten. If @hierarchical_class is TRUE, create
 * hierarchical class. It is used to guarantee minimal
 * throughput ('floor' attribute in NIC).
 *
 * Return 0 on success, -1 otherwise.
 */
int
virNetDevBandwidthSet(const char *ifname,
                      virNetDevBandwidthPtr bandwidth,
                      bool hierarchical_class)
{
    int ret = -1;
    virCommandPtr cmd = NULL;
    char *average = NULL;
    char *peak = NULL;
    char *burst = NULL;

    if (!bandwidth) {
        /* nothing to be enabled */
        ret = 0;
        goto cleanup;
    }

    virNetDevBandwidthClear(ifname);

    if (bandwidth->in && bandwidth->in->average) {
        if (virAsprintf(&average, "%llukbps", bandwidth->in->average) < 0)
            goto cleanup;
        if (bandwidth->in->peak &&
            (virAsprintf(&peak, "%llukbps", bandwidth->in->peak) < 0))
            goto cleanup;
        if (bandwidth->in->burst &&
            (virAsprintf(&burst, "%llukb", bandwidth->in->burst) < 0))
            goto cleanup;

        cmd = virCommandNew(TC);
        virCommandAddArgList(cmd, "qdisc", "add", "dev", ifname, "root",
                             "handle", "1:", "htb", "default",
                             hierarchical_class ? "2" : "1", NULL);
        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;

        /* If we are creating a hierarchical class, all non guaranteed traffic
         * goes to the 1:2 class which will adjust 'rate' dynamically as NICs
         * with guaranteed throughput are plugged and unplugged. Class 1:1
         * exists so we don't exceed the maximum limit for the network. For each
         * NIC with guaranteed throughput a separate classid will be created.
         * NB '1:' is just a shorter notation of '1:0'.
         *
         * To get a picture how this works:
         *
         * +-----+     +---------+     +-----------+      +-----------+     +-----+
         * |     |     |  qdisc  |     | class 1:1 |      | class 1:2 |     |     |
         * | NIC |     | def 1:2 |     |   rate    |      |   rate    |     | sfq |
         * |     | --> |         | --> |   peak    | -+-> |   peak    | --> |     |
         * +-----+     +---------+     +-----------+  |   +-----------+     +-----+
         *                                            |
         *                                            |   +-----------+     +-----+
         *                                            |   | class 1:3 |     |     |
         *                                            |   |   rate    |     | sfq |
         *                                            +-> |   peak    | --> |     |
         *                                            |   +-----------+     +-----+
         *                                           ...
         *                                            |   +-----------+     +-----+
         *                                            |   | class 1:n |     |     |
         *                                            |   |   rate    |     | sfq |
         *                                            +-> |   peak    | --> |     |
         *                                                +-----------+     +-----+
         *
         * After the routing decision, when is it clear a packet is to be sent
         * via a particular NIC, it is sent to the root qdisc (queueing
         * discipline). In this case HTB (Hierarchical Token Bucket). It has
         * only one direct child class (with id 1:1) which shapes the overall
         * rate that is sent through the NIC.  This class has at least one child
         * (1:2) which is meant for all non-privileged (non guaranteed) traffic
         * from all domains. Then, for each interface with guaranteed
         * throughput, a separate class (1:n) is created. Imagine a class is a
         * box. Whenever a packet ends up in a class it is stored in this box
         * until the kernel sends it, then it is removed from box. Packets are
         * placed into boxes based on rules (filters) - e.g. depending on
         * destination IP/MAC address. If there is no rule to be applied, the
         * root qdisc has a default where such packets go (1:2 in this case).
         * Packets come in over and over again and boxes get filled more and
         * more. Imagine that kernel sends packets just once a second. So it
         * starts to traverse through this tree. It starts with the root qdisc
         * and through 1:1 it gets to 1:2. It sends packets up to 1:2's 'rate'.
         * Then it moves to 1:3 and again sends packets up to 1:3's 'rate'.  The
         * whole process is repeated until 1:n is processed. So now we have
         * ensured each class its guaranteed bandwidth. If the sum of sent data
         * doesn't exceed the 'rate' in 1:1 class, we can go further and send
         * more packets. The rest of available bandwidth is distributed to the
         * 1:2,1:3...1:n classes by ratio of their 'rate'. As soon as the root
         * 'rate' limit is reached or there are no more packets to send, we stop
         * sending and wait another second. Each class has an SFQ qdisc which
         * shuffles packets in boxes stochastically, so one sender cannot
         * starve others.
         *
         * Therefore, whenever we want to plug in a new guaranteed interface, we
         * need to create a new class and adjust the 'rate' of the 1:2 class.
         * When unplugging we do the exact opposite - remove the associated
         * class, and adjust the 'rate'.
         *
         * This description is rather long, but it is still a good idea to read
         * it before you dig into the code.
         */
        if (hierarchical_class) {
            virCommandFree(cmd);
            cmd = virCommandNew(TC);
            virCommandAddArgList(cmd, "class", "add", "dev", ifname, "parent",
                                 "1:", "classid", "1:1", "htb", "rate", average,
                                 "ceil", peak ? peak : average, NULL);
            if (virCommandRun(cmd, NULL) < 0)
                goto cleanup;
        }
        virCommandFree(cmd);
        cmd = virCommandNew(TC);
        virCommandAddArgList(cmd,"class", "add", "dev", ifname, "parent",
                             hierarchical_class ? "1:1" : "1:", "classid",
                             hierarchical_class ? "1:2" : "1:1", "htb",
                             "rate", average, NULL);

        if (peak)
            virCommandAddArgList(cmd, "ceil", peak, NULL);
        if (burst)
            virCommandAddArgList(cmd, "burst", burst, NULL);

        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;

        virCommandFree(cmd);
        cmd = virCommandNew(TC);
        virCommandAddArgList(cmd, "qdisc", "add", "dev", ifname, "parent",
                             hierarchical_class ? "1:2" : "1:1",
                             "handle", "2:", "sfq", "perturb",
                             "10", NULL);

        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;

        virCommandFree(cmd);
        cmd = virCommandNew(TC);
        virCommandAddArgList(cmd,"filter", "add", "dev", ifname, "parent",
                             "1:0", "protocol", "ip", "handle", "1", "fw",
                             "flowid", "1", NULL);

        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;

        VIR_FREE(average);
        VIR_FREE(peak);
        VIR_FREE(burst);
    }

    if (bandwidth->out) {
        if (virAsprintf(&average, "%llukbps", bandwidth->out->average) < 0)
            goto cleanup;
        if (virAsprintf(&burst, "%llukb", bandwidth->out->burst ?
                        bandwidth->out->burst : bandwidth->out->average) < 0)
            goto cleanup;

        virCommandFree(cmd);
        cmd = virCommandNew(TC);
            virCommandAddArgList(cmd, "qdisc", "add", "dev", ifname,
                                 "ingress", NULL);

        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;

        virCommandFree(cmd);
        cmd = virCommandNew(TC);
        virCommandAddArgList(cmd, "filter", "add", "dev", ifname, "parent",
                             "ffff:", "protocol", "ip", "u32", "match", "ip",
                             "src", "0.0.0.0/0", "police", "rate", average,
                             "burst", burst, "mtu", "64kb", "drop", "flowid",
                             ":1", NULL);

        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;
    }

    ret = 0;

cleanup:
    virCommandFree(cmd);
    VIR_FREE(average);
    VIR_FREE(peak);
    VIR_FREE(burst);
    return ret;
}
Example #24
0
static virCommandPtr
virLXCProcessBuildControllerCmd(virLXCDriverPtr driver,
                                virDomainObjPtr vm,
                                int nveths,
                                char **veths,
                                int *ttyFDs,
                                size_t nttyFDs,
                                int *files,
                                size_t nfiles,
                                int handshakefd)
{
    size_t i;
    char *filterstr;
    char *outputstr;
    virCommandPtr cmd;
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);

    cmd = virCommandNew(vm->def->emulator);

    /* The controller may call ip command, so we have to retain PATH. */
    virCommandAddEnvPassBlockSUID(cmd, "PATH", "/bin:/usr/bin");

    virCommandAddEnvFormat(cmd, "LIBVIRT_DEBUG=%d",
                           virLogGetDefaultPriority());

    if (virLogGetNbFilters() > 0) {
        filterstr = virLogGetFilters();
        if (!filterstr) {
            virReportOOMError();
            goto cleanup;
        }

        virCommandAddEnvPair(cmd, "LIBVIRT_LOG_FILTERS", filterstr);
        VIR_FREE(filterstr);
    }

    if (cfg->log_libvirtd) {
        if (virLogGetNbOutputs() > 0) {
            outputstr = virLogGetOutputs();
            if (!outputstr) {
                virReportOOMError();
                goto cleanup;
            }

            virCommandAddEnvPair(cmd, "LIBVIRT_LOG_OUTPUTS", outputstr);
            VIR_FREE(outputstr);
        }
    } else {
        virCommandAddEnvFormat(cmd,
                               "LIBVIRT_LOG_OUTPUTS=%d:stderr",
                               virLogGetDefaultPriority());
    }

    virCommandAddArgList(cmd, "--name", vm->def->name, NULL);
    for (i = 0; i < nttyFDs; i++) {
        virCommandAddArg(cmd, "--console");
        virCommandAddArgFormat(cmd, "%d", ttyFDs[i]);
        virCommandPassFD(cmd, ttyFDs[i], 0);
    }

    for (i = 0; i < nfiles; i++) {
        virCommandAddArg(cmd, "--passfd");
        virCommandAddArgFormat(cmd, "%d", files[i]);
        virCommandPassFD(cmd, files[i], 0);
    }

    virCommandAddArgPair(cmd, "--security",
                         virSecurityManagerGetModel(driver->securityManager));

    virCommandAddArg(cmd, "--handshake");
    virCommandAddArgFormat(cmd, "%d", handshakefd);
    virCommandAddArg(cmd, "--background");

    for (i = 0; i < nveths; i++) {
        virCommandAddArgList(cmd, "--veth", veths[i], NULL);
    }

    virCommandPassFD(cmd, handshakefd, 0);

    return cmd;
 cleanup:
    virCommandFree(cmd);
    virObjectUnref(cfg);
    return NULL;
}
Example #25
0
/* Masquerade all traffic coming from the network associated
 * with the bridge
 */
static int
iptablesForwardMasquerade(iptablesContext *ctx,
                          virSocketAddr *netaddr,
                          unsigned int prefix,
                          const char *physdev,
                          virSocketAddr *addrStart,
                          virSocketAddr *addrEnd,
                          unsigned int portStart,
                          unsigned int portEnd,
                          const char *protocol,
                          int action)
{
    int ret = -1;
    char *networkstr = NULL;
    char *addrStartStr = NULL;
    char *addrEndStr = NULL;
    char *portRangeStr = NULL;
    char *natRangeStr = NULL;
    virCommandPtr cmd = NULL;

    if (!(networkstr = iptablesFormatNetwork(netaddr, prefix)))
        return -1;

    if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) {
        /* Higher level code *should* guaranteee it's impossible to get here. */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Attempted to NAT '%s'. NAT is only supported for IPv4."),
                       networkstr);
        goto cleanup;
    }

    if (VIR_SOCKET_ADDR_IS_FAMILY(addrStart, AF_INET)) {
        if (!(addrStartStr = virSocketAddrFormat(addrStart)))
            goto cleanup;
        if (VIR_SOCKET_ADDR_IS_FAMILY(addrEnd, AF_INET)) {
            if (!(addrEndStr = virSocketAddrFormat(addrEnd)))
                goto cleanup;
        }
    }

    cmd = iptablesCommandNew(ctx->nat_postrouting, AF_INET, action);
    virCommandAddArgList(cmd, "--source", networkstr, NULL);

    if (protocol && protocol[0])
        virCommandAddArgList(cmd, "-p", protocol, NULL);

    virCommandAddArgList(cmd, "!", "--destination", networkstr, NULL);

    if (physdev && physdev[0])
        virCommandAddArgList(cmd, "--out-interface", physdev, NULL);

    if (protocol && protocol[0]) {
        if (portStart == 0 && portEnd == 0) {
            portStart = 1024;
            portEnd = 65535;
        }

        if (portStart < portEnd && portEnd < 65536) {
            if (virAsprintf(&portRangeStr, ":%u-%u", portStart, portEnd) < 0) {
                virReportOOMError();
                goto cleanup;
            }
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid port range '%u-%u'."),
                           portStart, portEnd);
        }
    }

    /* Use --jump SNAT if public addr is specified */
    if (addrStartStr && addrStartStr[0]) {
        int r = 0;

        if (addrEndStr && addrEndStr[0]) {
            r = virAsprintf(&natRangeStr, "%s-%s%s", addrStartStr, addrEndStr,
                            portRangeStr ? portRangeStr : "");
        } else {
            r = virAsprintf(&natRangeStr, "%s%s", addrStartStr,
                            portRangeStr ? portRangeStr : "");
        }

        if (r < 0) {
            virReportOOMError();
            goto cleanup;
        }

        virCommandAddArgList(cmd, "--jump", "SNAT",
                                  "--to-source", natRangeStr, NULL);
     } else {
         virCommandAddArgList(cmd, "--jump", "MASQUERADE", NULL);

         if (portRangeStr && portRangeStr[0])
             virCommandAddArgList(cmd, "--to-ports", &portRangeStr[1], NULL);
     }

    ret = virCommandRun(cmd, NULL);
cleanup:
    virCommandFree(cmd);
    VIR_FREE(networkstr);
    VIR_FREE(addrStartStr);
    VIR_FREE(addrEndStr);
    VIR_FREE(portRangeStr);
    VIR_FREE(natRangeStr);
    return ret;
}
Example #26
0
/*
 * qemuTPMEmulatorBuildCommand:
 *
 * @tpm: TPM definition
 * @vmname: The name of the VM
 * @vmuuid: The UUID of the VM
 * @privileged: whether we are running in privileged mode
 * @swtpm_user: The uid for the swtpm to run as (drop privileges to from root)
 * @swtpm_group: The gid for the swtpm to run as
 * @swtpmStateDir: the directory where swtpm writes the pid file and creates the
 *                 Unix socket
 * @shortName: the short name of the VM
 *
 * Create the virCommand use for starting the emulator
 * Do some initializations on the way, such as creation of storage
 * and emulator setup.
 */
static virCommandPtr
qemuTPMEmulatorBuildCommand(virDomainTPMDefPtr tpm,
                            const char *vmname,
                            const unsigned char *vmuuid,
                            bool privileged,
                            uid_t swtpm_user,
                            gid_t swtpm_group,
                            const char *swtpmStateDir,
                            const char *shortName)
{
    virCommandPtr cmd = NULL;
    bool created = false;
    char *pidfile;

    if (qemuTPMCreateEmulatorStorage(tpm->data.emulator.storagepath,
                                     &created, swtpm_user, swtpm_group) < 0)
        return NULL;

    if (created &&
        qemuTPMEmulatorRunSetup(tpm->data.emulator.storagepath, vmname, vmuuid,
                                privileged, swtpm_user, swtpm_group,
                                tpm->data.emulator.logfile, tpm->version) < 0)
        goto error;

    unlink(tpm->data.emulator.source.data.nix.path);

    cmd = virCommandNew(swtpm_path);
    if (!cmd)
        goto error;

    virCommandClearCaps(cmd);

    virCommandAddArgList(cmd, "socket", "--daemon", "--ctrl", NULL);
    virCommandAddArgFormat(cmd, "type=unixio,path=%s,mode=0600",
                           tpm->data.emulator.source.data.nix.path);

    virCommandAddArg(cmd, "--tpmstate");
    virCommandAddArgFormat(cmd, "dir=%s,mode=0600",
                           tpm->data.emulator.storagepath);

    virCommandAddArg(cmd, "--log");
    virCommandAddArgFormat(cmd, "file=%s", tpm->data.emulator.logfile);

    virCommandSetUID(cmd, swtpm_user);
    virCommandSetGID(cmd, swtpm_group);

    switch (tpm->version) {
    case VIR_DOMAIN_TPM_VERSION_1_2:
        break;
    case VIR_DOMAIN_TPM_VERSION_2_0:
        virCommandAddArg(cmd, "--tpm2");
        break;
    case VIR_DOMAIN_TPM_VERSION_DEFAULT:
    case VIR_DOMAIN_TPM_VERSION_LAST:
        break;
    }

    if (!(pidfile = qemuTPMEmulatorCreatePidFilename(swtpmStateDir, shortName)))
        goto error;

    virCommandAddArg(cmd, "--pid");
    virCommandAddArgFormat(cmd, "file=%s", pidfile);
    VIR_FREE(pidfile);

    return cmd;

 error:
    if (created)
        qemuTPMDeleteEmulatorStorage(tpm);

    virCommandFree(cmd);

    return NULL;
}
Example #27
0
/*
 * qemuTPMEmulatorRunSetup
 *
 * @storagepath: path to the directory for TPM state
 * @vmname: the name of the VM
 * @vmuuid: the UUID of the VM
 * @privileged: whether we are running in privileged mode
 * @swtpm_user: The userid to switch to when setting up the TPM;
 *              typically this should be the uid of 'tss' or 'root'
 * @swtpm_group: The group id to switch to
 * @logfile: The file to write the log into; it must be writable
 *           for the user given by userid or 'tss'
 * @tpmversion: The version of the TPM, either a TPM 1.2 or TPM 2
 *
 * Setup the external swtpm by creating endorsement key and
 * certificates for it.
 */
static int
qemuTPMEmulatorRunSetup(const char *storagepath,
                        const char *vmname,
                        const unsigned char *vmuuid,
                        bool privileged,
                        uid_t swtpm_user,
                        gid_t swtpm_group,
                        const char *logfile,
                        const virDomainTPMVersion tpmversion)
{
    virCommandPtr cmd = NULL;
    int exitstatus;
    int ret = -1;
    char uuid[VIR_UUID_STRING_BUFLEN];
    char *vmid = NULL;

    if (!privileged && tpmversion == VIR_DOMAIN_TPM_VERSION_1_2)
        return virFileWriteStr(logfile,
                               _("Did not create EK and certificates since "
                                 "this requires privileged mode for a "
                                 "TPM 1.2\n"), 0600);

    cmd = virCommandNew(swtpm_setup);
    if (!cmd)
        goto cleanup;

    virUUIDFormat(vmuuid, uuid);
    if (virAsprintf(&vmid, "%s:%s", vmname, uuid) < 0)
        goto cleanup;

    virCommandSetUID(cmd, swtpm_user);
    virCommandSetGID(cmd, swtpm_group);

    switch (tpmversion) {
    case VIR_DOMAIN_TPM_VERSION_1_2:
        break;
    case VIR_DOMAIN_TPM_VERSION_2_0:
        virCommandAddArgList(cmd, "--tpm2", NULL);
        break;
    case VIR_DOMAIN_TPM_VERSION_DEFAULT:
    case VIR_DOMAIN_TPM_VERSION_LAST:
        break;
    }


    virCommandAddArgList(cmd,
                         "--tpm-state", storagepath,
                         "--vmid", vmid,
                         "--logfile", logfile,
                         "--createek",
                         "--create-ek-cert",
                         "--create-platform-cert",
                         "--lock-nvram",
                         "--not-overwrite",
                         NULL);

    virCommandClearCaps(cmd);

    if (virCommandRun(cmd, &exitstatus) < 0 || exitstatus != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not run '%s'. exitstatus: %d; "
                         "Check error log '%s' for details."),
                          swtpm_setup, exitstatus, logfile);
        goto cleanup;
    }

    ret = 0;

 cleanup:
    VIR_FREE(vmid);
    virCommandFree(cmd);

    return ret;
}
Example #28
0
static int
virStorageBackendZFSCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                              virStoragePoolObjPtr pool,
                              virStorageVolDefPtr vol)
{
    virCommandPtr cmd = NULL;
    int ret = -1;
    int volmode_needed = -1;

    if (vol->target.format != VIR_STORAGE_FILE_RAW) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("only RAW volumes are supported by this storage pool"));
        return -1;
    }

    if (vol->target.encryption != NULL) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("storage pool does not support encrypted "
                               "volumes"));
        return -1;
    }

    vol->type = VIR_STORAGE_VOL_BLOCK;

    VIR_FREE(vol->target.path);
    if (virAsprintf(&vol->target.path, "%s/%s",
                    pool->def->target.path, vol->name) == -1)
        return -1;

    if (VIR_STRDUP(vol->key, vol->target.path) < 0)
        goto cleanup;

    volmode_needed = virStorageBackendZFSVolModeNeeded();
    if (volmode_needed < 0)
        goto cleanup;
    /**
     * $ zfs create -o volmode=dev -V 10240K test/volname
     *
     * -o volmode=dev -- we want to get volumes exposed as cdev
     *                   devices. If we don't specify that zfs
     *                   will lookup vfs.zfs.vol.mode sysctl value
     * -V -- tells to create a volume with the specified size
     */
    cmd = virCommandNewArgList(ZFS, "create", NULL);
    if (volmode_needed)
        virCommandAddArgList(cmd, "-o", "volmode=dev", NULL);
    virCommandAddArg(cmd, "-V");
    virCommandAddArgFormat(cmd, "%lluK",
                           VIR_DIV_UP(vol->target.capacity, 1024));
    virCommandAddArgFormat(cmd, "%s/%s",
                           pool->def->source.name, vol->name);

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    if (virStorageBackendZFSFindVols(pool, vol) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    virCommandFree(cmd);
    return ret;

}
Example #29
0
static int
bhyveBuildNetArgStr(const virDomainDef *def, virCommandPtr cmd)
{
    virDomainNetDefPtr net = NULL;
    char *brname = NULL;
    char *realifname = NULL;
    int *tapfd = NULL;

    if (def->nnets != 1) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("domain should have one and only one net defined"));
        return -1;
    }

    net = def->nets[0];

    if (net) {
        int actualType = virDomainNetGetActualType(net);

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

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

        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) {
            VIR_FREE(net->ifname);
            VIR_FREE(brname);
            return -1;
        }
    }

    realifname = virBhyveTapGetRealDeviceName(net->ifname);

    if (realifname == NULL) {
        VIR_FREE(net->ifname);
        VIR_FREE(brname);
        return -1;
    }

    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) {
        VIR_FREE(net->ifname);
        VIR_FREE(brname);
        return -1;
    }

    virCommandAddArgList(cmd, "-s", "0:0,hostbridge", NULL);
    virCommandAddArg(cmd, "-s");
    virCommandAddArgFormat(cmd, "1:0,virtio-net,%s", realifname);

    return 0;
}