From df3d8c362d3f217760fd9534f55013810b8febac Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 22 Jun 2011 14:28:57 -0400 Subject: [PATCH] cleanup: make several interface functions commonly available In a second cleanup step this patch makes several interface functions from macvtap.c commonly available by moving them into interface.c and prefixing their names with 'iface'. Those functions taking Linux-specific structures as parameters are only visible on Linux. ifaceRestoreMacAddress returns the return code from the ifaceSetMacAddr call and display an error message if setting the MAC address did not work. The caller is unchanged and still ignores the return code (which is ok). --- src/libvirt_private.syms | 8 +- src/util/interface.c | 609 +++++++++++++++++++++++++++++++++++++++ src/util/interface.h | 37 +++ src/util/macvtap.c | 494 +------------------------------ 4 files changed, 663 insertions(+), 485 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a0fd92215c..d9d391364a 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 7651f1d1a6..02544d9829 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 fc0611b4d7..663fabb669 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 d651f7b1ac..30343c8670 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, -- GitLab