[libvirt] [RFC] [PATCH 2/3] vepa+vsi: add handling of 802.1Qbg using netlink messages
by Stefan Berger
This is so far a more or less experimental patch that adds code for
communicating with the external lldpad daemon using the recently added
netlink messages. It's communicating using multicast netlink messages in
case of 802.1Qbg and unicast using 802.1Qbh. In the multicast case I am
currently expecting an immediate response back from the (dummy) server
to indicate the status of the port profile setup (IFLA_PORT_RESPONSE). A
real server should probably then mimic the kernel driver and wait for a
RTM_GETLINK to return the response...
After adding netlink code for 802.1Qbg it wasn't difficult to add code
for 802.1Qbh anymore, so some code for 802.1Qbh is already here.
I am also adding detection code to configure.ac on whether the recently
added netlink messages and the defines are available and set the
WITH_VSI_VEPA #define if it is.
Lots of debugging output is still in this patch.
Signed-off-by: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
---
configure.ac | 16 +
src/util/macvtap.c | 595 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 604 insertions(+), 7 deletions(-)
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -27,7 +27,7 @@
#include <config.h>
-#if WITH_MACVTAP
+#if WITH_MACVTAP || WITH_VSI_VEPA
# include <stdio.h>
# include <errno.h>
@@ -41,6 +41,8 @@
# include <linux/rtnetlink.h>
# include <linux/if_tun.h>
+# include <netlink/msg.h>
+
# include "util.h"
# include "memory.h"
# include "logging.h"
@@ -58,6 +60,10 @@
# define MACVTAP_NAME_PREFIX "macvtap"
# define MACVTAP_NAME_PATTERN "macvtap%d"
+# define MICROSEC_PER_SEC (1000 * 1000)
+
+
+# define USE_IFLA_PORT_SELF
static int associatePortProfileId(const char *macvtap_ifname,
const virVSIProfileDefPtr vsi,
@@ -67,6 +73,11 @@ static int associatePortProfileId(const
static int disassociatePortProfileId(const char *macvtap_ifname,
const virVSIProfileDefPtr vsi);
+enum virVSIOp {
+ ASSOCIATE = 0x1,
+ DISASSOCIATE = 0x2,
+};
+
static int nlOpen(void)
{
@@ -159,6 +170,156 @@ err_exit:
}
+/**
+ * nlCommWaitSuccess:
+ *
+ * @nlmsg: pointer to netlink message
+ * @nl_grousp: the netlink multicast groups to send to
+ * @respbuf: pointer to pointer where response buffer will be allocated
+ * @respbuflen: pointer to integer holding the size of the response buffer
+ * on return of the function.
+ * @to_usecs: timeout in microseconds to wait for a success message
+ * to be returned
+ *
+ * Send the given message to the netlink multicast group and receive
+ * responses. Skip responses indicating an error and keep on receiving
+ * responses until a success response is returned.
+ * Returns 0 on success, -1 on error. In case of error, no response
+ * buffer will be returned.
+ */
+static int
+nlCommWaitSuccess(struct nlmsghdr *nlmsg, int nl_groups,
+ char **respbuf, int *respbuflen, long to_usecs)
+{
+ int rc = 0;
+ struct sockaddr_nl nladdr = {
+ .nl_family = AF_NETLINK,
+ .nl_pid = 0,
+ .nl_groups = nl_groups,
+ };
+ int rcvChunkSize = 1024; // expecting less than that
+ int rcvoffset = 0;
+ ssize_t nbytes;
+ int n;
+ struct timeval tv = {
+ .tv_sec = to_usecs / MICROSEC_PER_SEC,
+ .tv_usec = to_usecs % MICROSEC_PER_SEC,
+ };
+ fd_set rfds;
+ bool gotvalid = false;
+ int fd = nlOpen();
+ static uint32_t seq = 0x1234;
+ uint32_t myseq = seq++;
+ uint32_t mypid = getpid();
+
+ if (fd < 0)
+ return -1;
+
+ nlmsg->nlmsg_pid = mypid;
+ nlmsg->nlmsg_seq = myseq;
+ nlmsg->nlmsg_flags |= NLM_F_ACK;
+
+ nbytes = sendto(fd, (void *)nlmsg, nlmsg->nlmsg_len, 0,
+ (struct sockaddr *)&nladdr, sizeof(nladdr));
+ if (nbytes < 0) {
+ virReportSystemError(errno,
+ "%s", _("cannot send to netlink socket"));
+ rc = -1;
+ goto err_exit;
+ }
+ fprintf(stderr,"sent %d bytes\n", (int)nbytes);
+
+ while (!gotvalid) {
+ rcvoffset = 0;
+ while (1) {
+ socklen_t addrlen = sizeof(nladdr);
+
+ if (VIR_REALLOC_N(*respbuf, rcvoffset+rcvChunkSize) < 0) {
+ virReportOOMError();
+ rc = -1;
+ goto err_exit;
+ }
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ n = select(fd + 1, &rfds, NULL, NULL, &tv);
+ if (n == 0) {
+ fprintf(stderr,"Select timed out.\n");
+ rc = -1;
+ goto err_exit;
+ }
+
+ nbytes = recvfrom(fd, &((*respbuf)[rcvoffset]), rcvChunkSize, 0,
+ (struct sockaddr *)&nladdr, &addrlen);
+ fprintf(stderr,"got something... %d bytes\n",(int)nbytes);
+ if (nbytes < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ virReportSystemError(errno, "%s",
+ _("error receiving from netlink socket"));
+ rc = -1;
+ goto err_exit;
+ }
+ rcvoffset += nbytes;
+ break;
+ }
+ *respbuflen = rcvoffset;
+
+ /* check message for error */
+ if (*respbuflen > NLMSG_LENGTH(0) && *respbuf != NULL) {
+ struct nlmsghdr *resp = (struct nlmsghdr *)*respbuf;
+ struct nlmsgerr *err;
+
+ fprintf(stderr,"resp->nlmsg_type=%d\n", resp->nlmsg_type);
+ fprintf(stderr,"resp->nlmsg_flags=0x%x\n", resp->nlmsg_flags);
+ fprintf(stderr,"resp->nlmsg_seq=%d (%d)\n", resp->nlmsg_seq, myseq);
+ fprintf(stderr,"resp->nlmsg_pid=%d (%d)\n", resp->nlmsg_pid, mypid);
+
+ if (resp->nlmsg_pid != mypid ||
+ resp->nlmsg_seq != myseq)
+ continue;
+
+ switch (resp->nlmsg_type) {
+ default:
+ case NLMSG_ERROR:
+ err = (struct nlmsgerr *)NLMSG_DATA(resp);
+ if (resp->nlmsg_len >= NLMSG_LENGTH(sizeof(*err))) {
+ fprintf(stderr,"error %d\n", -err->error);
+ if (-err->error != EOPNOTSUPP) {
+ /* assuming error msg from daemon */
+ fprintf(stderr,"Got error %d, but assuming its response from lldpad: len = %d\n",
+ -err->error,
+ *respbuflen);
+ gotvalid = true;
+ break;
+ }
+ }
+ /* whatever this is, skip it */
+ VIR_FREE(*respbuf);
+ *respbuf = NULL;
+ *respbuflen = 0;
+ fprintf(stderr,"Skipping error resp. msg.\n");
+ break;
+ case NLMSG_DONE:
+ gotvalid = true;
+ break;
+ }
+ }
+ }
+
+err_exit:
+ if (rc == -1) {
+ VIR_FREE(*respbuf);
+ *respbuf = NULL;
+ *respbuflen = 0;
+ }
+
+ nlClose(fd);
+ return rc;
+}
+
+
static struct rtattr *
rtattrCreate(char *buffer, int bufsize, int type,
const void *data, int datalen)
@@ -204,6 +365,8 @@ nlAppend(struct nlmsghdr *nlm, int totle
}
+# if WITH_MACVTAP
+
static int
link_add(const char *type,
const unsigned char *macaddress, int macaddrsize,
@@ -652,7 +815,7 @@ create_name:
rc = associatePortProfileId(cr_ifname,
&net->data.direct.vsiProfile,
- -1,
+ PORT_SELF_VF,
vmuuid);
if (rc != 0)
goto link_del_exit;
@@ -711,8 +874,422 @@ delMacvtap(virDomainNetDefPtr net)
}
}
-#endif
+# endif
+
+
+# ifdef IFLA_PORT_MAX
+
+static struct nla_policy ifla_policy[IFLA_MAX + 1] =
+{
+ [IFLA_VF_PORTS] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy ifla_vf_ports_policy[IFLA_VF_PORT_MAX + 1] =
+{
+ [IFLA_VF_PORT] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] =
+{
+ [IFLA_PORT_RESPONSE] = { .type = NLA_U16 },
+};
+
+
+static int
+getPortProfileStatus(struct nlmsghdr *nlm, uint16_t *status)
+{
+ int rc = 1;
+ const char *msg = NULL;
+ struct nlattr *tb[IFLA_MAX+1],
+ *tb2[IFLA_VF_PORT_MAX + 1],
+ *tb3[IFLA_PORT_MAX+1];
+
+ if (nlmsg_parse(nlm, sizeof(struct ifinfomsg),
+ (struct nlattr **)&tb, IFLA_MAX, ifla_policy)) {
+ msg = _("error parsing netlink response.\n");
+ goto err_exit;
+ }
+
+# ifndef USE_IFLA_PORT_SELF
+ if (tb[IFLA_VF_PORTS]) {
+ if (nla_parse_nested(tb2, IFLA_VF_PORT_MAX, tb[IFLA_VF_PORTS],
+ ifla_vf_ports_policy)) {
+ msg = _("error parsing nested IFLA_VF_PORTS part");
+ goto err_exit;
+ }
+ if (tb2[IFLA_VF_PORT]) {
+ if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb2[IFLA_VF_PORT],
+ ifla_port_policy)) {
+ msg = _("error parsing nested IFLA_VF_PORT part");
+ goto err_exit;
+ }
+# else
+ (void)tb2;
+ (void)ifla_vf_ports_policy;
+ if (tb[IFLA_PORT_SELF]) {
+ if (1) {
+ if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb[IFLA_PORT_SELF],
+ ifla_port_policy)) {
+ msg = _("error parsing nested IFLA_VF_PORT part");
+ goto err_exit;
+ }
+# endif
+
+ if (tb3[IFLA_PORT_RESPONSE]) {
+ *status = *(uint16_t *)RTA_DATA(tb3[IFLA_PORT_RESPONSE]);
+ rc = 0;
+ } else {
+ msg = _("no IFLA_PORT_RESPONSE found in netlink message");
+ goto err_exit;
+ }
+ } else {
+ msg = _("no IFLA_VF_PORT found in netlink message");
+ goto err_exit;
+ }
+ } else {
+ msg = _("no IFLA_VF_PORTS found in netlink message");
+ goto err_exit;
+ }
+
+ err_exit:
+ if (msg)
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", msg);
+
+ return rc;
+}
+
+
+static int
+doPortProfileOpSetLink(bool multicast,
+ const char *ifname, int ifindex,
+ const char *profileId,
+ struct ifla_port_vsi *portVsi,
+ const unsigned char *instanceId,
+ const unsigned char *hostUUID,
+ int32_t vf,
+ uint8_t op)
+{
+ int rc = 0;
+ char nlmsgbuf[256];
+ struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
+ struct nlmsgerr *err;
+ char rtattbuf[64];
+ struct rtattr *rta, *vfports, *vfport;
+ struct ifinfomsg ifinfo = {
+ .ifi_family = AF_UNSPEC,
+ .ifi_index = ifindex,
+ };
+ char *recvbuf = NULL;
+ int recvbuflen = 0;
+ uint16_t status;
+
+ memset(&nlmsgbuf, 0, sizeof(nlmsgbuf));
+
+ nlInit(nlm, NLM_F_REQUEST, RTM_SETLINK);
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), &ifinfo, sizeof(ifinfo)))
+ goto buffer_too_small;
+
+# ifndef USE_IFLA_PORT_SELF
+
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_PORTS, NULL, 0);
+ if (!rta)
+ goto buffer_too_small;
+
+ if (!(vfports = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)))
+ goto buffer_too_small;
+
+ /* beging nesting vfports */
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_PORT, NULL, 0);
+# else
+ (void)vfports;
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_SELF, NULL, 0);
+# endif
+ if (!rta)
+ goto buffer_too_small;
+
+ if (!(vfport = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)))
+ goto buffer_too_small;
+
+ /* begin nesting of vfport */
+ if (profileId) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_PROFILE,
+ profileId, strlen(profileId) + 1);
+ if (!rta)
+ goto buffer_too_small;
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+
+ if (portVsi) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_VSI_TYPE,
+ portVsi, sizeof(*portVsi));
+ if (!rta)
+ goto buffer_too_small;
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+
+ if (instanceId) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_INSTANCE_UUID,
+ instanceId, VIR_UUID_BUFLEN);
+ if (!rta)
+ goto buffer_too_small;
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+ if (hostUUID) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_HOST_UUID,
+ hostUUID, VIR_UUID_BUFLEN);
+ if (!rta)
+ goto buffer_too_small;
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+
+ if (vf >= 0) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_VF,
+ &vf, sizeof(vf));
+ if (!rta)
+ goto buffer_too_small;
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_REQUEST,
+ &op, sizeof(op));
+ if (!rta)
+ goto buffer_too_small;
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+
+ /* end nesting of vport */
+ vfport->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)vfport;
+
+# ifndef USE_IFLA_PORT_SELF
+ /* end nesting of vfports */
+ vfports->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)vfports;
+# endif
+
+ if (!multicast) {
+ if (nlComm(nlm, &recvbuf, &recvbuflen) < 0)
+ return -1;
+ } else {
+ if (nlCommWaitSuccess(nlm, RTMGRP_LINK, &recvbuf, &recvbuflen,
+ 5 * MICROSEC_PER_SEC) < 0)
+ return -1;
+ }
+
+ 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;
+
+ default:
+ virReportSystemError(-err->error,
+ _("error during VSI configuration of %s interface"), ifname);
+ rc = -1;
+ }
+ break;
+
+ case NLMSG_DONE:
+ rc = getPortProfileStatus(resp, &status);
+ if (rc == 0 && status != PORT_VDP_RESPONSE_SUCCESS) {
+ macvtapError(VIR_ERR_INTERNAL_ERROR,
+ _("Response code from port profile setup: %d"),
+ status);
+ rc = -1;
+ }
+ break;
+
+ default:
+ goto malformed_resp;
+ }
+
+ VIR_FREE(recvbuf);
+
+ return rc;
+
+malformed_resp:
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed netlink response message"));
+ VIR_FREE(recvbuf);
+ return -1;
+
+buffer_too_small:
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("internal buffer is too small"));
+ return -1;
+}
+
+
+static int
+doPortProfileOpCommon(bool multicast,
+ const char *ifname, int ifindex,
+ const char *profileId,
+ struct ifla_port_vsi *portVsi,
+ const unsigned char *instanceId,
+ const unsigned char *hostUUID,
+ int32_t vf,
+ uint8_t op)
+{
+ int rc;
+
+ rc = doPortProfileOpSetLink(multicast,
+ ifname, ifindex,
+ profileId,
+ portVsi,
+ instanceId,
+ hostUUID,
+ vf,
+ op);
+
+ if (rc != 0) {
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Sending of PortProfileRequest failed.\n"));
+ return rc;
+ }
+
+ return rc;
+}
+
+# endif /* IFLA_PORT_MAX */
+
+static int
+doPortProfileOp8021Qbg(const char *ifname,
+ const virVSIProfileDefPtr vsi,
+ int32_t vf,
+ enum virVSIOp vsiOp)
+{
+ int rc;
+
+# ifndef IFLA_VF_PORT_MAX
+
+ (void)ifname;
+ (void)vsi;
+ (void)vf;
+ (void)vsiOp;
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Kernel VF Port support was missing at compile time."));
+ rc = 1;
+
+# else /* IFLA_VF_PORT_MAX */
+
+ int op = PORT_REQUEST_ASSOCIATE;
+ struct ifla_port_vsi portVsi = {
+ .vsi_mgr_id = vsi->u.vsi8021Qbg.managerID,
+ .vsi_type_version = vsi->u.vsi8021Qbg.typeIDVersion,
+ };
+ bool multicast = true;
+ int ifindex;
+
+ if (ifaceGetIndex(true, ifname, &ifindex) != 0) {
+ rc = 1;
+ goto err_exit;
+ }
+
+ portVsi.vsi_type_id[2] = vsi->u.vsi8021Qbg.typeID >> 16;
+ portVsi.vsi_type_id[1] = vsi->u.vsi8021Qbg.typeID >> 8;
+ portVsi.vsi_type_id[0] = vsi->u.vsi8021Qbg.typeID;
+
+ switch (vsiOp) {
+ case ASSOCIATE:
+ op = PORT_REQUEST_ASSOCIATE;
+ break;
+ case DISASSOCIATE:
+ op = PORT_REQUEST_DISASSOCIATE;
+ break;
+ default:
+ macvtapError(VIR_ERR_INTERNAL_ERROR,
+ _("operation type %d not supported"), op);
+ rc = 1;
+ goto err_exit;
+ }
+
+ rc = doPortProfileOpCommon(multicast, NULL, ifindex,
+ NULL,
+ &portVsi,
+ vsi->u.vsi8021Qbg.instanceID,
+ NULL,
+ vf,
+ op);
+
+err_exit:
+
+# endif /* IFLA_VF_PORT_MAX */
+
+ return rc;
+}
+
+
+static int
+doPortProfileOp8021Qbh(const virVSIProfileDefPtr vsi,
+ const unsigned char *host_uuid,
+ const unsigned char *vm_uuid,
+ enum virVSIOp vsiOp)
+{
+ int rc;
+
+# ifndef IFLA_VF_PORT_MAX
+
+ (void)vsi;
+ (void)host_uuid;
+ (void)vm_uuid;
+ (void)vsiOp;
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Kernel VF Port support was missing at compile time."));
+ rc = 1;
+
+# else /* IFLA_VF_PORT_MAX */
+
+ int op = PORT_REQUEST_ASSOCIATE;
+ bool multicast = false;
+
+ switch (vsiOp) {
+ case ASSOCIATE:
+ op = PORT_REQUEST_ASSOCIATE;
+ break;
+ case DISASSOCIATE:
+ op = PORT_REQUEST_DISASSOCIATE;
+ break;
+ default:
+ macvtapError(VIR_ERR_INTERNAL_ERROR,
+ _("operation type %d not supported"), op);
+ rc = 1;
+ goto err_exit;
+ }
+
+ rc = doPortProfileOpCommon(multicast, NULL, -1,
+ vsi->u.vsi8021Qbh.profileID,
+ NULL,
+ host_uuid,
+ vm_uuid,
+ -1,
+ op);
+
+err_exit:
+
+# endif /* IFLA_VF_PORT_MAX */
+
+ return rc;
+}
/**
* associatePortProfile
@@ -749,11 +1326,13 @@ associatePortProfileId(const char *macvt
break;
case VIR_VSI_8021QBG:
-
+ rc = doPortProfileOp8021Qbg(macvtap_ifname, vsi, vf,
+ ASSOCIATE);
break;
case VIR_VSI_8021QBH:
-
+ rc = doPortProfileOp8021Qbh(vsi, vmuuid /* host_uuid */, vmuuid,
+ ASSOCIATE);
break;
}
@@ -784,13 +1363,17 @@ disassociatePortProfileId(const char *ma
break;
case VIR_VSI_8021QBG:
-
+ rc = doPortProfileOp8021Qbg(macvtap_ifname, vsi, -1,
+ DISASSOCIATE);
break;
case VIR_VSI_8021QBH:
-
+ rc = doPortProfileOp8021Qbh(vsi, NULL, NULL,
+ DISASSOCIATE);
break;
}
return rc;
}
+
+#endif
Index: libvirt-acl/configure.ac
===================================================================
--- libvirt-acl.orig/configure.ac
+++ libvirt-acl/configure.ac
@@ -2005,13 +2005,26 @@ if test "$with_macvtap" != "no" ; then
fi
AM_CONDITIONAL([WITH_MACVTAP], [test "$with_macvtap" = "yes"])
+AC_TRY_COMPILE([ #include <sys/socket.h>
+ #include <linux/rtnetlink.h> ],
+ [ int x = IFLA_PORT_MAX; ],
+ [ with_vsi_vepa=yes ],
+ [ with_vsi_vepa=no ])
+if test "$with_vsi_vepa" = "yes"; then
+ val=1
+else
+ val=0
+fi
+AC_DEFINE_UNQUOTED([WITH_VSI_VEPA], $val, [whether vsi vepa support is enabled])
+AM_CONDITIONAL([WITH_VSI_VEPA], [test "$with_vsi_vepa" = "yes"])
+
dnl netlink library
LIBNL_CFLAGS=""
LIBNL_LIBS=""
-if test "$with_macvtap" = "yes"; then
+if test "$with_macvtap" = "yes" || "$with_vsi_vepa" = "yes"; then
PKG_CHECK_MODULES([LIBNL], [libnl-1 >= $LIBNL_REQUIRED], [
], [
AC_MSG_ERROR([libnl >= $LIBNL_REQUIRED is required for macvtap support])
@@ -2084,6 +2097,7 @@ AC_MSG_NOTICE([ Network: $with_network])
AC_MSG_NOTICE([Libvirtd: $with_libvirtd])
AC_MSG_NOTICE([ netcf: $with_netcf])
AC_MSG_NOTICE([ macvtap: $with_macvtap])
+AC_MSG_NOTICE([vsi-vepa: $with_vsi_vepa])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Storage Drivers])
AC_MSG_NOTICE([])
14 years, 11 months
[libvirt] [RFC] [PATCH 1/3] vepa+vsi: Introduce dependency on libnl
by Stefan Berger
This patch introduces a dependency on libnl, which subsequent patches
will then use.
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
Index: libvirt-acl/configure.ac
===================================================================
--- libvirt-acl.orig/configure.ac
+++ libvirt-acl/configure.ac
@@ -42,6 +42,7 @@ HAL_REQUIRED=0.5.0
DEVMAPPER_REQUIRED=1.0.0
LIBCURL_REQUIRED="7.18.0"
LIBPCAP_REQUIRED="1.0.0"
+LIBNL_REQUIRED="1.1"
dnl Checks for C compiler.
AC_PROG_CC
@@ -2005,6 +2006,24 @@ fi
AM_CONDITIONAL([WITH_MACVTAP], [test "$with_macvtap" = "yes"])
+dnl netlink library
+
+LIBNL_CFLAGS=""
+LIBNL_LIBS=""
+
+if test "$with_macvtap" = "yes"; then
+ PKG_CHECK_MODULES([LIBNL], [libnl-1 >= $LIBNL_REQUIRED], [
+ ], [
+ AC_MSG_ERROR([libnl >= $LIBNL_REQUIRED is required for macvtap support])
+ ])
+fi
+
+AC_SUBST([LIBNL_CFLAGS])
+AC_SUBST([LIBNL_LIBS])
+
+
+
+
# Only COPYING.LIB is under version control, yet COPYING
# is included as part of the distribution tarball.
# Copy one to the other, but only if this is a srcdir-build.
@@ -2183,6 +2202,11 @@ AC_MSG_NOTICE([ pcap: $LIBPCAP_CFLAGS
else
AC_MSG_NOTICE([ pcap: no])
fi
+if test "$with_macvtap" = "yes" ; then
+AC_MSG_NOTICE([ nl: $LIBNL_CFLAGS $LIBNL_LIBS])
+else
+AC_MSG_NOTICE([ nl: no])
+fi
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Test suite])
AC_MSG_NOTICE([])
Index: libvirt-acl/libvirt.spec.in
===================================================================
--- libvirt-acl.orig/libvirt.spec.in
+++ libvirt-acl/libvirt.spec.in
@@ -63,6 +63,7 @@
%define with_yajl 0%{!?_without_yajl:0}
%define with_nwfilter 0%{!?_without_nwfilter:0}
%define with_libpcap 0%{!?_without_libpcap:0}
+%define with_macvtap 0%{!?_without_macvtap:0}
# Non-server/HV driver defaults which are always enabled
%define with_python 0%{!?_without_python:1}
@@ -153,6 +154,11 @@
%if %{with_qemu}
%define with_nwfilter 0%{!?_without_nwfilter:%{server_drivers}}
%define with_libpcap 0%{!?_without_libpcap:%{server_drivers}}
+%define with_macvtap 0%{!?_without_macvtap:%{server_drivers}}
+%endif
+
+%if %{with_macvtap}
+%define with_libnl 1
%endif
# Force QEMU to run as non-root
@@ -282,6 +288,9 @@ BuildRequires: yajl-devel
%if %{with_libpcap}
BuildRequires: libpcap-devel
%endif
+%if %{with_libnl}
+BuildRequires: libnl-devel
+%endif
%if %{with_avahi}
BuildRequires: avahi-devel
%endif
@@ -531,6 +540,10 @@ of recent versions of Linux (and other O
%define _without_libpcap --without-libpcap
%endif
+%if ! %{with_macvtap}
+%define _without_macvtap --without-macvtap
+%endif
+
%configure %{?_without_xen} \
%{?_without_qemu} \
%{?_without_openvz} \
@@ -560,6 +573,7 @@ of recent versions of Linux (and other O
%{?_without_udev} \
%{?_without_yajl} \
%{?_without_libpcap} \
+ %{?_without_macvtap} \
--with-qemu-user=%{qemu_user} \
--with-qemu-group=%{qemu_group} \
--with-init-script=redhat \
Index: libvirt-acl/src/Makefile.am
===================================================================
--- libvirt-acl.orig/src/Makefile.am
+++ libvirt-acl/src/Makefile.am
@@ -997,7 +997,7 @@ libvirt_la_LDFLAGS = $(VERSION_SCRIPT_FL
$(CYGWIN_EXTRA_LDFLAGS) $(MINGW_EXTRA_LDFLAGS)
libvirt_la_BUILT_LIBADD += ../gnulib/lib/libgnu.la
libvirt_la_LIBADD += $(LIBXML_LIBS) \
- $(LIBPCAP_LIBS) \
+ $(LIBPCAP_LIBS) $(LIBNL_LIBS) \
$(DRIVER_MODULE_LIBS) \
$(CYGWIN_EXTRA_LIBADD)
libvirt_la_CFLAGS = $(COVERAGE_CFLAGS) -DIN_LIBVIRT
@@ -1056,7 +1056,7 @@ libvirt_lxc_SOURCES = \
libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDFLAGS)
libvirt_lxc_LDADD = $(CAPNG_LIBS) $(YAJL_LIBS) \
$(LIBXML_LIBS) $(NUMACTL_LIBS) $(LIB_PTHREAD) \
- ../gnulib/lib/libgnu.la
+ $(LIBNL_LIBS) ../gnulib/lib/libgnu.la
libvirt_lxc_CFLAGS = \
$(LIBPARTED_CFLAGS) \
$(NUMACTL_CFLAGS) \
14 years, 11 months
[libvirt] VIR_ERROR and VIR_DEBUG normalization
by Jim Meyering
Most of the following changes have been induced automatically.
The few outliers done manually are marked as such.
[PATCH 01/10] maint: use VIR_ERROR0 rather than VIR_ERROR with a bare "%s"
[PATCH 02/10] maint: mark translatable string args of VIR_ERROR0
[PATCH 03/10] maint: mark translatable string args of VIR_ERROR
[PATCH 04/10] maint: VIR_ERROR/VIR_ERROR0: mark up the remaining ones manually
[PATCH 05/10] maint: more of same, but manual: convert VIR_ERROR("%s" to VIR_ERROR0(
[PATCH 06/10] maint: change "" in err ? err->message : "" to _("unknown error"), ...
[PATCH 07/10] maint: enforce policy wrt VIR_ERROR and VIR_ERROR0
[PATCH 08/10] maint: don't mark VIR_DEBUG or VIR_DEBUG0 diagnostics for translation
[PATCH 09/10] maint: enforce policy wrt VIR_DEBUG and VIR_DEBUG0
[PATCH 10/10] maint: update po/POTFILES.in
14 years, 11 months
[libvirt] [PATCH v2] qemu: Use ShutdownVMDaemon for all startup cleanup paths
by Cole Robinson
The current cleanup: in StartVMDaemon path is a poor duplication.
qemuShutdownVMDaemon can handle teardown for inactive VMs, so let's use it.
v2: Remove old abort: label, only use cleanup:
Signed-off-by: Cole Robinson <crobinso(a)redhat.com>
---
src/qemu/qemu_driver.c | 37 ++++++++++---------------------------
1 files changed, 10 insertions(+), 27 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d387e69..3823dbd 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3516,29 +3516,29 @@ static int qemudStartVMDaemon(virConnectPtr conn,
DEBUG0("Waiting for monitor to show up");
if (qemudWaitForMonitor(driver, vm, pos) < 0)
- goto abort;
+ goto cleanup;
DEBUG0("Detecting VCPU PIDs");
if (qemuDetectVcpuPIDs(driver, vm) < 0)
- goto abort;
+ goto cleanup;
DEBUG0("Setting any required VM passwords");
if (qemuInitPasswords(conn, driver, vm, qemuCmdFlags) < 0)
- goto abort;
+ goto cleanup;
/* If we have -device, then addresses are assigned explicitly.
* If not, then we have to detect dynamic ones here */
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
DEBUG0("Determining domain device PCI addresses");
if (qemuInitPCIAddresses(driver, vm) < 0)
- goto abort;
+ goto cleanup;
}
DEBUG0("Setting initial memory amount");
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuMonitorSetBalloon(priv->mon, vm->def->memory) < 0) {
qemuDomainObjExitMonitorWithDriver(driver, vm);
- goto abort;
+ goto cleanup;
}
if (migrateFrom == NULL) {
@@ -3549,7 +3549,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
qemuReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("resume operation failed"));
qemuDomainObjExitMonitorWithDriver(driver, vm);
- goto abort;
+ goto cleanup;
}
}
qemuDomainObjExitMonitorWithDriver(driver, vm);
@@ -3557,7 +3557,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
DEBUG0("Writing domain status to disk");
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
- goto abort;
+ goto cleanup;
if (logfile != -1)
close(logfile);
@@ -3565,26 +3565,9 @@ static int qemudStartVMDaemon(virConnectPtr conn,
return 0;
cleanup:
- /* We jump here if we failed to start the VM for any reason
- * XXX investigate if we can kill this block and safely call
- * qemudShutdownVMDaemon even though no PID is running */
- qemuDomainReAttachHostDevices(driver, vm->def);
-
- if (driver->securityDriver &&
- driver->securityDriver->domainRestoreSecurityAllLabel)
- driver->securityDriver->domainRestoreSecurityAllLabel(vm, 0);
- if (driver->securityDriver &&
- driver->securityDriver->domainReleaseSecurityLabel)
- driver->securityDriver->domainReleaseSecurityLabel(vm);
- qemuRemoveCgroup(driver, vm, 1);
- if (logfile != -1)
- close(logfile);
- vm->def->id = -1;
- return -1;
-
-abort:
- /* We jump here if we failed to initialize the now running VM
- * killing it off and pretend we never started it */
+ /* We jump here if we failed to start the VM for any reason, or
+ * if we failed to initialize the now running VM. kill it off and
+ * pretend we never started it */
qemudShutdownVMDaemon(driver, vm, 0);
if (logfile != -1)
--
1.6.6.1
14 years, 11 months
[libvirt] [PATCH] daemon: A few initscript corrections
by Cole Robinson
Fedora bug https://bugzilla.redhat.com/show_bug.cgi?id=565238
- Avahi service is called 'avahi-daemon'
- chkconfig descriptions must use \ for line continuations
Signed-off-by: Cole Robinson <crobinso(a)redhat.com>
---
daemon/libvirtd.init.in | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/daemon/libvirtd.init.in b/daemon/libvirtd.init.in
index d4dc98b..809433e 100644
--- a/daemon/libvirtd.init.in
+++ b/daemon/libvirtd.init.in
@@ -9,7 +9,7 @@
# Should-Start: $named
# Should-Start: xend
# Should-Start: hal
-# Should-Start: avahi
+# Should-Start: avahi-daemon
# Required-Stop: $network messagebus
# Should-Stop: $named
# Default-Start: 3 4 5
@@ -24,8 +24,8 @@
# libvirtd: guest and virtual network management daemon
#
# chkconfig: 345 97 03
-# description: This is a daemon for managing guest instances
-# and libvirt virtual networks
+# description: This is a daemon for managing guest instances \
+# and libvirt virtual networks \
# See http://libvirt.org
#
# processname: libvirtd
--
1.6.6.1
14 years, 11 months
Re: [libvirt] libvirt and Ruby
by Chris Lalancette
On 05/20/2010 01:53 PM, Jaromír Červenka wrote:
> Hi Chris,
>
> thank you for your answer. That will be great! :) I decided that I
> will write this deamon with Ruby and with old ruby bindings at least,
> so this is good news for me :)
>
> My friend from suse (Michal Hrusecky) did two patches till now - one
> is for virNodeGetFreememory a the second implements
> virConnectGetLibVersion. He sent these patches to David Lutterkort,
> but without answer. Do you want them?
>
> Sorry for my EN :/
(please leave the list CC'ed; other people might be interested in the
status of the Ruby bindings).
Your English is just fine :). If you could send those patches to the libvirt
list (and CC me), that would be great; I also have commit access to the ruby
repository, so assuming they are OK I can add them.
Thanks,
--
Chris Lalancette
14 years, 11 months
[libvirt] [PATCH] qemu: Genericize tapfds/ntapfds
by Alex Williamson
There doesn't seem to be anything specific to tap devices for this
array of file descriptors which need to stay open of the guest to use.
Rename then for others to make use of.
Signed-off-by: Alex Williamson <alex.williamson(a)redhat.com>
---
src/qemu/qemu_conf.c | 28 ++++++++++++++--------------
src/qemu/qemu_driver.c | 18 +++++++++---------
2 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 3e334dc..d7bc798 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -3422,8 +3422,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
unsigned long long qemuCmdFlags,
const char ***retargv,
const char ***retenv,
- int **tapfds,
- int *ntapfds,
+ int **vmfds,
+ int *nvmfds,
const char *migrateFrom,
virDomainSnapshotObjPtr current_snapshot)
{
@@ -4116,7 +4116,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
if (tapfd < 0)
goto error;
- if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) {
+ if (VIR_REALLOC_N(*vmfds, (*nvmfds)+1) < 0) {
virNWFilterTearNWFilter(net);
close(tapfd);
goto no_memory;
@@ -4124,7 +4124,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
last_good_net = i;
- (*tapfds)[(*ntapfds)++] = tapfd;
+ (*vmfds)[(*nvmfds)++] = tapfd;
if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", tapfd) >= sizeof(tapfd_name))
goto no_memory;
@@ -4136,7 +4136,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
if (tapfd < 0)
goto error;
- if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) {
+ if (VIR_REALLOC_N(*vmfds, (*nvmfds)+1) < 0) {
virNWFilterTearNWFilter(net);
close(tapfd);
goto no_memory;
@@ -4144,7 +4144,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
last_good_net = i;
- (*tapfds)[(*ntapfds)++] = tapfd;
+ (*vmfds)[(*nvmfds)++] = tapfd;
if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", tapfd) >= sizeof(tapfd_name))
goto no_memory;
@@ -4157,12 +4157,12 @@ int qemudBuildCommandLine(virConnectPtr conn,
network device */
int vhostfd = qemudOpenVhostNet(net, qemuCmdFlags);
if (vhostfd >= 0) {
- if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) {
+ if (VIR_REALLOC_N(*vmfds, (*nvmfds)+1) < 0) {
close(vhostfd);
goto no_memory;
}
- (*tapfds)[(*ntapfds)++] = vhostfd;
+ (*vmfds)[(*nvmfds)++] = vhostfd;
if (snprintf(vhostfd_name, sizeof(vhostfd_name), "%d", vhostfd)
>= sizeof(vhostfd_name))
goto no_memory;
@@ -4653,12 +4653,12 @@ int qemudBuildCommandLine(virConnectPtr conn,
error:
for (i = 0; i <= last_good_net; i++)
virNWFilterTearNWFilter(def->nets[i]);
- if (tapfds &&
- *tapfds) {
- for (i = 0; i < *ntapfds; i++)
- close((*tapfds)[i]);
- VIR_FREE(*tapfds);
- *ntapfds = 0;
+ if (vmfds &&
+ *vmfds) {
+ for (i = 0; i < *nvmfds; i++)
+ close((*vmfds)[i]);
+ VIR_FREE(*vmfds);
+ *nvmfds = 0;
}
if (qargv) {
for (i = 0 ; i < qargc ; i++)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 65ca117..dd5bd24 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3253,8 +3253,8 @@ static int qemudStartVMDaemon(virConnectPtr conn,
const char **progenv = NULL;
int i, ret;
struct stat sb;
- int *tapfds = NULL;
- int ntapfds = 0;
+ int *vmfds = NULL;
+ int nvmfds = 0;
unsigned long long qemuCmdFlags;
fd_set keepfd;
const char *emulator;
@@ -3411,7 +3411,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
vm->def->id = driver->nextvmid++;
if (qemudBuildCommandLine(conn, driver, vm->def, priv->monConfig,
priv->monJSON, qemuCmdFlags, &argv, &progenv,
- &tapfds, &ntapfds, migrateFrom,
+ &vmfds, &nvmfds, migrateFrom,
vm->current_snapshot) < 0)
goto cleanup;
@@ -3462,8 +3462,8 @@ static int qemudStartVMDaemon(virConnectPtr conn,
VIR_WARN("Unable to seek to end of logfile: %s",
virStrerror(errno, ebuf, sizeof ebuf));
- for (i = 0 ; i < ntapfds ; i++)
- FD_SET(tapfds[i], &keepfd);
+ for (i = 0 ; i < nvmfds ; i++)
+ FD_SET(vmfds[i], &keepfd);
ret = virExecDaemonize(argv, progenv, &keepfd, &child,
stdin_fd, &logfile, &logfile,
@@ -3504,11 +3504,11 @@ static int qemudStartVMDaemon(virConnectPtr conn,
if (ret == -1) /* The VM failed to start; tear filters before taps */
virNWFilterTearVMNWFilters(vm);
- if (tapfds) {
- for (i = 0 ; i < ntapfds ; i++) {
- close(tapfds[i]);
+ if (vmfds) {
+ for (i = 0 ; i < nvmfds ; i++) {
+ close(vmfds[i]);
}
- VIR_FREE(tapfds);
+ VIR_FREE(vmfds);
}
if (ret == -1) /* The VM failed to start */
14 years, 11 months
[libvirt] [PATCH] qemu driver: fix version check typos
by Chris Wright
Looks like some cut'n paste error to me.
Signed-off-by: Chris Wright <chrisw(a)redhat.com>
---
src/qemu/qemu_conf.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 3e334dc..6d2ac6e 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1291,13 +1291,13 @@ int qemudParseHelpStr(const char *qemu,
++p;
minor = virParseNumber(&p);
- if (major == -1 || *p != '.')
+ if (minor == -1 || *p != '.')
goto fail;
++p;
micro = virParseNumber(&p);
- if (major == -1)
+ if (micro == -1)
goto fail;
SKIP_BLANKS(p);
14 years, 11 months
[libvirt] How to enable vhost for virtIO NIC?
by Huang, Zhiteng
Hi gurus on the list,
I'm trying to bring up a Linux with virtio vhost backend. My system is running on kernel 2.6.34-rc7, libvirt 0.8.0.
Two questions regarding to vhost:
1) XML format for vhost
I didn't find any documents on libvirt.org description the XML or QMU argument format for vhost.
According to http://www.linux-kvm.org/page/VhostNet#vhost-net_driver_projects, I tried *domxml-from-native* to convert following qemu argument to XML
qemu-system-x86_64 -m 1G disk-c.qcow2 \
-net nic,model=virtio,netdev=foo \
-netdev tap,id=foo,ifname=msttap0,script=/home/mst/ifup,downscript=no,vhost=on
But the output clearly ignore the network.
<domain type='qemu'>
<name>unnamed</name>
<uuid>9cc877c1-7ac2-463d-3d3f-fa8f8918fe23</uuid>
<memory>1048576</memory>
<currentMemory>1048576</currentMemory>
<vcpu>1</vcpu>
<os>
<type arch='x86_64'>hvm</type>
</os>
<features>
<acpi/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>qemu-system-x86_64</emulator>
<input type='mouse' bus='ps2'/>
<graphics type='sdl'/>
<video>
<model type='cirrus' vram='9216' heads='1'/>
</video>
</devices>
</domain>
What's the problem here?
2) Virtio driver.
It's said that vhost require guest kernel version > 2.6.31 because vhost requires MSI-X. How about frontend of virtio driver? Say I'm running a Windows 2008 (with MSI-X support) + virtio NIC, is it necessary to upgrade frontend driver too?
Regards,
HUANG, Zhiteng
14 years, 11 months
[libvirt] [PATCH 0/4] qemu: Unify cleanup paths in qemuStartVMDaemon
by Cole Robinson
Many of the cleanup paths in qemuStartVMDaemon have the potential of
squashing a legitimate startup error message. qemuShutdownVMDaemon
already properly handles this, so let's unify all the cleanup to use it.
This series fixes a few teardown issues, and changes ShutdownVMDaemon to
not reject non-running VMs. This could be an issue if some caller was
depending on this functionality, but I couldn't find one.
Cole Robinson (4):
qemu: Properly cleanup in security startup error path
qemu: Remove explicit VNC XML cleanup
qemu: Don't deny ShutdownVMDaemon for non-running VMs
qemu: Use ShutdownVMDaemon for all startup cleanup paths
src/qemu/qemu_driver.c | 31 +++++--------------------------
1 files changed, 5 insertions(+), 26 deletions(-)
14 years, 11 months