Пример #1
0
/**
 * ifaceGetNthParent
 *
 * @ifindex : the index of the interface or -1 if ifname is given
 * @ifname : the name of the interface; ignored if ifindex is valid
 * @nthParent : the nth parent interface to get
 * @parent_ifindex : pointer to int
 * @parent_ifname : pointer to buffer of size IFNAMSIZ
 * @nth : the nth parent that is actually returned; if for example eth0.100
 *        was given and the 100th parent is to be returned, then eth0 will
 *        most likely be returned with nth set to 1 since the chain does
 *        not have more interfaces
 *
 * Get the nth parent interface of the given interface. 0 is the interface
 * itself.
 *
 * Return 0 on success, != 0 otherwise
 */
static int
ifaceGetNthParent(int ifindex, const char *ifname, unsigned int nthParent,
                  int *parent_ifindex, char *parent_ifname,
                  unsigned int *nth)
{
    int rc;
    struct nlattr *tb[IFLA_MAX + 1] = { NULL, };
    char *recvbuf = NULL;
    bool end = false;
    unsigned int i = 0;

    *nth = 0;

    if (ifindex <= 0 && ifaceGetIndex(true, ifname, &ifindex) != 0)
        return 1;

    while (!end && i <= nthParent) {
        rc = link_dump(true, ifname, ifindex, tb, &recvbuf);
        if (rc)
            break;

        if (tb[IFLA_IFNAME]) {
            if (!virStrcpy(parent_ifname, (char*)RTA_DATA(tb[IFLA_IFNAME]),
                           IFNAMSIZ)) {
                macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("buffer for root interface name is too small"));
                VIR_FREE(recvbuf);
                return 1;
            }
            *parent_ifindex = ifindex;
        }

        if (tb[IFLA_LINK]) {
            ifindex = *(int *)RTA_DATA(tb[IFLA_LINK]);
            ifname = NULL;
        } else
            end = true;

        VIR_FREE(recvbuf);

        i++;
    }

    if (nth)
        *nth = i - 1;

    return rc;
}
Пример #2
0
int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
                                    const virDomainNetDefPtr net)
{
    const char *drvname = EBIPTABLES_DRIVER_ID;
    int ifindex;
    virNWFilterTechDriverPtr techdriver;

    techdriver = virNWFilterTechDriverForName(drvname);
    if (!techdriver) {
        virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Could not get access to ACL tech "
                               "driver '%s'"),
                               drvname);
        return 1;
    }

    /* don't tear anything while the address is being learned */
    if (ifaceGetIndex(true, net->ifname, &ifindex) == 0 &&
        virNWFilterLookupLearnReq(ifindex) != NULL)
        return 0;

    return techdriver->tearNewRules(conn, net->ifname);
}
Пример #3
0
static int
_virNWFilterInstantiateFilter(virConnectPtr conn,
                              const virDomainNetDefPtr net,
                              bool teardownOld,
                              enum instCase useNewFilter,
                              bool *foundNewFilter)
{
    const char *linkdev = (net->type == VIR_DOMAIN_NET_TYPE_DIRECT)
                          ? net->data.direct.linkdev
                          : NULL;
    int ifindex;
    int rc;

    if (ifaceGetIndex(true, net->ifname, &ifindex))
        return 1;

    virNWFilterLockFilterUpdates();

    rc = __virNWFilterInstantiateFilter(conn,
                                        teardownOld,
                                        net->ifname,
                                        ifindex,
                                        linkdev,
                                        net->type,
                                        net->mac,
                                        net->filter,
                                        net->filterparams,
                                        useNewFilter,
                                        conn->nwfilterPrivateData,
                                        false,
                                        foundNewFilter);

    virNWFilterUnlockFilterUpdates();

    return rc;
}
Пример #4
0
/**
 * openMacvtapTap:
 * Create an instance of a macvtap device and open its tap character
 * device.
 * @tgifname: Interface name that the macvtap is supposed to have. May
 *    be NULL if this function is supposed to choose a name
 * @macaddress: The MAC address for the macvtap device
 * @linkdev: The interface name of the NIC to connect to the external bridge
 * @mode: int describing the mode for 'bridge', 'vepa' or 'private'.
 * @vnet_hdr: 1 to enable IFF_VNET_HDR, 0 to disable it
 * @vmuuid: The UUID of the VM the macvtap belongs to
 * @virtPortProfile: pointer to object holding the virtual port profile data
 * @res_ifname: Pointer to a string pointer where the actual name of the
 *     interface will be stored into if everything succeeded. It is up
 *     to the caller to free the string.
 *
 * Returns file descriptor of the tap device in case of success,
 * negative value otherwise with error reported.
 *
 */
int
openMacvtapTap(const char *tgifname,
               const unsigned char *macaddress,
               const char *linkdev,
               int mode,
               int vnet_hdr,
               const unsigned char *vmuuid,
               virVirtualPortProfileParamsPtr virtPortProfile,
               char **res_ifname)
{
    const char *type = "macvtap";
    int c, rc;
    char ifname[IFNAMSIZ];
    int retries, do_retry = 0;
    uint32_t macvtapMode = macvtapModeFromInt(mode);
    const char *cr_ifname;
    int ifindex;

    *res_ifname = NULL;

    if (tgifname) {
        if(ifaceGetIndex(false, tgifname, &ifindex) == 0) {
            if (STRPREFIX(tgifname,
                          MACVTAP_NAME_PREFIX)) {
                goto create_name;
            }
            virReportSystemError(errno,
                                 _("Interface %s already exists"), tgifname);
            return -1;
        }
        cr_ifname = tgifname;
        rc = link_add(type, macaddress, 6, tgifname, linkdev,
                      macvtapMode, &do_retry);
        if (rc)
            return -1;
    } else {
create_name:
        retries = 5;
        for (c = 0; c < 8192; c++) {
            snprintf(ifname, sizeof(ifname), MACVTAP_NAME_PATTERN, c);
            if (ifaceGetIndex(false, ifname, &ifindex) == ENODEV) {
                rc = link_add(type, macaddress, 6, ifname, linkdev,
                              macvtapMode, &do_retry);
                if (rc == 0)
                    break;

                if (do_retry && --retries)
                    continue;
                return -1;
            }
        }
        cr_ifname = ifname;
    }

    if (vpAssociatePortProfileId(cr_ifname,
                                 macaddress,
                                 linkdev,
                                 virtPortProfile,
                                 vmuuid) != 0) {
        rc = -1;
        goto link_del_exit;
    }

    rc = ifaceUp(cr_ifname);
    if (rc != 0) {
        virReportSystemError(errno,
                             _("cannot 'up' interface %s -- another "
                             "macvtap device may be 'up' and have the same "
                             "MAC address"),
                             cr_ifname);
        rc = -1;
        goto disassociate_exit;
    }

    rc = openTap(cr_ifname, 10);

    if (rc >= 0) {
        if (configMacvtapTap(rc, vnet_hdr) < 0) {
            close(rc);
            rc = -1;
            goto disassociate_exit;
        }
        *res_ifname = strdup(cr_ifname);
    } else
        goto disassociate_exit;

    return rc;

disassociate_exit:
    vpDisassociatePortProfileId(cr_ifname,
                                macaddress,
                                linkdev,
                                virtPortProfile);

link_del_exit:
    link_del(cr_ifname);

    return rc;
}
Пример #5
0
static int
link_add(const char *type,
         const unsigned char *macaddress, int macaddrsize,
         const char *ifname,
         const char *srcdev,
         uint32_t macvlan_mode,
         int *retry)
{
    int rc = 0;
    char nlmsgbuf[NLMSGBUF_SIZE];
    struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
    struct nlmsgerr *err;
    char rtattbuf[RATTBUF_SIZE];
    struct rtattr *rta, *rta1, *li;
    struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
    int ifindex;
    char *recvbuf = NULL;
    unsigned int recvbuflen;

    if (ifaceGetIndex(true, srcdev, &ifindex) != 0)
        return -1;

    *retry = 0;

    memset(&nlmsgbuf, 0, sizeof(nlmsgbuf));

    nlInit(nlm, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL, RTM_NEWLINK);

    if (!nlAppend(nlm, sizeof(nlmsgbuf), &ifinfo, sizeof(ifinfo)))
        goto buffer_too_small;

    rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_LINK,
                       &ifindex, sizeof(ifindex));
    if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
        goto buffer_too_small;

    rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_ADDRESS,
                       macaddress, macaddrsize);
    if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
        goto buffer_too_small;

    if (ifname) {
        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_IFNAME,
                           ifname, strlen(ifname) + 1);
        if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
            goto buffer_too_small;
    }

    rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_LINKINFO, NULL, 0);
    if (!rta ||
        !(li = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)))
        goto buffer_too_small;

    rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_INFO_KIND,
                       type, strlen(type));
    if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
        goto buffer_too_small;

    if (macvlan_mode > 0) {
        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_INFO_DATA,
                           NULL, 0);
        if (!rta ||
            !(rta1 = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)))
            goto buffer_too_small;

        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_MACVLAN_MODE,
                           &macvlan_mode, sizeof(macvlan_mode));
        if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
            goto buffer_too_small;

        rta1->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)rta1;
    }

    li->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)li;

    if (nlComm(nlm, &recvbuf, &recvbuflen, 0) < 0)
        return -1;

    if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL)
        goto malformed_resp;

    resp = (struct nlmsghdr *)recvbuf;

    switch (resp->nlmsg_type) {
    case NLMSG_ERROR:
        err = (struct nlmsgerr *)NLMSG_DATA(resp);
        if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
            goto malformed_resp;

        switch (err->error) {

        case 0:
            break;

        case -EEXIST:
            *retry = 1;
            rc = -1;
            break;

        default:
            virReportSystemError(-err->error,
                                 _("error creating %s type of interface"),
                                 type);
            rc = -1;
        }
        break;

    case NLMSG_DONE:
        break;

    default:
        goto malformed_resp;
    }

    VIR_FREE(recvbuf);

    return rc;

malformed_resp:
    macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
                 _("malformed netlink response message"));
    VIR_FREE(recvbuf);
    return -1;

buffer_too_small:
    macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
                 _("internal buffer is too small"));
    return -1;
}