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