[libvirt] [PATCH 2/2] cleanup: make several interface functions commonly available
by Stefan Berger
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
13 years, 5 months
[libvirt] [PATCH] build: require newer netcf when it is available
by Eric Blake
When building for newer Fedora or RHEL, take advantage of the
newer netcf packaging to guarantee interface snapshot support.
* libvirt.spec.in (BuildRequires): Bump minimum version on
platforms that support netcf 0.1.8.
---
I don't think we need an explicit 'Requires: netcf-libs >= 0.1.8' line
for the runtime dependency, since netcf uses versioned symbols.
I'm not sure whether F16 was the right target for requiring 0.1.8,
or whether we should also try to include F15 (but 0.1.8 has not yet
been built for F15).
libvirt.spec.in | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 75b145a..11b8591 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -424,8 +424,12 @@ BuildRequires: libcap-ng-devel >= 0.5.0
BuildRequires: libssh2-devel
%endif
%if %{with_netcf}
+%if 0%{?fedora} >= 16 || 0%{?rhel} >= 6
+BuildRequires: netcf-devel >= 0.1.8
+%else
BuildRequires: netcf-devel >= 0.1.4
%endif
+%endif
%if %{with_esx}
%if 0%{?fedora} >= 9 || 0%{?rhel} >= 6
BuildRequires: libcurl-devel
--
1.7.4.4
13 years, 5 months
[libvirt] [PATCH] virsh: avoid bogus description
by Eric Blake
https://bugzilla.redhat.com/show_bug.cgi?id=682121
Gettext reserves the empty string for internal use, and it must
not be passed through _(). We were violating this for commands
that (for whatever reason) used "" for their description.
* tools/virsh.c (vshCmddefHelp): Don't translate empty string.
Reported by Tatsuo Kawasaki.
---
tools/virsh.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index a315f05..bdd5005 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -12113,7 +12113,8 @@ vshCmddefHelp(vshControl *ctl, const char *cmdname)
vshError(ctl, _("command '%s' doesn't exist"), cmdname);
return false;
} else {
- const char *desc = _(vshCmddefGetInfo(def, "desc"));
+ /* Don't translate desc until after we know it isn't "". */
+ const char *desc = vshCmddefGetInfo(def, "desc");
const char *help = _(vshCmddefGetInfo(def, "help"));
char buf[256];
uint32_t opts_need_arg;
@@ -12167,7 +12168,7 @@ vshCmddefHelp(vshControl *ctl, const char *cmdname)
if (desc[0]) {
/* Print the description only if it's not empty. */
fputs(_("\n DESCRIPTION\n"), stdout);
- fprintf(stdout, " %s\n", desc);
+ fprintf(stdout, " %s\n", _(desc));
}
if (def->opts) {
--
1.7.4.4
13 years, 5 months
[libvirt] [libvirt-php] Announcement: Release 0.4.2 available
by Michal Novotny
Hello everybody.
it's been a rather long time since the first release of libvirt-php
bindings however there are many new features so I've decided to release
a new version of libvirt-php, release 0.4.2.
New features:
- Storage pool / volume related functions (by Lyre)
- VNC client support to get screenshot using gvnccapture (if present)
- experimental - sending keys and client pointer events over VNC protocol
- API to change domain VCPU count, memory amount and guest boot order
- libvirt resources tracking - can be obtained by
libvirt_print_binding_resources() API function
- debug logging using libvirt_logfile_set() API function (default max
log file size can be obtained in PHPInfo output)
- functions to add/remove domain disks/NICs in an easy way (using a
simple PHP API functions)
For this release thanks goes to those guys:
- Lyre <liyong(a)skybility.com> - storage-related functions as well as
many bug fixes
- Yukihiro Kawada <warp.kawada(a)gmail.com> - fix for the memory leak in
libvirt_list_domains()
- Daniel P. Berrange <berrange(a)redhat.com> - bug fixes/improvements
for the build system
- Radek Hladik <r.hladik(a)cybersales.cz> - patch to add API to update
device
- Tiziano Mueller <dev-zero(a)gentoo.org> - several bug fixes for
threaded php and libvirt_connect/version failures without Xen
I hope I didn't forget to mention anybody ;-)
The new release can be found at:
http://libvirt.org/sources/php/libvirt-php-0.4.2.tar.gz
Michal
--
Michal Novotny <minovotn(a)redhat.com>, RHCE, Red Hat
Virtualization Team (xen userspace) | libvirt-php bindings
13 years, 5 months
[libvirt] [PATCH 00/10] python: Implement missing stream/event ops
by Cole Robinson
Currently it isn't possible to implement the equivalent of 'virsh console'
with the python bindings. This series implements the missing functionality
required to do so.
Cole Robinson (10):
python: libvirt-override: use simpler debug
python: generator: Don't print warning if nothing to warn about
python: Implement bindings for virStreamEventAddCallback
python: Implement virStreamSend/Recv
python: Implement virStreamSend/RecvAll helpers
Promote virEvent*Handle/Timeout to public API
events: Correct virEventAddTimeout docs
python: Add bindings for virEvent*Handle/Timeout
python: events: Fix C->Python handle callback prototype
python: Mark event callback wrappers as private
daemon/libvirtd.c | 1 -
daemon/mdns.c | 1 -
examples/domain-events/events-python/event-test.py | 6 +-
python/generator.py | 27 +-
python/libvirt-override-virConnect.py | 102 ++---
python/libvirt-override-virStream.py | 123 +++++-
python/libvirt-override.c | 492 ++++++++++++++-----
python/libvirt-override.py | 80 +++-
python/typewrappers.c | 14 +
python/typewrappers.h | 2 +-
src/conf/domain_event.c | 1 -
src/conf/domain_event.h | 1 -
src/fdstream.c | 1 -
src/libvirt_private.syms | 9 -
src/libvirt_public.syms | 6 +
src/libxl/libxl_driver.c | 1 -
src/lxc/lxc_driver.c | 1 -
src/network/bridge_driver.c | 1 -
src/node_device/node_device_hal.c | 1 -
src/node_device/node_device_udev.c | 1 -
src/openvz/openvz_driver.c | 1 -
src/qemu/qemu_domain.c | 1 -
src/qemu/qemu_driver.c | 1 -
src/qemu/qemu_monitor.c | 1 -
src/remote/remote_driver.c | 1 -
src/test/test_driver.c | 1 -
src/uml/uml_driver.c | 1 -
src/util/event.c | 56 +++
src/util/event.h | 73 ---
src/util/util.c | 1 -
src/vbox/vbox_tmpl.c | 1 -
src/xen/xen_inotify.c | 1 -
src/xen/xs_internal.c | 1 -
tools/console.c | 1 -
34 files changed, 692 insertions(+), 320 deletions(-)
--
1.7.4.4
13 years, 5 months
Re: [libvirt] Network device abstraction aka virtual switch - V3
by Neil Wilson
> The current modes are:
>
> <forward layer='network' mode='route|nat'/>
>
> (in addition to not listing any mode, which equates to "isolated")
>
> Here are suggested new modes:
Has anybody considered the migration requirements of networks in this
new layout?
If you move a machine attached to a 'route|nat' network to another Host
you need to extend the network to the new Host and eventually you need
to move the supporting processes that hand out the IP addresses/DNS
addresses etc (if you're decommissioning a Host server for example).
If you try to start a copy of the network on the new host, then it
generally clashes with the pre-existing routing
It would be useful to be able to extend a network onto another Host
somehow and be able to migrate the supporting processes (DNSMasq, IP
addressing, etc) between Hosts. (And obviously remove extensions as
required as well).
Perhaps this suggests that the address and route management systems need
separating from the definition of the bridge network. (There's no real
reason why the address management systems couldn't be attached to
macvtap and vepa networks as well as basic bridges).
Rgs
Neil Wilson
13 years, 5 months
[libvirt] [PATCH] Support reboots with the QEMU driver
by Daniel P. Berrange
For controlled shutdown we issue a 'system_powerdown' command
to the QEMU monitor. This triggers an ACPI event which (most)
guest OS wire up to a controlled shutdown. There is no equiv
ACPI event to trigger a controlled reboot. This patch attempts
to fake a reboot.
- In qemuDomainObjPrivatePtr we have a bool fakeReboot
flag.
- The virDomainReboot method sets this flag and then
triggers a normal 'system_powerdown'.
- The QEMU process is started with '-no-shutdown'
so that the guest CPUs pause when it powers off the
guest
- When we receive the 'POWEROFF' event from QEMU JSON
monitor if fakeReboot is not set we invoke the
qemuProcessKill command and shutdown continues
normally
- If fakeReboot was set, we spawn a background thread
which issues 'system_reset' to perform a warm reboot
of the guest hardware. Then it issues 'cont' to
start the CPUs again
* src/qemu/qemu_command.c: Add -no-shutdown flag if
we have JSON support
* src/qemu/qemu_domain.h: Add 'fakeReboot' flag to
qemuDomainObjPrivate struct
* src/qemu/qemu_driver.c: Fake reboot using the
system_powerdown command if JSON support is available
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_json.h,
src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h: Add
binding for system_reset command
* src/qemu/qemu_process.c: Reset the guest & start CPUs if
fakeReboot is set
---
src/qemu/qemu_command.c | 7 +++
src/qemu/qemu_domain.h | 2 +
src/qemu/qemu_driver.c | 65 ++++++++++++++++++++++++++++-
src/qemu/qemu_monitor.c | 19 ++++++++
src/qemu/qemu_monitor.h | 1 +
src/qemu/qemu_monitor_json.c | 19 ++++++++
src/qemu/qemu_monitor_json.h | 1 +
src/qemu/qemu_monitor_text.c | 13 ++++++
src/qemu/qemu_monitor_text.h | 1 +
src/qemu/qemu_process.c | 95 +++++++++++++++++++++++++++++++++++++++++-
10 files changed, 220 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 6346243..9ae1409 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3207,6 +3207,13 @@ qemuBuildCommandLine(virConnectPtr conn,
def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
virCommandAddArg(cmd, "-no-reboot");
+ /* If JSON monitor is enabled, we can receive an event
+ * when QEMU stops. If we use no-shutdown, then we can
+ * watch for this event and do a soft/warm reboot.
+ */
+ if (monitor_json)
+ virCommandAddArg(cmd, "-no-shutdown");
+
if (!(def->features & (1 << VIR_DOMAIN_FEATURE_ACPI)))
virCommandAddArg(cmd, "-no-acpi");
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index bacf5b5..b8469b6 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -89,6 +89,8 @@ struct _qemuDomainObjPrivate {
virBitmapPtr qemuCaps;
char *lockState;
+
+ bool fakeReboot;
};
struct qemuDomainWatchdogEvent
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 853c84c..4c827cf 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1429,7 +1429,7 @@ cleanup:
}
-static int qemudDomainShutdown(virDomainPtr dom) {
+static int qemuDomainShutdown(virDomainPtr dom) {
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
@@ -1461,6 +1461,8 @@ static int qemudDomainShutdown(virDomainPtr dom) {
ret = qemuMonitorSystemPowerdown(priv->mon);
qemuDomainObjExitMonitor(vm);
+ priv->fakeReboot = false;
+
endjob:
if (qemuDomainObjEndJob(vm) == 0)
vm = NULL;
@@ -1472,11 +1474,66 @@ cleanup:
}
+static int qemuDomainReboot(virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) {
+ struct qemud_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+ qemuDomainObjPrivatePtr priv;
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ qemuDriverUnlock(driver);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ qemuReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+ priv = vm->privateData;
+
+#if HAVE_YAJL
+ if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
+ if (qemuDomainObjBeginJob(vm) < 0)
+ goto cleanup;
+
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ goto endjob;
+ }
+
+ qemuDomainObjEnterMonitor(vm);
+ ret = qemuMonitorSystemPowerdown(priv->mon);
+ qemuDomainObjExitMonitor(vm);
+
+ priv->fakeReboot = true;
+
+ endjob:
+ if (qemuDomainObjEndJob(vm) == 0)
+ vm = NULL;
+ } else {
+#endif
+ qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
+ _("Reboot is not supported without the JSON monitor"));
+#if HAVE_YAJL
+ }
+#endif
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+
static int qemudDomainDestroy(virDomainPtr dom) {
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
virDomainEventPtr event = NULL;
+ qemuDomainObjPrivatePtr priv;
qemuDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
@@ -1488,6 +1545,9 @@ static int qemudDomainDestroy(virDomainPtr dom) {
goto cleanup;
}
+ priv = vm->privateData;
+ priv->fakeReboot = false;
+
/* Although qemuProcessStop does this already, there may
* be an outstanding job active. We want to make sure we
* can kill the process even if a job is active. Killing
@@ -8146,7 +8206,8 @@ static virDriver qemuDriver = {
.domainLookupByName = qemudDomainLookupByName, /* 0.2.0 */
.domainSuspend = qemudDomainSuspend, /* 0.2.0 */
.domainResume = qemudDomainResume, /* 0.2.0 */
- .domainShutdown = qemudDomainShutdown, /* 0.2.0 */
+ .domainShutdown = qemuDomainShutdown, /* 0.2.0 */
+ .domainReboot = qemuDomainReboot, /* 0.9.3 */
.domainDestroy = qemudDomainDestroy, /* 0.2.0 */
.domainGetOSType = qemudDomainGetOSType, /* 0.2.2 */
.domainGetMaxMemory = qemudDomainGetMaxMemory, /* 0.4.2 */
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 1428921..1dafc4b 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1096,6 +1096,25 @@ int qemuMonitorSystemPowerdown(qemuMonitorPtr mon)
}
+int qemuMonitorSystemReset(qemuMonitorPtr mon)
+{
+ int ret;
+ VIR_DEBUG("mon=%p", mon);
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONSystemReset(mon);
+ else
+ ret = qemuMonitorTextSystemReset(mon);
+ return ret;
+}
+
+
int qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
int **pids)
{
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 3bb0269..ae74a3c 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -194,6 +194,7 @@ int qemuMonitorStartCPUs(qemuMonitorPtr mon,
int qemuMonitorStopCPUs(qemuMonitorPtr mon);
int qemuMonitorGetStatus(qemuMonitorPtr mon, bool *running);
+int qemuMonitorSystemReset(qemuMonitorPtr mon);
int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
int qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 56ec65b..6cc6ea7 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -947,6 +947,25 @@ int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon)
}
+int qemuMonitorJSONSystemReset(qemuMonitorPtr mon)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("system_reset", NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
/*
* [ { "CPU": 0, "current": true, "halted": false, "pc": 3227107138 },
* { "CPU": 1, "current": false, "halted": true, "pc": 7108165 } ]
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 393d8fc..a72bf7c 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -49,6 +49,7 @@ int qemuMonitorJSONStopCPUs(qemuMonitorPtr mon);
int qemuMonitorJSONGetStatus(qemuMonitorPtr mon, bool *running);
int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
+int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon,
int **pids);
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index a16ea91..67333aa 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -417,6 +417,19 @@ int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon) {
}
+int qemuMonitorTextSystemReset(qemuMonitorPtr mon) {
+ char *info;
+
+ if (qemuMonitorHMPCommand(mon, "system_reset", &info) < 0) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("system reset operation failed"));
+ return -1;
+ }
+ VIR_FREE(info);
+ return 0;
+}
+
+
int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
int **pids)
{
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index 4fa5064..7536557 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -46,6 +46,7 @@ int qemuMonitorTextStopCPUs(qemuMonitorPtr mon);
int qemuMonitorTextGetStatus(qemuMonitorPtr mon, bool *running);
int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon);
+int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
int **pids);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 6838417..694d8a9 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -348,12 +348,99 @@ qemuProcessHandleReset(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
}
+/*
+ * Since we have the '-no-shutdown' flag set, the
+ * QEMU process will currently have guest OS shutdown
+ * and the CPUS stopped. To fake the reboot, we thus
+ * want todo a reset of the virtual hardware, followed
+ * by restart of the CPUs. This should result in the
+ * guest OS booting up again
+ */
+static void
+qemuProcessFakeReboot(void *opaque)
+{
+ struct qemud_driver *driver = qemu_driver;
+ virDomainObjPtr vm = opaque;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ virDomainEventPtr event = NULL;
+ int ret = -1;
+ VIR_DEBUG("vm=%p", vm);
+ qemuDriverLock(driver);
+ virDomainObjLock(vm);
+ if (qemuDomainObjBeginJob(vm) < 0)
+ goto cleanup;
+
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest unexpectedly quit"));
+ goto endjob;
+ }
+
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ if (qemuMonitorSystemReset(priv->mon) < 0) {
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ goto endjob;
+ }
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest unexpectedly quit"));
+ goto endjob;
+ }
+
+ if (qemuProcessStartCPUs(driver, vm, NULL,
+ VIR_DOMAIN_RUNNING_BOOTED) < 0) {
+ if (virGetLastError() == NULL)
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("resume operation failed"));
+ goto endjob;
+ }
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
+
+ ret = 0;
+
+endjob:
+ if (qemuDomainObjEndJob(vm) == 0)
+ vm = NULL;
+
+cleanup:
+ if (vm) {
+ if (ret == -1)
+ qemuProcessKill(vm);
+ if (virDomainObjUnref(vm) > 0)
+ virDomainObjUnlock(vm);
+ }
+ if (event)
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+}
+
+
static int
qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
virDomainObjPtr vm)
{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ VIR_DEBUG("vm=%p", vm);
+
virDomainObjLock(vm);
- ((qemuDomainObjPrivatePtr) vm->privateData)->gotShutdown = true;
+ priv->gotShutdown = true;
+ if (priv->fakeReboot) {
+ virDomainObjRef(vm);
+ virThread th;
+ if (virThreadCreate(&th,
+ false,
+ qemuProcessFakeReboot,
+ vm) < 0) {
+ VIR_ERROR("Failed to create reboot thread, killing domain");
+ qemuProcessKill(vm);
+ }
+ } else {
+ qemuProcessKill(vm);
+ }
virDomainObjUnlock(vm);
return 0;
@@ -1920,6 +2007,11 @@ qemuProcessPrepareMonitorChr(struct qemud_driver *driver,
}
+/*
+ * Precondition: Both driver and vm must be locked,
+ * and a job must be active. This method will call
+ * {Enter,Exit}MonitorWithDriver
+ */
int
qemuProcessStartCPUs(struct qemud_driver *driver, virDomainObjPtr vm,
virConnectPtr conn, virDomainRunningReason reason)
@@ -2182,6 +2274,7 @@ int qemuProcessStart(virConnectPtr conn,
goto cleanup;
vm->def->id = driver->nextvmid++;
+ priv->fakeReboot = false;
/* Run an early hook to set-up missing devices */
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
--
1.7.4.4
13 years, 5 months
[libvirt] FreeBSD portability question, --network question
by Jason Helfman
Hey Everyone,
I've ported libvirt to FreeBSD, however it has the networking disabled for
the build, however I was curious what would need to be changed for this to
work.
Currently, we do have virtualbox-ose in the FreeBSD portstree, and I am
curious if the networking would need to be reworked to support libvirt with
networking in FreeBSD in the same manner in which virtualbox creates
interfaces and uses the networking stack?
Basically, I am seeking to learn what is missing, and how to either find
resources to get this implemented, or implement it myself. The latter of
implementing it myself is unlikely, as I really don't have very much
source control experience at a networking stack layer.
Thanks very much,
Jason
--
Jason Helfman
System Administrator
experts-exchange.com
http://www.experts-exchange.com/M_4830110.html
E4AD 7CF1 1396 27F6 79DD 4342 5E92 AD66 8C8C FBA5
13 years, 5 months
[libvirt] [PATCH v3]: set and restore MAC address of a NIC when using PASSTHROUGH mode
by Gerhard Stenzel
This is another rework of the patch from Dirk addressing all comments
received so far.
The following patch addresses the problem that when a PASSTHROUGH
mode DIRECT NIC connection is made the MAC address of the NIC is
not automatically set and reset to the configured VM MAC and
back again.
The attached patch fixes this problem by setting and resetting the MAC
while remembering the previous setting while the VM is running.
This also works if libvirtd is restarted while the VM is running.
the patch passes make syntax-check
Signed-off-by: Dirk Herrendoerfer <d.herrendoerfer at herrendoerfer.name>
Signed-off-by: Gerhard Stenzel <gerhard.stenzel(a)de.ibm.com>
---
Index: libvirt/src/qemu/qemu_command.c
===================================================================
--- libvirt.orig/src/qemu/qemu_command.c
+++ libvirt/src/qemu/qemu_command.c
@@ -128,7 +128,7 @@ qemuPhysIfaceConnect(virDomainDefPtr def
rc = openMacvtapTap(net->ifname, net->mac, net->data.direct.linkdev,
net->data.direct.mode, vnet_hdr, def->uuid,
&net->data.direct.virtPortProfile, &res_ifname,
- vmop);
+ vmop, driver->stateDir);
if (rc >= 0) {
qemuAuditNetDevice(def, net, res_ifname, true);
VIR_FREE(net->ifname);
@@ -149,7 +149,9 @@ qemuPhysIfaceConnect(virDomainDefPtr def
if (err) {
VIR_FORCE_CLOSE(rc);
delMacvtap(net->ifname, net->mac, net->data.direct.linkdev,
- &net->data.direct.virtPortProfile);
+ net->data.direct.mode,
+ &net->data.direct.virtPortProfile,
+ driver->stateDir);
VIR_FREE(net->ifname);
}
}
Index: libvirt/src/qemu/qemu_process.c
===================================================================
--- libvirt.orig/src/qemu/qemu_process.c
+++ libvirt/src/qemu/qemu_process.c
@@ -2876,7 +2876,8 @@ void qemuProcessStop(struct qemud_driver
virDomainNetDefPtr net = def->nets[i];
if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
delMacvtap(net->ifname, net->mac, net->data.direct.linkdev,
- &net->data.direct.virtPortProfile);
+ net->data.direct.mode,
+ &net->data.direct.virtPortProfile, driver->stateDir);
VIR_FREE(net->ifname);
}
}
Index: libvirt/src/util/macvtap.c
===================================================================
--- libvirt.orig/src/util/macvtap.c
+++ libvirt/src/util/macvtap.c
@@ -545,6 +545,106 @@ 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)
+{
+ int ret;
+ 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) {
+ virReportSystemError(errno, _("Unable to preserve mac for %s"),
+ linkdev);
+ return errno;
+ }
+
+ if (virParseMacAddr(macstr, &oldmac[0]) != 0) {
+ virReportSystemError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse MAC address from '%s'"),
+ oldmacname);
+ return -1;
+ }
+
+ /*reset mac and remove file-ignore results*/
+ ret = ifaceSetMacaddr(linkdev, oldmac);
+ ret = unlink(path);
+ VIR_FREE(macstr);
+ return 0;
+}
/**
* openMacvtapTap:
@@ -575,7 +675,8 @@ openMacvtapTap(const char *tgifname,
const unsigned char *vmuuid,
virVirtualPortProfileParamsPtr virtPortProfile,
char **res_ifname,
- enum virVMOperationType vmOp)
+ enum virVMOperationType vmOp,
+ char *stateDir)
{
const char *type = "macvtap";
int c, rc;
@@ -589,6 +690,21 @@ openMacvtapTap(const char *tgifname,
VIR_DEBUG("%s: VM OPERATION: %s", __FUNCTION__, virVMOperationTypeToString(vmOp));
+ /** Note: When using PASSTHROUGH mode with MACVTAP devices the link
+ * device's MAC address must be set to the VMs MAC address. In
+ * order to not confuse the first switch or bridge in line this MAC
+ * address must be reset when the VM is shut down.
+ * This is especially important when using SRIOV capable cards that
+ * emulate their switch in firmware.
+ */
+ if (mode == VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU) {
+ if (replaceMacAdress(macaddress, linkdev, stateDir) != 0) {
+ virReportSystemError(errno,
+ _("cannot replace MAC address on $s"),
+ linkdev);
+ }
+ }
+
if (tgifname) {
if(ifaceGetIndex(false, tgifname, &ifindex) == 0) {
if (STRPREFIX(tgifname,
@@ -684,8 +800,18 @@ void
delMacvtap(const char *ifname,
const unsigned char *macaddr,
const char *linkdev,
- virVirtualPortProfileParamsPtr virtPortProfile)
+ int mode,
+ virVirtualPortProfileParamsPtr virtPortProfile,
+ char *stateDir)
{
+ if (mode == VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU) {
+ if (restoreMacAddress(linkdev, stateDir) != 0) {
+ virReportSystemError(errno,
+ _("cannot restore MAC address on $s"),
+ linkdev);
+ }
+ }
+
if (ifname) {
vpDisassociatePortProfileId(ifname, macaddr,
linkdev,
Index: libvirt/src/util/macvtap.h
===================================================================
--- libvirt.orig/src/util/macvtap.h
+++ libvirt/src/util/macvtap.h
@@ -83,12 +83,15 @@ int openMacvtapTap(const char *ifname,
const unsigned char *vmuuid,
virVirtualPortProfileParamsPtr virtPortProfile,
char **res_ifname,
- enum virVMOperationType vmop);
+ enum virVMOperationType vmop,
+ char *stateDir);
void delMacvtap(const char *ifname,
const unsigned char *macaddress,
const char *linkdev,
- virVirtualPortProfileParamsPtr virtPortProfile);
+ int mode,
+ virVirtualPortProfileParamsPtr virtPortProfile,
+ char *stateDir);
int vpAssociatePortProfileId(const char *macvtap_ifname,
const unsigned char *macvtap_macaddr,
Index: libvirt/src/qemu/qemu_hotplug.c
===================================================================
--- libvirt.orig/src/qemu/qemu_hotplug.c
+++ libvirt/src/qemu/qemu_hotplug.c
@@ -1610,7 +1610,9 @@ int qemuDomainDetachNetDevice(struct qem
#if WITH_MACVTAP
if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
delMacvtap(detach->ifname, detach->mac, detach->data.direct.linkdev,
- &detach->data.direct.virtPortProfile);
+ detach->data.direct.mode,
+ &detach->data.direct.virtPortProfile,
+ driver->stateDir);
VIR_FREE(detach->ifname);
}
#endif
Index: libvirt/src/util/interface.c
===================================================================
--- libvirt.orig/src/util/interface.c
+++ libvirt/src/util/interface.c
@@ -390,3 +390,102 @@ ifaceGetVlanID(const char *vlanifname AT
return ENOSYS;
}
#endif /* __linux__ */
+
+/**
+ * ifaceGetMacaddr:
+ * @ifname: interface name to set MTU for
+ * @macaddr: MAC address (VIR_MAC_BUFLEN in size)
+ *
+ * This function gets the @macaddr for a given interface @ifname.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef __linux__
+int
+ifaceGetMacaddr(const char *ifname,
+ unsigned char *macaddr)
+{
+ struct ifreq ifr;
+ int fd;
+
+ if (!ifname)
+ return EINVAL;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if(fd < 0){
+ return errno;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
+ return EINVAL;
+
+ if(ioctl(fd, SIOCGIFHWADDR, (char *)&ifr) != 0){
+ return errno;
+ }
+
+ memcpy(macaddr, ifr.ifr_ifru.ifru_hwaddr.sa_data, VIR_MAC_BUFLEN);
+
+ return 0;
+}
+
+#else
+
+int
+ifaceGetMacaddr(const char *ifname,
+ unsigned char *macaddr)
+{
+ return ENOSYS;
+}
+
+#endif /* __linux__ */
+
+/**
+ * ifaceSetMacaddr:
+ * @ifname: interface name to set MTU for
+ * @macaddr: MAC address (VIR_MAC_BUFLEN in size)
+ *
+ * This function sets the @macaddr for a given interface @ifname. This
+ * gets rid of the kernel's automatically assigned random MAC.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef __linux__
+int
+ifaceSetMacaddr(const char *ifname,
+ const unsigned char *macaddr)
+{
+ struct ifreq ifr;
+ int fd;
+
+ if (!ifname)
+ return EINVAL;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if(fd < 0){
+ return errno;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
+ return EINVAL;
+
+ /* To fill ifr.ifr_hdaddr.sa_family field */
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0)
+ return errno;
+
+ memcpy(ifr.ifr_hwaddr.sa_data, macaddr, VIR_MAC_BUFLEN);
+
+ return ioctl(fd, SIOCSIFHWADDR, &ifr) == 0 ? 0 : errno;
+}
+
+#else
+
+int
+ifaceSetMacaddr(const char *ifname,
+ const unsigned char *macaddr)
+{
+ return ENOSYS;
+}
+
+#endif /* __linux__ */
Index: libvirt/src/util/interface.h
===================================================================
--- libvirt.orig/src/util/interface.h
+++ libvirt/src/util/interface.h
@@ -32,4 +32,8 @@ int ifaceGetIndex(bool reportError, cons
int ifaceGetVlanID(const char *vlanifname, int *vlanid);
+int ifaceSetMacaddr(const char *ifname, const unsigned char *macaddr);
+
+int ifaceGetMacaddr(const char *ifname, unsigned char *macaddr);
+
#endif /* __VIR_INTERFACE_H__ */
Index: libvirt/src/libvirt_private.syms
===================================================================
--- libvirt.orig/src/libvirt_private.syms
+++ libvirt/src/libvirt_private.syms
@@ -507,7 +507,9 @@ ifaceCheck;
ifaceCtrl;
ifaceGetFlags;
ifaceGetIndex;
+ifaceGetMacaddr;
ifaceGetVlanID;
+ifaceSetMacaddr;
ifaceIsUp;
===================================================================
Best regards,
Gerhard Stenzel
-------------------------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschaeftsfuehrung: Dirk Wittkopp
Sitz der Gesellschaft: Boeblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
13 years, 5 months
[libvirt] [PATCH 0/4] RFC: vcpupin: some improvements of virsh vcpupin command
by Taku Izumi
Hi all,
I'll resend this patchset because what sent yesterday was broken.
Sorry to be a nuisance.
---
This patchset improves virsh vcpupin command like the following:
(i) introduce special markup "-" and "^" which are similar to XML schema
of "cpuset" attribute
# virsh vcpupin VM 0 0-8,^4 --config
# virsh dumpxml VM
...
<vcpu>4</vcpu>
<cputune>
<vcpupin vcpu='0' cpuset='0-3,5-8'/>
</cputune>
...
(ii) allow to receive the special keyword 'r' as a cpulist parameter
when resetting vcpupin setting.
# virsh vcpupin VM 0 r --config
(iii) when resetting, that is, pinning the specified virtual cpu to
all host physical cpus, vcpupin setting will be deleted
# virsh dumpxml VM
...
<vcpu>4</vcpu>
<cputune>
</cputune>
...
The following my patchset is the prerequisite of this:
http://www.redhat.com/archives/libvir-list/2011-June/msg00441.html
*[PATCH 1/4] vcpupin: improve vcpupin definition of virsh vcpupin
*[PATCH 2/4] vcpupin: add reset option to virsh vcpupin command
*[PATCH 3/4] vcpupin: add virDomainVcpupinDel function
*[PATCH 4/4] vcpupin: add vcpupin resetting feature to qemu driver
Best regards,
Taku Izumi
13 years, 5 months