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).
Signed-off-by: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
---
src/libvirt_private.syms | 8
src/util/interface.c | 590
+++++++++++++++++++++++++++++++++++++++++++++++
src/util/interface.h | 33 ++
src/util/macvtap.c | 495 ---------------------------------------
4 files changed, 640 insertions(+), 486 deletions(-)
Index: libvirt-acl/src/util/interface.c
===================================================================
--- libvirt-acl.orig/src/util/interface.c
+++ libvirt-acl/src/util/interface.c
@@ -27,6 +27,7 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
+#include <fcntl.h>
#ifdef __linux__
# include <linux/if.h>
@@ -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,588 @@ ifaceSetMacaddr(const char *ifname ATTRI
}
#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;
+}
+
+#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;
+}
Index: libvirt-acl/src/util/interface.h
===================================================================
--- libvirt-acl.orig/src/util/interface.h
+++ libvirt-acl/src/util/interface.h
@@ -10,6 +10,13 @@
#ifndef __VIR_INTERFACE_H__
# define __VIR_INTERFACE_H__
+# include <stdint.h>
+
+# if __linux__
+# include <sys/socket.h>
+# include <linux/netlink.h>
+# endif
+
# include "datatypes.h"
int ifaceGetFlags(const char *name, short *flags);
@@ -36,4 +43,30 @@ int ifaceSetMacaddr(const char *ifname,
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);
+
+# if __linux__
+int ifaceMacvtapLinkDump(bool nltarget_kernel, const char *ifname, int
ifindex,
+ struct nlattr **tb, unsigned char **recvbuf,
+ uint32_t (*getPidFunc)(void));
+# endif
+
+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__ */
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -95,212 +95,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
@@ -450,104 +244,6 @@ configMacvtapTap(int tapfd, int vnet_hdr
}
/**
- * 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;
-}
-
-/**
* openMacvtapTap:
* Create an instance of a macvtap device and open its tap character
* device.
@@ -599,7 +295,7 @@ openMacvtapTap(const char *tgifname,
* emulate their switch in firmware.
*/
if (mode == VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU) {
- if (replaceMacAdress(macaddress, linkdev, stateDir) != 0) {
+ if (ifaceReplaceMacAddress(macaddress, linkdev, stateDir) != 0) {
return -1;
}
}
@@ -615,8 +311,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 {
@@ -625,8 +321,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;
@@ -679,7 +375,7 @@ disassociate_exit:
vmOp);
link_del_exit:
- link_del(cr_ifname);
+ ifaceLinkDel(cr_ifname);
return rc;
}
@@ -704,7 +400,7 @@ delMacvtap(const char *ifname,
char *stateDir)
{
if (mode == VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU) {
- restoreMacAddress(linkdev, stateDir);
+ ifaceRestoreMacAddress(linkdev, stateDir);
}
if (ifname) {
@@ -712,7 +408,7 @@ delMacvtap(const char *ifname,
linkdev,
virtPortProfile,
VIR_VM_OP_DESTROY);
- link_del(ifname);
+ ifaceLinkDel(ifname);
}
}
@@ -720,11 +416,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 },
@@ -764,173 +455,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
*
@@ -1258,7 +782,8 @@ doPortProfileOpCommon(bool nltarget_kern
}
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,
Index: libvirt-acl/src/libvirt_private.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_private.syms
+++ libvirt-acl/src/libvirt_private.syms
@@ -499,9 +499,15 @@ ifaceCtrl;
ifaceGetFlags;
ifaceGetIndex;
ifaceGetMacaddr;
+ifaceGetNthParent;
ifaceGetVlanID;
-ifaceSetMacaddr;
ifaceIsUp;
+ifaceLinkDel;
+ifaceMacvtapLinkAdd;
+ifaceMacvtapLinkDump;
+ifaceReplaceMacAddress;
+ifaceRestoreMacaddress;
+ifaceSetMacaddr;
# interface_conf.h