diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a0fd92215c6462e68d9fe718d778b1cbbafe59e6..d9d391364a8fd4e998de1c7cb013af280d58fa8b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -501,9 +501,15 @@ ifaceCtrl; ifaceGetFlags; ifaceGetIndex; ifaceGetMacaddr; +ifaceGetNthParent; ifaceGetVlanID; -ifaceSetMacaddr; ifaceIsUp; +ifaceLinkDel; +ifaceMacvtapLinkAdd; +ifaceMacvtapLinkDump; +ifaceReplaceMacAddress; +ifaceRestoreMacaddress; +ifaceSetMacaddr; # interface_conf.h diff --git a/src/util/interface.c b/src/util/interface.c index 7651f1d1a61fc2a57a1476abcec3651206e6cea9..02544d9829c0b6d5fee50d7ec4996dcf44cc4c93 100644 --- a/src/util/interface.c +++ b/src/util/interface.c @@ -27,6 +27,7 @@ #include #include +#include #ifdef __linux__ # include @@ -40,6 +41,10 @@ #include "interface.h" #include "virterror_internal.h" #include "files.h" +#include "memory.h" +#include "netlink.h" + +#define VIR_FROM_THIS VIR_FROM_NET #define ifaceError(code, ...) \ virReportErrorHelper(VIR_FROM_NET, code, __FILE__, \ @@ -486,3 +491,607 @@ ifaceSetMacaddr(const char *ifname ATTRIBUTE_UNUSED, } #endif /* __linux__ */ + + +/** + * ifaceLinkAdd + * + * @type: The type of device, i.e., "macvtap" + * @macaddress: The MAC address of the device + * @macaddrsize: The size of the MAC address, typically '6' + * @ifname: The name the interface is supposed to have; optional parameter + * @srcdev: The name of the 'link' device + * @macvlan_mode: The macvlan mode to use + * @retry: Pointer to integer that will be '1' upon return if an interface + * with the same name already exists and it is worth to try + * again with a different name + * + * Create a macvtap device with the given properties. + * + * Returns 0 on success, -1 on fatal error. + */ +#if __linux__ +int +ifaceMacvtapLinkAdd(const char *type, + const unsigned char *macaddress, int macaddrsize, + const char *ifname, + const char *srcdev, + uint32_t macvlan_mode, + int *retry) +{ + int rc = 0; + struct nlmsghdr *resp; + struct nlmsgerr *err; + struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC }; + int ifindex; + unsigned char *recvbuf = NULL; + unsigned int recvbuflen; + struct nl_msg *nl_msg; + struct nlattr *linkinfo, *info_data; + + if (ifaceGetIndex(true, srcdev, &ifindex) != 0) + return -1; + + *retry = 0; + + nl_msg = nlmsg_alloc_simple(RTM_NEWLINK, + NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL); + if (!nl_msg) { + virReportOOMError(); + return -1; + } + + if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) + goto buffer_too_small; + + if (nla_put_u32(nl_msg, IFLA_LINK, ifindex) < 0) + goto buffer_too_small; + + if (nla_put(nl_msg, IFLA_ADDRESS, macaddrsize, macaddress) < 0) + goto buffer_too_small; + + if (ifname && + nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) + goto buffer_too_small; + + if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO))) + goto buffer_too_small; + + if (nla_put(nl_msg, IFLA_INFO_KIND, strlen(type), type) < 0) + goto buffer_too_small; + + if (macvlan_mode > 0) { + if (!(info_data = nla_nest_start(nl_msg, IFLA_INFO_DATA))) + goto buffer_too_small; + + if (nla_put(nl_msg, IFLA_MACVLAN_MODE, sizeof(macvlan_mode), + &macvlan_mode) < 0) + goto buffer_too_small; + + nla_nest_end(nl_msg, info_data); + } + + nla_nest_end(nl_msg, linkinfo); + + if (nlComm(nl_msg, &recvbuf, &recvbuflen, 0) < 0) { + rc = -1; + goto err_exit; + } + + 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; + } + +err_exit: + nlmsg_free(nl_msg); + + VIR_FREE(recvbuf); + + return rc; + +malformed_resp: + nlmsg_free(nl_msg); + + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed netlink response message")); + VIR_FREE(recvbuf); + return -1; + +buffer_too_small: + nlmsg_free(nl_msg); + + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("allocated netlink buffer is too small")); + return -1; +} + +#else + +int +ifaceMacvtapLinkAdd(const char *type ATTRIBUTE_UNUSED, + const unsigned char *macaddress ATTRIBUTE_UNUSED, + int macaddrsize ATTRIBUTE_UNUSED, + const char *ifname ATTRIBUTE_UNUSED, + const char *srcdev ATTRIBUTE_UNUSED, + uint32_t macvlan_mode ATTRIBUTE_UNUSED, + int *retry ATTRIBUTE_UNUSED) +{ + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("ifaceMacvtapLinkAdd is not supported on non-linux " + "platforms")); + return -1; +} + +#endif + + +/** + * ifaceLinkDel + * + * @ifname: Name of the interface + * + * Tear down an interface with the given name. + * + * Returns 0 on success, -1 on fatal error. + */ +#if __linux__ +int +ifaceLinkDel(const char *ifname) +{ + int rc = 0; + struct nlmsghdr *resp; + struct nlmsgerr *err; + struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC }; + unsigned char *recvbuf = NULL; + unsigned int recvbuflen; + struct nl_msg *nl_msg; + + nl_msg = nlmsg_alloc_simple(RTM_DELLINK, + NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL); + if (!nl_msg) { + virReportOOMError(); + return -1; + } + + if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) + goto buffer_too_small; + + if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) + goto buffer_too_small; + + if (nlComm(nl_msg, &recvbuf, &recvbuflen, 0) < 0) { + rc = -1; + goto err_exit; + } + + 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; + + if (err->error) { + virReportSystemError(-err->error, + _("error destroying %s interface"), + ifname); + rc = -1; + } + break; + + case NLMSG_DONE: + break; + + default: + goto malformed_resp; + } + +err_exit: + nlmsg_free(nl_msg); + + VIR_FREE(recvbuf); + + return rc; + +malformed_resp: + nlmsg_free(nl_msg); + + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed netlink response message")); + VIR_FREE(recvbuf); + return -1; + +buffer_too_small: + nlmsg_free(nl_msg); + + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("allocated netlink buffer is too small")); + return -1; +} + +#else + +int +ifaceLinkDel(const char *ifname ATTRIBUTE_UNUSED) +{ + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("ifaceLinkDel is not supported on non-linux platforms")); + return -1; +} + +#endif + + +#if __linux__ +static struct nla_policy ifla_policy[IFLA_MAX + 1] = +{ + [IFLA_VF_PORTS] = { .type = NLA_NESTED }, +}; + +/** + * ifaceMacvtapLinkDump + * + * @nltarget_kernel: whether to send the message to the kernel or another + * process + * @ifname: The name of the interface; only use if ifindex < 0 + * @ifindex: The interface index; may be < 0 if ifname is given + * @nlattr: pointer to a pointer of netlink attributes that will contain + * the results + * @recvbuf: Pointer to the buffer holding the returned netlink response + * message; free it, once not needed anymore + * @getPidFunc: Pointer to a function that will be invoked if the kernel + * is not the target of the netlink message but it is to be + * sent to another process. + * + * Get information about an interface given its name or index. + * + * Returns 0 on success, -1 on fatal error. + */ +int +ifaceMacvtapLinkDump(bool nltarget_kernel, const char *ifname, int ifindex, + struct nlattr **tb, unsigned char **recvbuf, + uint32_t (*getPidFunc)(void)) +{ + int rc = 0; + struct nlmsghdr *resp; + struct nlmsgerr *err; + struct ifinfomsg ifinfo = { + .ifi_family = AF_UNSPEC, + .ifi_index = ifindex + }; + unsigned int recvbuflen; + uint32_t pid = 0; + struct nl_msg *nl_msg; + + *recvbuf = NULL; + + nl_msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST); + if (!nl_msg) { + virReportOOMError(); + return -1; + } + + if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) + goto buffer_too_small; + + if (ifindex < 0 && ifname) { + if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) + goto buffer_too_small; + } + + if (!nltarget_kernel) { + pid = getPidFunc(); + if (pid == 0) { + rc = -1; + goto err_exit; + } + } + + if (nlComm(nl_msg, recvbuf, &recvbuflen, pid) < 0) { + rc = -1; + goto err_exit; + } + + 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; + + if (err->error) { + virReportSystemError(-err->error, + _("error dumping %s (%d) interface"), + ifname, ifindex); + rc = -1; + } + break; + + case GENL_ID_CTRL: + case NLMSG_DONE: + if (nlmsg_parse(resp, sizeof(struct ifinfomsg), + tb, IFLA_MAX, ifla_policy)) { + goto malformed_resp; + } + break; + + default: + goto malformed_resp; + } + + if (rc != 0) + VIR_FREE(*recvbuf); + +err_exit: + nlmsg_free(nl_msg); + + return rc; + +malformed_resp: + nlmsg_free(nl_msg); + + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed netlink response message")); + VIR_FREE(*recvbuf); + return -1; + +buffer_too_small: + nlmsg_free(nl_msg); + + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("allocated netlink buffer is too small")); + return -1; +} + +#else + +int +ifaceMacvtapLinkDump(bool nltarget_kernel ATTRIBUTE_UNUSED, + const char *ifname ATTRIBUTE_UNUSED, + int ifindex ATTRIBUTE_UNUSED, + struct nlattr **tb ATTRIBUTE_UNUSED, + unsigned char **recvbuf ATTRIBUTE_UNUSED, + uint32_t (*getPidFunc)(void) ATTRIBUTE_UNUSED) +{ + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("ifaceMacvtapLinkDump is not supported on non-linux " + "platforms")); + return -1; +} + +#endif + + +/** + * 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 + */ +#if __linux__ +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, }; + unsigned 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 = ifaceMacvtapLinkDump(true, ifname, ifindex, tb, &recvbuf, NULL); + if (rc) + break; + + if (tb[IFLA_IFNAME]) { + if (!virStrcpy(parent_ifname, (char*)RTA_DATA(tb[IFLA_IFNAME]), + IFNAMSIZ)) { + ifaceError(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; +} + +#else + +int +ifaceGetNthParent(int ifindex ATTRIBUTE_UNUSED, + const char *ifname ATTRIBUTE_UNUSED, + unsigned int nthParent ATTRIBUTE_UNUSED, + int *parent_ifindex ATTRIBUTE_UNUSED, + char *parent_ifname ATTRIBUTE_UNUSED, + unsigned int *nth ATTRIBUTE_UNUSED) +{ + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("ifaceGetNthParent is not supported on non-linux platforms")); + return -1; +} + +#endif + +/** + * ifaceReplaceMacAddress: + * @macaddress: new MAC address for interface + * @linkdev: name of interface + * @stateDir: directory to store old MAC address + * + * Returns 0 on success, -1 in case of fatal error, error code otherwise. + * + */ +int +ifaceReplaceMacAddress(const unsigned char *macaddress, + const char *linkdev, + const char *stateDir) +{ + unsigned char oldmac[6]; + int rc; + + rc = ifaceGetMacaddr(linkdev, oldmac); + + if (rc) { + virReportSystemError(rc, + _("Getting MAC address from '%s' " + "to '%02x:%02x:%02x:%02x:%02x:%02x' failed."), + linkdev, + oldmac[0], oldmac[1], oldmac[2], + oldmac[3], oldmac[4], oldmac[5]); + } else { + char *path = NULL; + char macstr[VIR_MAC_STRING_BUFLEN]; + + if (virAsprintf(&path, "%s/%s", + stateDir, + linkdev) < 0) { + virReportOOMError(); + return errno; + } + virFormatMacAddr(oldmac, macstr); + if (virFileWriteStr(path, macstr, O_CREAT|O_TRUNC|O_WRONLY) < 0) { + virReportSystemError(errno, _("Unable to preserve mac for %s"), + linkdev); + return errno; + } + } + + rc = ifaceSetMacaddr(linkdev, macaddress); + if (rc) { + virReportSystemError(rc, + _("Setting MAC address on '%s' to " + "'%02x:%02x:%02x:%02x:%02x:%02x' failed."), + linkdev, + macaddress[0], macaddress[1], macaddress[2], + macaddress[3], macaddress[4], macaddress[5]); + } + + return rc; +} + +/** + * ifaceRestoreMacAddress: + * @linkdev: name of interface + * @stateDir: directory containing old MAC address + * + * Returns 0 on success, -1 in case of fatal error, error code otherwise. + * + */ +int +ifaceRestoreMacAddress(const char *linkdev, + const char *stateDir) +{ + int rc; + char *oldmacname = NULL; + char *macstr = NULL; + char *path = NULL; + unsigned char oldmac[6]; + + if (virAsprintf(&path, "%s/%s", + stateDir, + linkdev) < 0) { + virReportOOMError(); + return -1; + } + + if (virFileReadAll(path, VIR_MAC_STRING_BUFLEN, &macstr) < 0) { + return errno; + } + + if (virParseMacAddr(macstr, &oldmac[0]) != 0) { + ifaceError(VIR_ERR_INTERNAL_ERROR, + _("Cannot parse MAC address from '%s'"), + oldmacname); + return -1; + } + + /*reset mac and remove file-ignore results*/ + rc = ifaceSetMacaddr(linkdev, oldmac); + if (rc) { + virReportSystemError(rc, + _("Setting MAC address on '%s' to " + "'%02x:%02x:%02x:%02x:%02x:%02x' failed."), + linkdev, + oldmac[0], oldmac[1], oldmac[2], + oldmac[3], oldmac[4], oldmac[5]); + } + ignore_value(unlink(path)); + VIR_FREE(macstr); + + return rc; +} diff --git a/src/util/interface.h b/src/util/interface.h index fc0611b4d7c88341b39671462b39edcef79c982e..663fabb669d00c913f13fb171a522c4f7b791ce0 100644 --- a/src/util/interface.h +++ b/src/util/interface.h @@ -10,6 +10,19 @@ #ifndef __VIR_INTERFACE_H__ # define __VIR_INTERFACE_H__ +# include + +# if __linux__ + +# include +# include + +# else + +struct nlattr; + +# endif + # include "datatypes.h" int ifaceGetFlags(const char *name, short *flags); @@ -36,4 +49,28 @@ int ifaceSetMacaddr(const char *ifname, const unsigned char *macaddr); int ifaceGetMacaddr(const char *ifname, unsigned char *macaddr); +int ifaceMacvtapLinkAdd(const char *type, + const unsigned char *macaddress, int macaddrsize, + const char *ifname, + const char *srcdev, + uint32_t macvlan_mode, + int *retry); + +int ifaceLinkDel(const char *ifname); + +int ifaceMacvtapLinkDump(bool nltarget_kernel, const char *ifname, int ifindex, + struct nlattr **tb, unsigned char **recvbuf, + uint32_t (*getPidFunc)(void)); + +int ifaceGetNthParent(int ifindex, const char *ifname, unsigned int nthParent, + int *parent_ifindex, char *parent_ifname, + unsigned int *nth); + +int ifaceReplaceMacAddress(const unsigned char *macaddress, + const char *linkdev, + const char *stateDir); + +int ifaceRestoreMacAddress(const char *linkdev, + const char *stateDir); + #endif /* __VIR_INTERFACE_H__ */ diff --git a/src/util/macvtap.c b/src/util/macvtap.c index d651f7b1ac8f1aa1ab535c05f7458a291d19a1c8..30343c8670ef44dd9868e2360919f4d3398131b3 100644 --- a/src/util/macvtap.c +++ b/src/util/macvtap.c @@ -100,212 +100,6 @@ enum virVirtualPortOp { # if WITH_MACVTAP -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; - struct nlmsghdr *resp; - struct nlmsgerr *err; - struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC }; - int ifindex; - unsigned char *recvbuf = NULL; - unsigned int recvbuflen; - struct nl_msg *nl_msg; - struct nlattr *linkinfo, *info_data; - - if (ifaceGetIndex(true, srcdev, &ifindex) != 0) - return -1; - - *retry = 0; - - nl_msg = nlmsg_alloc_simple(RTM_NEWLINK, - NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL); - if (!nl_msg) { - virReportOOMError(); - return -1; - } - - if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) - goto buffer_too_small; - - if (nla_put_u32(nl_msg, IFLA_LINK, ifindex) < 0) - goto buffer_too_small; - - if (nla_put(nl_msg, IFLA_ADDRESS, macaddrsize, macaddress) < 0) - goto buffer_too_small; - - if (ifname && - nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) - goto buffer_too_small; - - if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO))) - goto buffer_too_small; - - if (nla_put(nl_msg, IFLA_INFO_KIND, strlen(type), type) < 0) - goto buffer_too_small; - - if (macvlan_mode > 0) { - if (!(info_data = nla_nest_start(nl_msg, IFLA_INFO_DATA))) - goto buffer_too_small; - - if (nla_put(nl_msg, IFLA_MACVLAN_MODE, sizeof(macvlan_mode), - &macvlan_mode) < 0) - goto buffer_too_small; - - nla_nest_end(nl_msg, info_data); - } - - nla_nest_end(nl_msg, linkinfo); - - if (nlComm(nl_msg, &recvbuf, &recvbuflen, 0) < 0) { - rc = -1; - goto err_exit; - } - - 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; - } - -err_exit: - nlmsg_free(nl_msg); - - VIR_FREE(recvbuf); - - return rc; - -malformed_resp: - nlmsg_free(nl_msg); - - macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", - _("malformed netlink response message")); - VIR_FREE(recvbuf); - return -1; - -buffer_too_small: - nlmsg_free(nl_msg); - - macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", - _("allocated netlink buffer is too small")); - return -1; -} - - -static int -link_del(const char *ifname) -{ - int rc = 0; - struct nlmsghdr *resp; - struct nlmsgerr *err; - struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC }; - unsigned char *recvbuf = NULL; - unsigned int recvbuflen; - struct nl_msg *nl_msg; - - nl_msg = nlmsg_alloc_simple(RTM_DELLINK, - NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL); - if (!nl_msg) { - virReportOOMError(); - return -1; - } - - if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) - goto buffer_too_small; - - if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) - goto buffer_too_small; - - if (nlComm(nl_msg, &recvbuf, &recvbuflen, 0) < 0) { - rc = -1; - goto err_exit; - } - - 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; - - if (err->error) { - virReportSystemError(-err->error, - _("error destroying %s interface"), - ifname); - rc = -1; - } - break; - - case NLMSG_DONE: - break; - - default: - goto malformed_resp; - } - -err_exit: - nlmsg_free(nl_msg); - - VIR_FREE(recvbuf); - - return rc; - -malformed_resp: - nlmsg_free(nl_msg); - - macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", - _("malformed netlink response message")); - VIR_FREE(recvbuf); - return -1; - -buffer_too_small: - nlmsg_free(nl_msg); - - macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", - _("allocated netlink buffer is too small")); - return -1; -} - - /* Open the macvtap's tap device. * @ifname: Name of the macvtap interface * @retries : Number of retries in case udev for example may need to be @@ -434,103 +228,6 @@ configMacvtapTap(int tapfd, int vnet_hdr) return 0; } -/** - * replaceMacAdress: - * @macaddress: new MAC address for interface - * @linkdev: name of interface - * @stateDir: directory to store old MAC address - * - * Returns 0 on success, -1 in case of fatal error, error code otherwise. - * - */ -static int -replaceMacAdress(const unsigned char *macaddress, - const char *linkdev, - char *stateDir) -{ - unsigned char oldmac[6]; - int rc; - - rc = ifaceGetMacaddr(linkdev, oldmac); - - if (rc) { - virReportSystemError(rc, - _("Getting MAC address from '%s' " - "to '%02x:%02x:%02x:%02x:%02x:%02x' failed."), - linkdev, - oldmac[0], oldmac[1], oldmac[2], - oldmac[3], oldmac[4], oldmac[5]); - } else { - char *path = NULL; - char macstr[VIR_MAC_STRING_BUFLEN]; - - if (virAsprintf(&path, "%s/%s", - stateDir, - linkdev) < 0) { - virReportOOMError(); - return errno; - } - virFormatMacAddr(oldmac, macstr); - if (virFileWriteStr(path, macstr, O_CREAT|O_TRUNC|O_WRONLY) < 0) { - virReportSystemError(errno, _("Unable to preserve mac for %s"), - linkdev); - return errno; - } - } - - rc = ifaceSetMacaddr(linkdev, macaddress); - if (rc) { - virReportSystemError(errno, - _("Setting MAC address on '%s' to " - "'%02x:%02x:%02x:%02x:%02x:%02x' failed."), - linkdev, - macaddress[0], macaddress[1], macaddress[2], - macaddress[3], macaddress[4], macaddress[5]); - } - return rc; -} - -/** - * restoreMacAddress: - * @linkdev: name of interface - * @stateDir: directory containing old MAC address - * - * Returns 0 on success, -1 in case of fatal error, error code otherwise. - * - */ -static int -restoreMacAddress(const char *linkdev, - char *stateDir) -{ - char *oldmacname = NULL; - char *macstr = NULL; - char *path = NULL; - unsigned char oldmac[6]; - - if (virAsprintf(&path, "%s/%s", - stateDir, - linkdev) < 0) { - virReportOOMError(); - return -1; - } - - if (virFileReadAll(path, VIR_MAC_STRING_BUFLEN, &macstr) < 0) { - return errno; - } - - if (virParseMacAddr(macstr, &oldmac[0]) != 0) { - macvtapError(VIR_ERR_INTERNAL_ERROR, - _("Cannot parse MAC address from '%s'"), - oldmacname); - return -1; - } - - /*reset mac and remove file-ignore results*/ - ignore_value(ifaceSetMacaddr(linkdev, oldmac)); - ignore_value(unlink(path)); - VIR_FREE(macstr); - return 0; -} static const uint32_t modeMap[VIR_MACVTAP_MODE_LAST] = { [VIR_MACVTAP_MODE_VEPA] = MACVLAN_MODE_VEPA, @@ -593,7 +290,7 @@ openMacvtapTap(const char *tgifname, * emulate their switch in firmware. */ if (mode == VIR_MACVTAP_MODE_PASSTHRU) { - if (replaceMacAdress(macaddress, linkdev, stateDir) != 0) { + if (ifaceReplaceMacAddress(macaddress, linkdev, stateDir) != 0) { return -1; } } @@ -609,8 +306,8 @@ openMacvtapTap(const char *tgifname, return -1; } cr_ifname = tgifname; - rc = link_add(type, macaddress, 6, tgifname, linkdev, - macvtapMode, &do_retry); + rc = ifaceMacvtapLinkAdd(type, macaddress, 6, tgifname, linkdev, + macvtapMode, &do_retry); if (rc) return -1; } else { @@ -619,8 +316,8 @@ create_name: 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); + rc = ifaceMacvtapLinkAdd(type, macaddress, 6, ifname, linkdev, + macvtapMode, &do_retry); if (rc == 0) break; @@ -673,7 +370,7 @@ disassociate_exit: vmOp); link_del_exit: - link_del(cr_ifname); + ifaceLinkDel(cr_ifname); return rc; } @@ -698,7 +395,7 @@ delMacvtap(const char *ifname, char *stateDir) { if (mode == VIR_MACVTAP_MODE_PASSTHRU) { - restoreMacAddress(linkdev, stateDir); + ifaceRestoreMacAddress(linkdev, stateDir); } if (ifname) { @@ -706,7 +403,7 @@ delMacvtap(const char *ifname, linkdev, virtPortProfile, VIR_VM_OP_DESTROY); - link_del(ifname); + ifaceLinkDel(ifname); } } @@ -714,11 +411,6 @@ delMacvtap(const char *ifname, # ifdef IFLA_PORT_MAX -static struct nla_policy ifla_policy[IFLA_MAX + 1] = -{ - [IFLA_VF_PORTS] = { .type = NLA_NESTED }, -}; - static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] = { [IFLA_PORT_RESPONSE] = { .type = NLA_U16 }, @@ -758,173 +450,6 @@ getLldpadPid(void) { } -static int -link_dump(bool nltarget_kernel, const char *ifname, int ifindex, - struct nlattr **tb, unsigned char **recvbuf) -{ - int rc = 0; - struct nlmsghdr *resp; - struct nlmsgerr *err; - struct ifinfomsg ifinfo = { - .ifi_family = AF_UNSPEC, - .ifi_index = ifindex - }; - unsigned int recvbuflen; - uint32_t pid = 0; - struct nl_msg *nl_msg; - - *recvbuf = NULL; - - nl_msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST); - if (!nl_msg) { - virReportOOMError(); - return -1; - } - - if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) - goto buffer_too_small; - - if (ifindex < 0 && ifname) { - if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) - goto buffer_too_small; - } - - if (!nltarget_kernel) { - pid = getLldpadPid(); - if (pid == 0) { - rc = -1; - goto err_exit; - } - } - - if (nlComm(nl_msg, recvbuf, &recvbuflen, pid) < 0) { - rc = -1; - goto err_exit; - } - - 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; - - if (err->error) { - virReportSystemError(-err->error, - _("error dumping %s (%d) interface"), - ifname, ifindex); - rc = -1; - } - break; - - case GENL_ID_CTRL: - case NLMSG_DONE: - if (nlmsg_parse(resp, sizeof(struct ifinfomsg), - tb, IFLA_MAX, ifla_policy)) { - goto malformed_resp; - } - break; - - default: - goto malformed_resp; - } - - if (rc != 0) - VIR_FREE(*recvbuf); - -err_exit: - nlmsg_free(nl_msg); - - return rc; - -malformed_resp: - nlmsg_free(nl_msg); - - macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", - _("malformed netlink response message")); - VIR_FREE(*recvbuf); - return -1; - -buffer_too_small: - nlmsg_free(nl_msg); - - macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", - _("allocated netlink buffer is too small")); - return -1; -} - - -/** - * 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, }; - unsigned 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; -} - /** * getPortProfileStatus * @@ -1252,7 +777,8 @@ doPortProfileOpCommon(bool nltarget_kernel, } while (--repeats >= 0) { - rc = link_dump(nltarget_kernel, NULL, ifindex, tb, &recvbuf); + rc = ifaceMacvtapLinkDump(nltarget_kernel, NULL, ifindex, tb, + &recvbuf, getLldpadPid); if (rc) goto err_exit; rc = getPortProfileStatus(tb, vf, instanceId, nltarget_kernel,