#include <sys/socket.h>
#include <sys/ioctl.h>
+#include <fcntl.h>
#ifdef __linux__
# include <linux/if.h>
#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__, \
}
#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;
+}
# 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
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,
* 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;
}
}
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 {
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;
vmOp);
link_del_exit:
- link_del(cr_ifname);
+ ifaceLinkDel(cr_ifname);
return rc;
}
char *stateDir)
{
if (mode == VIR_MACVTAP_MODE_PASSTHRU) {
- restoreMacAddress(linkdev, stateDir);
+ ifaceRestoreMacAddress(linkdev, stateDir);
}
if (ifname) {
linkdev,
virtPortProfile,
VIR_VM_OP_DESTROY);
- link_del(ifname);
+ ifaceLinkDel(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 },
}
-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
*
}
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,