Devel
Threads by month
- ----- 2026 -----
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
May 2010
- 56 participants
- 296 discussions
13 May '10
Setting dynamic_ownership=0 in /etc/libvirt/qemu.conf prevents
libvirt's DAC security driver from setting uid/gid on disk
files when starting/stopping QEMU, allowing the admin to manage
this manually. As a side effect it also stopped setting of
uid/gid when saving guests to a file, which completely breaks
save when QEMU is running non-root. Thus saved state labelling
code must ignore the dynamic_ownership parameter
* src/qemu/qemu_security_dac.c: Ignore dynamic_ownership=0 when
doing save/restore image labelling
---
src/qemu/qemu_security_dac.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
index 2d42ce2..364227d 100644
--- a/src/qemu/qemu_security_dac.c
+++ b/src/qemu/qemu_security_dac.c
@@ -407,7 +407,7 @@ static int
qemuSecurityDACSetSavedStateLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
const char *savefile)
{
- if (!driver->privileged || !driver->dynamicOwnership)
+ if (!driver->privileged)
return 0;
return qemuSecurityDACSetOwnership(savefile, driver->user, driver->group);
@@ -418,7 +418,7 @@ static int
qemuSecurityDACRestoreSavedStateLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
const char *savefile)
{
- if (!driver->privileged || !driver->dynamicOwnership)
+ if (!driver->privileged)
return 0;
return qemuSecurityDACRestoreSecurityFileLabel(savefile);
--
1.6.6.1
2
1
Below is David Alan's original patch with lots of changes.
In particular, it now parses the following two XML descriptions, one
for 802.1Qbg and 802.1Qbh and stored the data internally. The actual
triggering of the switch setup protocol has not been implemented
here but the relevant code to do that should go into the functions
associatePortProfileId() and disassociatePortProfileId().
<interface type='direct'>
<source dev='static' mode='vepa'/>
<model type='virtio'/>
<vsi type='802.1Qbg'>
<parameters managerid='12' typeid='0x123456' typeidversion='1'
instanceid='fa9b7fff-b0a0-4893-8e0e-beef4ff18f8f'/>
</vsi>
<filterref filter='clean-traffic'/>
</interface>
<interface type='direct'>
<source dev='static' mode='vepa'/>
<model type='virtio'/>
<vsi type='802.1Qbh'>
<parameters profileid='my_profile'/>
</vsi>
</interface>
I'd suggest to use this patch as a base for triggering the setup
protocol with the 802.1Qb{g|h} switch.
Changes from V2 to V3:
- if instance ID UUID is not supplied it will automatically be generated
- adapted schema to make instance ID UUID optional
- added test case
Some of the changes from V1 to V2:
- parser and XML generator have been separated into their own
functions so they can be re-used elsewhere (passthrough case
for example)
- Adapted XML parser and generator support the above shown type
(802.1Qbg, 802.1Qbh).
- Adapted schema to above XML
- Adapted test XML to above XML
- Passing through the VM's UUID which seems to be necessary for
802.1Qbh -- sorry no host UUID
- adding virtual function ID to association function, in case it's
necessary to use (for SR-IOV)
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
>From a945107f047c7cd71f9c1b74fd74c47d8cdc3670 Mon Sep 17 00:00:00 2001
From: David Allan <dallan(a)redhat.com>
Date: Fri, 12 Mar 2010 13:25:04 -0500
Subject: [PATCH 1/1] POC of port profile id support
* Modified schema per DanPB's feedback
* Added test for modified schema
---
docs/schemas/domain.rng | 69 ++++++++++++++
src/conf/domain_conf.c | 155 +++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 35 +++++++
src/qemu/qemu_conf.c | 17 +--
src/qemu/qemu_conf.h | 5 -
src/qemu/qemu_driver.c | 17 +--
src/util/macvtap.c | 150 ++++++++++++++++++++++++++++---
src/util/macvtap.h | 10 +-
tests/domainschemadata/portprofile.xml | 36 +++++++
9 files changed, 446 insertions(+), 48 deletions(-)
create mode 100644 tests/domainschemadata/portprofile.xml
Index: libvirt-acl/docs/schemas/domain.rng
===================================================================
--- libvirt-acl.orig/docs/schemas/domain.rng
+++ libvirt-acl/docs/schemas/domain.rng
@@ -817,6 +817,9 @@
</optional>
<empty/>
</element>
+ <optional>
+ <ref name="vsiProfile"/>
+ </optional>
<ref name="interface-options"/>
</interleave>
</group>
@@ -902,6 +905,45 @@
</optional>
</interleave>
</define>
+ <define name="vsiProfile">
+ <choice>
+ <group>
+ <element name="vsi">
+ <attribute name="type">
+ <value>802.1Qbg</value>
+ </attribute>
+ <element name="parameters">
+ <attribute name="managerid">
+ <ref name="uint8range"/>
+ </attribute>
+ <attribute name="typeid">
+ <ref name="uint24range"/>
+ </attribute>
+ <attribute name="typeidversion">
+ <ref name="uint8range"/>
+ </attribute>
+ <optional>
+ <attribute name="instanceid">
+ <ref name="UUID"/>
+ </attribute>
+ </optional>
+ </element>
+ </element>
+ </group>
+ <group>
+ <element name="vsi">
+ <attribute name="type">
+ <value>802.1Qbh</value>
+ </attribute>
+ <element name="parameters">
+ <attribute name="profileid">
+ <ref name="vsiProfileID"/>
+ </attribute>
+ </element>
+ </element>
+ </group>
+ </choice>
+ </define>
<!--
An emulator description is just a path to the binary used for the task
-->
@@ -1769,4 +1811,31 @@
<param name="pattern">[a-zA-Z0-9_\.:]+</param>
</data>
</define>
+ <define name="uint8range">
+ <choice>
+ <data type="string">
+ <param name="pattern">0x[0-9a-fA-F]{1,2}</param>
+ </data>
+ <data type="int">
+ <param name="minInclusive">0</param>
+ <param name="maxInclusive">255</param>
+ </data>
+ </choice>
+ </define>
+ <define name="uint24range">
+ <choice>
+ <data type="string">
+ <param name="pattern">0x[0-9a-fA-F]{1,6}</param>
+ </data>
+ <data type="int">
+ <param name="minInclusive">0</param>
+ <param name="maxInclusive">16777215</param>
+ </data>
+ </choice>
+ </define>
+ <define name="vsiProfileID">
+ <data type="string">
+ <param name="maxLength">39</param>
+ </data>
+ </define>
</grammar>
Index: libvirt-acl/src/conf/domain_conf.c
===================================================================
--- libvirt-acl.orig/src/conf/domain_conf.c
+++ libvirt-acl/src/conf/domain_conf.c
@@ -242,6 +242,11 @@ VIR_ENUM_IMPL(virDomainNetdevMacvtap, VI
"private",
"bridge")
+VIR_ENUM_IMPL(virVSI, VIR_VSI_TYPE_LAST,
+ "none",
+ "802.1Qbg",
+ "802.1Qbh")
+
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
"utc",
"localtime",
@@ -1807,6 +1812,145 @@ isValidIfname(const char *ifname) {
}
+static void
+virVSIProfileDefParseXML(xmlNodePtr node,
+ virVSIProfileDefPtr vsi)
+{
+ char *vsiType;
+ char *vsiManagerID = NULL;
+ char *vsiTypeID = NULL;
+ char *vsiTypeIDVersion = NULL;
+ char *vsiInstanceID = NULL;
+ char *vsiProfileID = NULL;
+ xmlNodePtr cur = node->children;
+
+ vsiType = virXMLPropString(node, "type");
+ if (!vsiType)
+ return;
+
+ while (cur != NULL) {
+ if (xmlStrEqual(cur->name, BAD_CAST "parameters")) {
+
+ vsiManagerID = virXMLPropString(cur, "managerid");
+ vsiTypeID = virXMLPropString(cur, "typeid");
+ vsiTypeIDVersion = virXMLPropString(cur, "typeidversion");
+ vsiInstanceID = virXMLPropString(cur, "instanceid");
+ vsiProfileID = virXMLPropString(cur, "profileid");
+
+ break;
+ }
+
+ cur = cur->next;
+ }
+
+ vsi->vsiType = VIR_VSI_NONE;
+
+ switch (virVSITypeFromString(vsiType)) {
+
+ case VIR_VSI_8021QBG:
+ if (vsiManagerID != NULL && vsiTypeID != NULL &&
+ vsiTypeIDVersion != NULL) {
+ unsigned int val;
+
+ if ((virStrToLong_ui(vsiManagerID, NULL, 10, &val) &&
+ virStrToLong_ui(vsiManagerID, NULL, 16, &val) ) ||
+ val > 0xff)
+ break;
+
+ vsi->u.vsi8021Qbg.managerID = (uint8_t)val;
+
+ if ((virStrToLong_ui(vsiTypeID, NULL, 10, &val) &&
+ virStrToLong_ui(vsiTypeID, NULL, 16, &val) ) ||
+ val > 0xffffff)
+ break;
+
+ vsi->u.vsi8021Qbg.typeID = (uint32_t)val;
+
+ if ((virStrToLong_ui(vsiTypeIDVersion, NULL, 10, &val) &&
+ virStrToLong_ui(vsiTypeIDVersion, NULL, 16, &val) ) ||
+ val > 0xff)
+ break;
+
+ vsi->u.vsi8021Qbg.typeIDVersion = (uint8_t)val;
+
+ if (vsiInstanceID != NULL) {
+ if (virUUIDParse(vsiInstanceID, vsi->u.vsi8021Qbg.instanceID))
+ break;
+ } else {
+ if (virUUIDGenerate(vsi->u.vsi8021Qbg.instanceID))
+ break;
+ }
+
+ vsi->vsiType = VIR_VSI_8021QBG;
+ }
+ break;
+
+ case VIR_VSI_8021QBH:
+ if (vsiProfileID != NULL) {
+ if (virStrcpyStatic(vsi->u.vsi8021Qbh.profileID,
+ vsiProfileID) != NULL)
+ vsi->vsiType = VIR_VSI_8021QBH;
+ }
+ break;
+
+
+ default:
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+ }
+
+ VIR_FREE(vsiManagerID);
+ VIR_FREE(vsiTypeID);
+ VIR_FREE(vsiTypeIDVersion);
+ VIR_FREE(vsiInstanceID);
+ VIR_FREE(vsiProfileID);
+ VIR_FREE(vsiType);
+}
+
+
+static void
+virVSIProfileFormat(virBufferPtr buf, virVSIProfileDefPtr vsi,
+ const char *indent)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ if (vsi->vsiType == VIR_VSI_NONE)
+ return;
+
+ virBufferVSprintf(buf, "%s<vsi type='%s'>\n",
+ indent, virVSITypeToString(vsi->vsiType));
+
+ switch (vsi->vsiType) {
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+
+ case VIR_VSI_8021QBG:
+ virUUIDFormat(vsi->u.vsi8021Qbg.instanceID,
+ uuidstr);
+ virBufferVSprintf(buf,
+ "%s <parameters managerid='%d' typeid='%d' "
+ "typeidversion='%d' instanceid='%s'/>\n",
+ indent,
+ vsi->u.vsi8021Qbg.managerID,
+ vsi->u.vsi8021Qbg.typeID,
+ vsi->u.vsi8021Qbg.typeIDVersion,
+ uuidstr);
+ break;
+
+ case VIR_VSI_8021QBH:
+ virBufferVSprintf(buf,
+ "%s <parameters profileid='%s'/>\n",
+ indent,
+ vsi->u.vsi8021Qbh.profileID);
+ break;
+ }
+
+ virBufferVSprintf(buf, "%s</vsi>\n", indent);
+}
+
+
/* Parse the XML definition for a network interface
* @param node XML nodeset to parse for net definition
* @return 0 on success, -1 on failure
@@ -1832,6 +1976,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *devaddr = NULL;
char *mode = NULL;
virNWFilterHashTablePtr filterparams = NULL;
+ virVSIProfileDef vsi;
+ bool vsiParsed = false;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
@@ -1873,6 +2019,11 @@ virDomainNetDefParseXML(virCapsPtr caps,
xmlStrEqual(cur->name, BAD_CAST "source")) {
dev = virXMLPropString(cur, "dev");
mode = virXMLPropString(cur, "mode");
+ } else if ((vsiParsed == false) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
+ xmlStrEqual(cur->name, BAD_CAST "vsi")) {
+ virVSIProfileDefParseXML(cur, &vsi);
+ vsiParsed = true;
} else if ((network == NULL) &&
((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
(def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
@@ -2049,6 +2200,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
} else
def->data.direct.mode = VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA;
+ def->data.direct.vsiProfile = vsi;
+
def->data.direct.linkdev = dev;
dev = NULL;
@@ -5141,6 +5294,8 @@ virDomainNetDefFormat(virBufferPtr buf,
virBufferVSprintf(buf, " mode='%s'",
virDomainNetdevMacvtapTypeToString(def->data.direct.mode));
virBufferAddLit(buf, "/>\n");
+ virVSIProfileFormat(buf, &def->data.direct.vsiProfile,
+ " ");
break;
case VIR_DOMAIN_NET_TYPE_USER:
Index: libvirt-acl/src/conf/domain_conf.h
===================================================================
--- libvirt-acl.orig/src/conf/domain_conf.h
+++ libvirt-acl/src/conf/domain_conf.h
@@ -259,6 +259,39 @@ enum virDomainNetdevMacvtapType {
};
+enum virVSIType {
+ VIR_VSI_NONE,
+ VIR_VSI_8021QBG,
+ VIR_VSI_8021QBH,
+
+ VIR_VSI_TYPE_LAST,
+};
+
+# ifdef IFLA_VF_PORT_PROFILE_MAX
+# define LIBVIRT_IFLA_VF_PORT_PROFILE_MAX IFLA_VF_PORT_PROFILE_MAX
+# else
+# define LIBVIRT_IFLA_VF_PORT_PROFILE_MAX 40
+# endif
+
+/* profile data for macvtap (VEPA) */
+typedef struct _virVSIProfileDef virVSIProfileDef;
+typedef virVSIProfileDef *virVSIProfileDefPtr;
+struct _virVSIProfileDef {
+ enum virVSIType vsiType;
+ union {
+ struct {
+ uint8_t managerID;
+ uint32_t typeID; // 24 bit valid
+ uint8_t typeIDVersion;
+ unsigned char instanceID[VIR_UUID_BUFLEN];
+ } vsi8021Qbg;
+ struct {
+ char profileID[LIBVIRT_IFLA_VF_PORT_PROFILE_MAX];
+ } vsi8021Qbh;
+ } u;
+};
+
+
/* Stores the virtual network interface configuration */
typedef struct _virDomainNetDef virDomainNetDef;
typedef virDomainNetDef *virDomainNetDefPtr;
@@ -290,6 +323,7 @@ struct _virDomainNetDef {
struct {
char *linkdev;
int mode;
+ virVSIProfileDef vsiProfile;
} direct;
} data;
char *ifname;
@@ -1089,6 +1123,7 @@ VIR_ENUM_DECL(virDomainSeclabel)
VIR_ENUM_DECL(virDomainClockOffset)
VIR_ENUM_DECL(virDomainNetdevMacvtap)
+VIR_ENUM_DECL(virVSI)
VIR_ENUM_DECL(virDomainTimerName)
VIR_ENUM_DECL(virDomainTimerTrack)
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -43,6 +43,7 @@
# include "util.h"
# include "memory.h"
+# include "logging.h"
# include "macvtap.h"
# include "interface.h"
# include "conf/domain_conf.h"
@@ -570,36 +571,127 @@ configMacvtapTap(int tapfd, int vnet_hdr
/**
+ * associatePortProfile
+ *
+ * @linkdev: the link dev in case of macvtap
+ * @mac: the MAC address of the interface
+ * @mode: The vepa mode (private, bridge or vepa)
+ * @vsi: pointer to the object holding port profile parameters
+ * @vf: virtual function number, -1 if to be ignored
+ * @vmuuid : the UUID of the virtual machine
+ *
+ * Associate a port on a swtich with a profile. This function
+ * may notify a kernel driver or an external daemon to run
+ * the setup protocol. If profile parameters were not supplied
+ * by the user, then this function returns without doing
+ * anything.
+ *
+ * Returns 0 in case of success, != 0 otherwise with error
+ * having been reported.
+ */
+static int
+associatePortProfileId(const char *linkdev,
+ const unsigned char *mac,
+ int mode,
+ const virVSIProfileDefPtr vsi,
+ int vf,
+ const unsigned char *vmuuid)
+{
+ int rc = 0;
+ VIR_DEBUG("Associating port profile '%p' on link device '%s' mode %d ",
+ vsi, linkdev, mode);
+ (void)mac;
+ (void)vf;
+ (void)vmuuid;
+
+ switch (vsi->vsiType) {
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+
+ case VIR_VSI_8021QBG:
+ rc = -1;
+ break;
+
+ case VIR_VSI_8021QBH:
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+
+/**
+ * disassociatePortProfile
+ *
+ * @linkdev: The link dev in case of a macvtap device
+ * @mac: The MAC address of the interface
+ * @vsi: point to object holding port profile parameters
+ *
+ * Returns 0 in case of success, != 0 otherwise with error
+ * having been reported.
+ */
+static int
+disassociatePortProfileId(const char *linkdev,
+ const unsigned char *mac,
+ const virVSIProfileDefPtr vsi)
+{
+ int rc = 0;
+ VIR_DEBUG("Disassociating port profile id '%p' on link device '%s' ",
+ vsi, linkdev);
+ (void)mac;
+
+ switch (vsi->vsiType) {
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+
+ case VIR_VSI_8021QBG:
+ rc = -1;
+ break;
+
+ case VIR_VSI_8021QBH:
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+
+/**
* openMacvtapTap:
* Create an instance of a macvtap device and open its tap character
* device.
* @tgifname: Interface name that the macvtap is supposed to have. May
* be NULL if this function is supposed to choose a name
- * @macaddress: The MAC address for the macvtap device
- * @linkdev: The interface name of the NIC to connect to the external bridge
- * @mode_str: String describing the mode. Valid are 'bridge', 'vepa' and
- * 'private'.
+ * @net: pointer to the virDomainNetDef object describing the direct
+ * type if an interface
* @res_ifname: Pointer to a string pointer where the actual name of the
* interface will be stored into if everything succeeded. It is up
* to the caller to free the string.
+ * @vnet_hdr: Whether to enable IFF_VNET_HDR on the interface
+ * @vmuuid: The (raw) UUID of the VM
*
* Returns file descriptor of the tap device in case of success,
* negative value otherwise with error reported.
*
+ * Open a macvtap device and trigger the switch setup protocol
+ * if valid port profile parameters were provided.
*/
int
openMacvtapTap(const char *tgifname,
- const unsigned char *macaddress,
- const char *linkdev,
- int mode,
+ virDomainNetDefPtr net,
char **res_ifname,
- int vnet_hdr)
+ int vnet_hdr,
+ const unsigned char *vmuuid)
{
const char *type = "macvtap";
int c, rc;
char ifname[IFNAMSIZ];
int retries, do_retry = 0;
- uint32_t macvtapMode = macvtapModeFromInt(mode);
+ uint32_t macvtapMode = macvtapModeFromInt(net->data.direct.mode);
const char *cr_ifname;
int ifindex;
@@ -616,7 +708,7 @@ openMacvtapTap(const char *tgifname,
return -1;
}
cr_ifname = tgifname;
- rc = link_add(type, macaddress, 6, tgifname, linkdev,
+ rc = link_add(type, net->mac, 6, tgifname, net->data.direct.linkdev,
macvtapMode, &do_retry);
if (rc)
return -1;
@@ -626,7 +718,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,
+ rc = link_add(type, net->mac, 6, ifname,
+ net->data.direct.linkdev,
macvtapMode, &do_retry);
if (rc == 0)
break;
@@ -639,6 +732,15 @@ create_name:
cr_ifname = ifname;
}
+ rc = associatePortProfileId(net->data.direct.linkdev,
+ net->mac,
+ net->data.direct.mode,
+ &net->data.direct.vsiProfile,
+ -1,
+ vmuuid);
+ if (rc != 0)
+ goto link_del_exit;
+
rc = ifaceUp(cr_ifname);
if (rc != 0) {
virReportSystemError(errno,
@@ -647,7 +749,7 @@ create_name:
"MAC address"),
cr_ifname);
rc = -1;
- goto link_del_exit;
+ goto disassociate_exit;
}
rc = openTap(cr_ifname, 10);
@@ -656,14 +758,19 @@ create_name:
if (configMacvtapTap(rc, vnet_hdr) < 0) {
close(rc);
rc = -1;
- goto link_del_exit;
+ goto disassociate_exit;
}
*res_ifname = strdup(cr_ifname);
} else
- goto link_del_exit;
+ goto disassociate_exit;
return rc;
+disassociate_exit:
+ disassociatePortProfileId(net->data.direct.linkdev,
+ net->mac,
+ &net->data.direct.vsiProfile);
+
link_del_exit:
link_del(cr_ifname);
@@ -673,14 +780,21 @@ link_del_exit:
/**
* delMacvtap:
- * @ifname : The name of the macvtap interface
+ * @net: pointer to virDomainNetDef object
*
- * Delete an interface given its name.
+ * Delete an interface given its name. Disassociate
+ * it with the switch if port profile parameters
+ * were provided.
*/
void
-delMacvtap(const char *ifname)
+delMacvtap(virDomainNetDefPtr net)
{
- link_del(ifname);
+ if (net->ifname) {
+ disassociatePortProfileId(net->data.direct.linkdev,
+ net->mac,
+ &net->data.direct.vsiProfile);
+ link_del(net->ifname);
+ }
}
#endif
Index: libvirt-acl/src/util/macvtap.h
===================================================================
--- libvirt-acl.orig/src/util/macvtap.h
+++ libvirt-acl/src/util/macvtap.h
@@ -27,15 +27,15 @@
# if defined(WITH_MACVTAP)
# include "internal.h"
+# include "conf/domain_conf.h"
int openMacvtapTap(const char *ifname,
- const unsigned char *macaddress,
- const char *linkdev,
- int mode,
+ virDomainNetDefPtr net,
char **res_ifname,
- int vnet_hdr);
+ int vnet_hdr,
+ const unsigned char *vmuuid);
-void delMacvtap(const char *ifname);
+void delMacvtap(virDomainNetDefPtr net);
# endif /* WITH_MACVTAP */
Index: libvirt-acl/tests/domainschemadata/portprofile.xml
===================================================================
--- /dev/null
+++ libvirt-acl/tests/domainschemadata/portprofile.xml
@@ -0,0 +1,36 @@
+<domain type='lxc'>
+ <name>portprofile</name>
+ <uuid>00000000-0000-0000-0000-000000000000</uuid>
+ <memory>1048576</memory>
+ <os>
+ <type>exe</type>
+ <init>/sh</init>
+ </os>
+ <devices>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ <vsi type='802.1Qbg'>
+ <parameters managerid='12' typeid='1193046' typeidversion='1'
+ instanceid='fa9b7fff-b0a0-4893-8e0e-beef4ff18f8f'/>
+ </vsi>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ <vsi type='802.1Qbg'>
+ <parameters managerid='12' typeid='1193046' typeidversion='1'/>
+ </vsi>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ <vsi type='802.1Qbh'>
+ <parameters profileid='my_profile'/>
+ </vsi>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ </interface>
+ </devices>
+</domain>
Index: libvirt-acl/src/qemu/qemu_conf.h
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.h
+++ libvirt-acl/src/qemu/qemu_conf.h
@@ -271,9 +271,8 @@ qemudOpenVhostNet(virDomainNetDefPtr net
int qemudPhysIfaceConnect(virConnectPtr conn,
struct qemud_driver *driver,
virDomainNetDefPtr net,
- char *linkdev,
- int brmode,
- unsigned long long qemuCmdFlags);
+ unsigned long long qemuCmdFlags,
+ const unsigned char *vmuuid);
int qemudProbeMachineTypes (const char *binary,
virCapsGuestMachinePtr **machines,
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -3585,10 +3585,8 @@ static void qemudShutdownVMDaemon(struct
def = vm->def;
for (i = 0; i < def->nnets; i++) {
virDomainNetDefPtr net = def->nets[i];
- if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (net->ifname)
- delMacvtap(net->ifname);
- }
+ if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT)
+ delMacvtap(net);
}
#endif
@@ -7175,9 +7173,8 @@ static int qemudDomainAttachNetDevice(vi
}
if ((tapfd = qemudPhysIfaceConnect(conn, driver, net,
- net->data.direct.linkdev,
- net->data.direct.mode,
- qemuCmdFlags)) < 0)
+ qemuCmdFlags,
+ vm->def->uuid)) < 0)
return -1;
}
@@ -8146,10 +8143,8 @@ qemudDomainDetachNetDevice(struct qemud_
virNWFilterTearNWFilter(detach);
#if WITH_MACVTAP
- if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (detach->ifname)
- delMacvtap(detach->ifname);
- }
+ if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT)
+ delMacvtap(detach);
#endif
if ((driver->macFilter) && (detach->ifname != NULL)) {
Index: libvirt-acl/src/qemu/qemu_conf.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.c
+++ libvirt-acl/src/qemu/qemu_conf.c
@@ -1465,9 +1465,8 @@ int
qemudPhysIfaceConnect(virConnectPtr conn,
struct qemud_driver *driver,
virDomainNetDefPtr net,
- char *linkdev,
- int brmode,
- unsigned long long qemuCmdFlags)
+ unsigned long long qemuCmdFlags,
+ const unsigned char *vmuuid)
{
int rc;
#if WITH_MACVTAP
@@ -1479,8 +1478,7 @@ qemudPhysIfaceConnect(virConnectPtr conn
net->model && STREQ(net->model, "virtio"))
vnet_hdr = 1;
- rc = openMacvtapTap(net->ifname, net->mac, linkdev, brmode,
- &res_ifname, vnet_hdr);
+ rc = openMacvtapTap(net->ifname, net, &res_ifname, vnet_hdr, vmuuid);
if (rc >= 0) {
VIR_FREE(net->ifname);
net->ifname = res_ifname;
@@ -1500,15 +1498,13 @@ qemudPhysIfaceConnect(virConnectPtr conn
if (err) {
close(rc);
rc = -1;
- delMacvtap(net->ifname);
+ delMacvtap(net);
}
}
}
#else
(void)conn;
(void)net;
- (void)linkdev;
- (void)brmode;
(void)qemuCmdFlags;
(void)driver;
qemuReportError(VIR_ERR_INTERNAL_ERROR,
@@ -4130,9 +4126,8 @@ int qemudBuildCommandLine(virConnectPtr
goto no_memory;
} else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
int tapfd = qemudPhysIfaceConnect(conn, driver, net,
- net->data.direct.linkdev,
- net->data.direct.mode,
- qemuCmdFlags);
+ qemuCmdFlags,
+ def->uuid);
if (tapfd < 0)
goto error;
1
0
13 May '10
The cgroups ACL code was only allowing the primary disk image.
It is possible to chain images together, so we need to search
for backing stores and add them to the ACL too. Since the ACL
only handles block devices, we ignore the EINVAL we get from
plain files. In addition it was missing code to teardown the
cgroup when hot-unplugging a disk
* src/qemu/qemu_driver.c: Allow backing stores in cgroup ACLs
and add missing teardown code in unplug path
---
src/qemu/qemu_driver.c | 170 +++++++++++++++++++++++++++++++++++++++---------
1 files changed, 139 insertions(+), 31 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 92dc22d..f615072 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2929,6 +2929,102 @@ static const char *const defaultDeviceACL[] = {
#define DEVICE_PTY_MAJOR 136
#define DEVICE_SND_MAJOR 116
+static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
+ virDomainObjPtr vm,
+ virDomainDiskDefPtr disk)
+{
+ char *path = disk->src;
+ int ret = -1;
+
+ while (path != NULL) {
+ virStorageFileMetadata meta;
+ int rc;
+
+ VIR_DEBUG("Process path %s for disk", path);
+ rc = virCgroupAllowDevicePath(cgroup, path);
+ if (rc != 0) {
+ /* Get this for non-block devices */
+ if (rc == -EINVAL) {
+ VIR_DEBUG("Ignoring EINVAL for %s", path);
+ } else {
+ virReportSystemError(-rc,
+ _("Unable to allow device %s for %s"),
+ path, vm->def->name);
+ if (path != disk->src)
+ VIR_FREE(path);
+ goto cleanup;
+ }
+ }
+
+ memset(&meta, 0, sizeof(meta));
+
+ rc = virStorageFileGetMetadata(path, &meta);
+
+ if (path != disk->src)
+ VIR_FREE(path);
+ path = NULL;
+
+ if (rc < 0)
+ goto cleanup;
+
+ path = meta.backingStore;
+ } while (path != NULL);
+
+ ret = 0;
+
+cleanup:
+ return ret;
+}
+
+
+static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
+ virDomainObjPtr vm,
+ virDomainDiskDefPtr disk)
+{
+ char *path = disk->src;
+ int ret = -1;
+
+ while (path != NULL) {
+ virStorageFileMetadata meta;
+ int rc;
+
+ VIR_DEBUG("Process path %s for disk", path);
+ rc = virCgroupDenyDevicePath(cgroup, path);
+ if (rc != 0) {
+ /* Get this for non-block devices */
+ if (rc == -EINVAL) {
+ VIR_DEBUG("Ignoring EINVAL for %s", path);
+ } else {
+ virReportSystemError(-rc,
+ _("Unable to deny device %s for %s"),
+ path, vm->def->name);
+ if (path != disk->src)
+ VIR_FREE(path);
+ goto cleanup;
+ }
+ }
+
+ memset(&meta, 0, sizeof(meta));
+
+ rc = virStorageFileGetMetadata(path, &meta);
+
+ if (path != disk->src)
+ VIR_FREE(path);
+ path = NULL;
+
+ if (rc < 0)
+ goto cleanup;
+
+ path = meta.backingStore;
+ } while (path != NULL);
+
+ ret = 0;
+
+cleanup:
+ return ret;
+}
+
+
static int qemuSetupCgroup(struct qemud_driver *driver,
virDomainObjPtr vm)
{
@@ -2965,18 +3061,8 @@ static int qemuSetupCgroup(struct qemud_driver *driver,
}
for (i = 0; i < vm->def->ndisks ; i++) {
- if (vm->def->disks[i]->type != VIR_DOMAIN_DISK_TYPE_BLOCK ||
- vm->def->disks[i]->src == NULL)
- continue;
-
- rc = virCgroupAllowDevicePath(cgroup,
- vm->def->disks[i]->src);
- if (rc != 0) {
- virReportSystemError(-rc,
- _("Unable to allow device %s for %s"),
- vm->def->disks[i]->src, vm->def->name);
+ if (qemuSetupDiskCgroup(cgroup, vm, vm->def->disks[i]) < 0)
goto cleanup;
- }
}
rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR);
@@ -7550,15 +7636,8 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
vm->def->name);
goto endjob;
}
- if (dev->data.disk->src != NULL &&
- dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
- virCgroupAllowDevicePath(cgroup,
- dev->data.disk->src) < 0) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR,
- _("unable to allow device %s"),
- dev->data.disk->src);
+ if (qemuSetupDiskCgroup(cgroup, vm, dev->data.disk) < 0)
goto endjob;
- }
}
switch (dev->data.disk->device) {
@@ -7602,8 +7681,9 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
/* Fallthrough */
}
if (ret != 0 && cgroup) {
- virCgroupDenyDevicePath(cgroup,
- dev->data.disk->src);
+ if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
+ VIR_WARN("Failed to teardown cgroup for disk path %s",
+ NULLSTR(dev->data.disk->src));
}
} else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
@@ -7801,15 +7881,8 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
vm->def->name);
goto endjob;
}
- if (dev->data.disk->src != NULL &&
- dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
- virCgroupAllowDevicePath(cgroup,
- dev->data.disk->src) < 0) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR,
- _("unable to allow device %s"),
- dev->data.disk->src);
+ if (qemuSetupDiskCgroup(cgroup, vm, dev->data.disk) < 0)
goto endjob;
- }
}
switch (dev->data.disk->device) {
@@ -7831,8 +7904,9 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
}
if (ret != 0 && cgroup) {
- virCgroupDenyDevicePath(cgroup,
- dev->data.disk->src);
+ if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
+ VIR_WARN("Failed to teardown cgroup for disk path %s",
+ NULLSTR(dev->data.disk->src));
}
break;
@@ -7904,6 +7978,7 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
int i, ret = -1;
virDomainDiskDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
+ virCgroupPtr cgroup = NULL;
i = qemudFindDisk(vm->def, dev->data.disk->dst);
@@ -7915,6 +7990,15 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
detach = vm->def->disks[i];
+ if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find cgroup for %s\n"),
+ vm->def->name);
+ goto cleanup;
+ }
+ }
+
if (!virDomainDeviceAddressIsValid(&detach->info,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
@@ -7939,11 +8023,19 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
qemudShrinkDisks(vm->def, i);
+ virDomainDiskDefFree(detach);
+
if (driver->securityDriver &&
driver->securityDriver->domainRestoreSecurityImageLabel &&
driver->securityDriver->domainRestoreSecurityImageLabel(vm, dev->data.disk) < 0)
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
+ if (cgroup != NULL) {
+ if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
+ VIR_WARN("Failed to teardown cgroup for disk path %s",
+ NULLSTR(dev->data.disk->src));
+ }
+
ret = 0;
cleanup:
@@ -7958,6 +8050,7 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
int i, ret = -1;
virDomainDiskDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
+ virCgroupPtr cgroup = NULL;
i = qemudFindDisk(vm->def, dev->data.disk->dst);
@@ -7975,6 +8068,15 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
detach = vm->def->disks[i];
+ if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find cgroup for %s\n"),
+ vm->def->name);
+ goto cleanup;
+ }
+ }
+
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
qemuDomainObjExitMonitor(vm);
@@ -7991,6 +8093,12 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
driver->securityDriver->domainRestoreSecurityImageLabel(vm, dev->data.disk) < 0)
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
+ if (cgroup != NULL) {
+ if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
+ VIR_WARN("Failed to teardown cgroup for disk path %s",
+ NULLSTR(dev->data.disk->src));
+ }
+
ret = 0;
cleanup:
--
1.6.5.2
2
1
I've done some more work on error cleanup, expanding 3 patches
of v1 into 10 patches, with more still to be written. See
individual patches for more comments.
bootstrap.conf | 1 +
cfg.mk | 5 +-
src/datatypes.c | 127 +++++++++++----
src/libvirt.c | 94 ++++++-----
src/security/virt-aa-helper.c | 141 ++++++++--------
src/storage/storage_backend.c | 2 +-
src/util/virterror.c | 374 +++++++++++++---------------------------
src/xen/xend_internal.c | 5 +-
tests/cpuset | 4 +-
tests/undefine | 4 +-
10 files changed, 352 insertions(+), 405 deletions(-)
Net reduction in lines of code is a good thing.
[PATCHv2 01/10] virt-aa-helper: translate error messages
[PATCHv2 02/10] build: use gnulib func module
[PATCHv2 03/10] datatypes: avoid redundant __FUNCTION__
[PATCHv2 04/10] virErrorMsg: refactor to simplify common case
[PATCHv2 05/10] virterror: start messages with lower case
[PATCHv2 06/10] virterror: clean up VIR_ERR_HTTP_ERROR usage
[PATCHv2 07/10] virterror: clean up VIR_ERR_XML_DETAIL usage
[PATCHv2 08/10] virterror: clean up several seldom-used errors
[PATCHv2 09/10] virterror: clean up VIR_ERR_INVALID_NETWORK usage
[PATCHv2 10/10] virterror: clean up VIR_ERR_INVALID_INTERFACE usage
[PATCHv2 N/N] to be written, after feedback on this round
1
10
[libvirt] [libvirt PATCH] Port-profile ID support using IFLA_VF_PORT_PROFILE netlink msg
by Scott Feldman 12 May '10
by Scott Feldman 12 May '10
12 May '10
From: Scott Feldman <scofeldm(a)cisco.com>
This fleshes out the port profile ID proof-of-concept patch posted earlier
by David Allan, referenced here:
https://www.redhat.com/archives/libvir-list/2010-March/msg01401.html
It uses the new IFLA_VF_PORT_PROFILE netlink msg to set/unset the port-
profile for the virtual switch port backing the VM device. The new netlink
msg is being discussed on the netdev kernel mailing list here:
http://marc.info/?l=linux-netdev&m=127312092712543&w=2
http://marc.info/?l=linux-netdev&m=127312093412556&w=2
IFLA_VF_PORT_PROFILE is sent using RTM_SETLINK, and retrieved using
RTM_GETLINK. IFLA_VF_PORT_PROFILE is sent using netlink multicast send
with RTNLGRP_LINK so the receiver of the msg can be in user-space or
kernel-space.
The device XML is:
<interface type='direct'>
<source dev='eth2' mode='private' profileid='dc_test'/>
<mac address='00:16:3e:1a:b3:4b'/>
</interface>
The port-profile ID msg is sent to source dev.
Tested with Cisco 10G Ethernet NIC using port-profiles defined in Cisco's
Unified Computing System Management software and above referenced kernel
patches.
Signed-off-by: Scott Feldman <scofeldm(a)cisco.com>
Signed-off-by: Roopa Prabhu<roprabhu(a)cisco.com>
---
src/conf/domain_conf.c | 13 +++
src/conf/domain_conf.h | 1
src/libvirt_macvtap.syms | 2
src/qemu/qemu_conf.c | 7 ++
src/qemu/qemu_driver.c | 10 ++
src/util/macvtap.c | 200 +++++++++++++++++++++++++++++++++++++++++++++-
src/util/macvtap.h | 6 +
7 files changed, 233 insertions(+), 6 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 3e45f79..968076f 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -484,6 +484,7 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
case VIR_DOMAIN_NET_TYPE_DIRECT:
VIR_FREE(def->data.direct.linkdev);
+ VIR_FREE(def->data.direct.profileid);
break;
case VIR_DOMAIN_NET_TYPE_USER:
@@ -1831,6 +1832,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *internal = NULL;
char *devaddr = NULL;
char *mode = NULL;
+ char *profileid = NULL;
virNWFilterHashTablePtr filterparams = NULL;
if (VIR_ALLOC(def) < 0) {
@@ -1873,6 +1875,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
xmlStrEqual(cur->name, BAD_CAST "source")) {
dev = virXMLPropString(cur, "dev");
mode = virXMLPropString(cur, "mode");
+ profileid = virXMLPropString(cur, "profileid");
} else if ((network == NULL) &&
((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
(def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
@@ -2049,6 +2052,11 @@ virDomainNetDefParseXML(virCapsPtr caps,
} else
def->data.direct.mode = VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA;
+ if (profileid != NULL) {
+ def->data.direct.profileid = profileid;
+ profileid = NULL;
+ }
+
def->data.direct.linkdev = dev;
dev = NULL;
@@ -2114,6 +2122,7 @@ cleanup:
VIR_FREE(internal);
VIR_FREE(devaddr);
VIR_FREE(mode);
+ VIR_FREE(profileid);
virNWFilterHashTableFree(filterparams);
return def;
@@ -5140,6 +5149,10 @@ virDomainNetDefFormat(virBufferPtr buf,
def->data.direct.linkdev);
virBufferVSprintf(buf, " mode='%s'",
virDomainNetdevMacvtapTypeToString(def->data.direct.mode));
+ if (def->data.direct.profileid) {
+ virBufferEscapeString(buf, " profileid='%s'",
+ def->data.direct.profileid);
+ }
virBufferAddLit(buf, "/>\n");
break;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index fadc8bd..30ebf07 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -290,6 +290,7 @@ struct _virDomainNetDef {
struct {
char *linkdev;
int mode;
+ char *profileid;
} direct;
} data;
char *ifname;
diff --git a/src/libvirt_macvtap.syms b/src/libvirt_macvtap.syms
index ae229a0..9d4652e 100644
--- a/src/libvirt_macvtap.syms
+++ b/src/libvirt_macvtap.syms
@@ -3,3 +3,5 @@
# macvtap.h
openMacvtapTap;
delMacvtap;
+setPortProfileId;
+unsetPortProfileId;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 5fa8c0a..aff6f28 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1479,6 +1479,11 @@ qemudPhysIfaceConnect(virConnectPtr conn,
net->model && STREQ(net->model, "virtio"))
vnet_hdr = 1;
+ if (!STREQ(net->data.direct.profileid, ""))
+ setPortProfileId(net->data.direct.linkdev,
+ net->data.direct.profileid,
+ net->mac);
+
rc = openMacvtapTap(net->ifname, net->mac, linkdev, brmode,
&res_ifname, vnet_hdr);
if (rc >= 0) {
@@ -1501,6 +1506,8 @@ qemudPhysIfaceConnect(virConnectPtr conn,
close(rc);
rc = -1;
delMacvtap(net->ifname);
+ if (!STREQ(net->data.direct.profileid, ""))
+ unsetPortProfileId(net->data.direct.linkdev);
}
}
}
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index bb1079e..6ea37d4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3586,8 +3586,11 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver,
for (i = 0; i < def->nnets; i++) {
virDomainNetDefPtr net = def->nets[i];
if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (net->ifname)
+ if (net->ifname) {
delMacvtap(net->ifname);
+ if (!STREQ(net->data.direct.profileid, ""))
+ unsetPortProfileId(net->data.direct.linkdev);
+ }
}
}
#endif
@@ -8147,8 +8150,11 @@ qemudDomainDetachNetDevice(struct qemud_driver *driver,
#if WITH_MACVTAP
if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (detach->ifname)
+ if (detach->ifname) {
delMacvtap(detach->ifname);
+ if (!STREQ(detach->data.direct.profileid, ""))
+ unsetPortProfileId(detach->data.direct.linkdev);
+ }
}
#endif
diff --git a/src/util/macvtap.c b/src/util/macvtap.c
index 5d129fd..825cf30 100644
--- a/src/util/macvtap.c
+++ b/src/util/macvtap.c
@@ -85,14 +85,14 @@ static void nlClose(int fd)
* buffer will be returned.
*/
static
-int nlComm(struct nlmsghdr *nlmsg,
+int nlComm(struct nlmsghdr *nlmsg, int nlgroups,
char **respbuf, int *respbuflen)
{
int rc = 0;
struct sockaddr_nl nladdr = {
.nl_family = AF_NETLINK,
.nl_pid = 0,
- .nl_groups = 0,
+ .nl_groups = nlgroups,
};
int rcvChunkSize = 1024; // expecting less than that
int rcvoffset = 0;
@@ -287,7 +287,7 @@ link_add(const char *type,
li->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)li;
- if (nlComm(nlm, &recvbuf, &recvbuflen) < 0)
+ if (nlComm(nlm, 0, &recvbuf, &recvbuflen) < 0)
return -1;
if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL)
@@ -371,7 +371,7 @@ link_del(const char *name)
if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
goto buffer_too_small;
- if (nlComm(nlm, &recvbuf, &recvbuflen) < 0)
+ if (nlComm(nlm, 0, &recvbuf, &recvbuflen) < 0)
return -1;
if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL)
@@ -568,6 +568,198 @@ configMacvtapTap(int tapfd, int vnet_hdr)
return 0;
}
+static int
+get_host_uuid(char *host_uuid, int len)
+{
+ const char *dmidecodearg[] = { "dmidecode", "-s", "system-uuid", NULL };
+ const char *const dmidecodeenv[] = { "LC_ALL=C", NULL };
+ char *binary, *newline;
+ int dmidecodestdout = -1;
+ int ret = -1;
+ pid_t child;
+
+ binary = virFindFileInPath(dmidecodearg[0]);
+ if (binary == NULL || access(binary, X_OK) != 0) {
+ VIR_FREE(binary);
+ return -1;
+ }
+ dmidecodearg[0] = binary;
+
+ if (virExec(dmidecodearg, dmidecodeenv, NULL,
+ &child, -1, &dmidecodestdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0) {
+ ret = -1;
+ goto cleanup;
+ }
+
+ if((ret = saferead(dmidecodestdout, host_uuid, len)) <= 0) {
+ ret = -1;
+ goto cleanup;
+ }
+ host_uuid[ret-1] = '\0';
+
+ /* strip newline */
+ newline = strrchr(host_uuid, '\n');
+ if (newline)
+ *newline = '\0';
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(binary);
+
+ if (close(dmidecodestdout) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int sendPortProfileMulticastMsg(const char *linkdev,
+ struct ifla_vf_port_profile *ivp)
+{
+ int rc = 0;
+ char nlmsgbuf[512];
+ struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
+ char *recvbuf = NULL;
+ struct nlmsgerr *err;
+ char rtattbuf[256];
+ struct rtattr *rta;
+ int recvbuflen;
+ int ifindex;
+ struct ifinfomsg i = { .ifi_family = AF_UNSPEC };
+
+ if (ifaceGetIndex(true, linkdev, &ifindex) != 0)
+ return -1;
+
+ memset(&nlmsgbuf, 0, sizeof(nlmsgbuf));
+ nlInit(nlm, NLM_F_REQUEST, RTM_SETLINK);
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), &i, sizeof(i)))
+ goto buffer_too_small;
+
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_IFNAME,
+ linkdev, strlen(linkdev) + 1);
+ 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_VF_PORT_PROFILE,
+ ivp, sizeof(*ivp));
+ if (!rta)
+ goto buffer_too_small;
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+
+ if (nlComm(nlm, RTNLGRP_LINK, &recvbuf, &recvbuflen) < 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 setting port profile on %s"),
+ linkdev);
+ rc = -1;
+ }
+ break;
+ case NLMSG_DONE:
+ 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;
+}
+
+
+int unsetPortProfileId(const char *linkdev)
+{
+ int rc = 0;
+ struct ifla_vf_port_profile ivp;
+
+ memset(&ivp, 0, sizeof(struct ifla_vf_port_profile));
+ ivp.vf = -1;
+
+ if(!(rc = sendPortProfileMulticastMsg(linkdev, &ivp))) {
+ rc = ifaceDown(linkdev);
+ if (rc != 0) {
+ virReportSystemError(errno,
+ ("cannot 'down' interface %s"),
+ linkdev);
+ //Should we error out ?
+ //rc = -1;
+ }
+ }
+
+ return rc;
+}
+
+int setPortProfileId(const char *linkdev,
+ const char *profileid,
+ unsigned char *macaddress)
+{
+ int rc = 0;
+ struct ifla_vf_port_profile ivp;
+ char host_uuid[IFLA_VF_UUID_MAX] = "\0";
+
+ if (!profileid)
+ return -EINVAL;
+
+ memset(&ivp, 0, sizeof(struct ifla_vf_port_profile));
+ ivp.vf = -1;
+ strncpy((char *)ivp.port_profile, profileid, sizeof(ivp.port_profile));
+ ivp.port_profile[sizeof(ivp.port_profile)-1] = '\0';
+ memcpy(ivp.mac, macaddress, sizeof(ivp.mac));
+ get_host_uuid(host_uuid, IFLA_VF_UUID_MAX);
+ if (strlen(host_uuid)) {
+ strncpy((char *)ivp.host_uuid, host_uuid, sizeof(ivp.host_uuid));
+ ivp.port_profile[sizeof(ivp.port_profile)-1] = '\0';
+ }
+
+ if(!(rc = sendPortProfileMulticastMsg(linkdev, &ivp))) {
+ rc = ifaceUp(linkdev);
+ if (rc != 0) {
+ virReportSystemError(errno,
+ ("cannot 'up' interface %s"),
+ linkdev);
+ // Should we error out of here ?
+ //rc = -1;
+ }
+ }
+
+ return rc;
+}
/**
* openMacvtapTap:
diff --git a/src/util/macvtap.h b/src/util/macvtap.h
index 5d4ea5e..7f58a13 100644
--- a/src/util/macvtap.h
+++ b/src/util/macvtap.h
@@ -37,6 +37,12 @@ int openMacvtapTap(const char *ifname,
void delMacvtap(const char *ifname);
+int setPortProfileId(const char *linkdev,
+ const char *profileid,
+ unsigned char *macaddress);
+
+int unsetPortProfileId(const char *linkdev);
+
# endif /* WITH_MACVTAP */
# define MACVTAP_MODE_PRIVATE_STR "private"
6
22
Below is David Alan's original patch with lots of changes.
In particular, it now parses the following two XML descriptions, one
for 802.1Qbg and 802.1Qbh and stored the data internally. The actual
triggering of the switch setup protocol has not been implemented
here but the relevant code to do that should go into the functions
associatePortProfileId() and disassociatePortProfileId().
<interface type='direct'>
<source dev='static' mode='vepa'/>
<model type='virtio'/>
<vsi type='802.1Qbg'>
<parameters managerid='12' typeid='0x123456' typeidversion='1'
instanceid='fa9b7fff-b0a0-4893-8e0e-beef4ff18f8f'/>
</vsi>
<filterref filter='clean-traffic'/>
</interface>
<interface type='direct'>
<source dev='static' mode='vepa'/>
<model type='virtio'/>
<vsi type='802.1Qbh'>
<parameters profileid='my_profile'/>
</vsi>
</interface>
I'd suggest to use this patch as a base for triggering the setup
protocol with the 802.1Qb{g|h} switch.
Some of the changes from V1 to V2:
- parser and XML generator have been separated into their own
functions so they can be re-used elsewhere (passthrough case
for example)
- Adapted XML parser and generator support the above shown type
(802.1Qbg, 802.1Qbh).
- Adapted schema to above XML
- Adapted test XML to above XML
- Passing through the VM's UUID which seems to be necessary for
802.1Qbh -- sorry no host UUID
- adding virtual function ID to association function, in case it's
necessary to use (for SR-IOV)
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
>From a945107f047c7cd71f9c1b74fd74c47d8cdc3670 Mon Sep 17 00:00:00 2001
From: David Allan <dallan(a)redhat.com>
Date: Fri, 12 Mar 2010 13:25:04 -0500
Subject: [PATCH 1/1] POC of port profile id support
* Modified schema per DanPB's feedback
* Added test for modified schema
---
docs/schemas/domain.rng | 67 ++++++++++++++
src/conf/domain_conf.c | 150
+++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 35 +++++++
src/qemu/qemu_conf.c | 17 +--
src/qemu/qemu_conf.h | 5 -
src/qemu/qemu_driver.c | 17 +--
src/util/macvtap.c | 150
+++++++++++++++++++++++++++++----
src/util/macvtap.h | 10 +-
tests/domainschemadata/portprofile.xml | 30 ++++++
9 files changed, 433 insertions(+), 48 deletions(-)
create mode 100644 tests/domainschemadata/portprofile.xml
Index: libvirt-acl/docs/schemas/domain.rng
===================================================================
--- libvirt-acl.orig/docs/schemas/domain.rng
+++ libvirt-acl/docs/schemas/domain.rng
@@ -817,6 +817,9 @@
</optional>
<empty/>
</element>
+ <optional>
+ <ref name="vsiProfile"/>
+ </optional>
<ref name="interface-options"/>
</interleave>
</group>
@@ -902,6 +905,43 @@
</optional>
</interleave>
</define>
+ <define name="vsiProfile">
+ <choice>
+ <group>
+ <element name="vsi">
+ <attribute name="type">
+ <value>802.1Qbg</value>
+ </attribute>
+ <element name="parameters">
+ <attribute name="managerid">
+ <ref name="uint8range"/>
+ </attribute>
+ <attribute name="typeid">
+ <ref name="uint24range"/>
+ </attribute>
+ <attribute name="typeidversion">
+ <ref name="uint8range"/>
+ </attribute>
+ <attribute name="instanceid">
+ <ref name="UUID"/>
+ </attribute>
+ </element>
+ </element>
+ </group>
+ <group>
+ <element name="vsi">
+ <attribute name="type">
+ <value>802.1Qbh</value>
+ </attribute>
+ <element name="parameters">
+ <attribute name="profileid">
+ <ref name="vsiProfileID"/>
+ </attribute>
+ </element>
+ </element>
+ </group>
+ </choice>
+ </define>
<!--
An emulator description is just a path to the binary used for the
task
-->
@@ -1769,4 +1809,31 @@
<param name="pattern">[a-zA-Z0-9_\.:]+</param>
</data>
</define>
+ <define name="uint8range">
+ <choice>
+ <data type="string">
+ <param name="pattern">0x[0-9a-fA-F]{1,2}</param>
+ </data>
+ <data type="int">
+ <param name="minInclusive">0</param>
+ <param name="maxInclusive">255</param>
+ </data>
+ </choice>
+ </define>
+ <define name="uint24range">
+ <choice>
+ <data type="string">
+ <param name="pattern">0x[0-9a-fA-F]{1,6}</param>
+ </data>
+ <data type="int">
+ <param name="minInclusive">0</param>
+ <param name="maxInclusive">16777215</param>
+ </data>
+ </choice>
+ </define>
+ <define name="vsiProfileID">
+ <data type="string">
+ <param name="maxLength">39</param>
+ </data>
+ </define>
</grammar>
Index: libvirt-acl/src/conf/domain_conf.c
===================================================================
--- libvirt-acl.orig/src/conf/domain_conf.c
+++ libvirt-acl/src/conf/domain_conf.c
@@ -242,6 +242,11 @@ VIR_ENUM_IMPL(virDomainNetdevMacvtap, VI
"private",
"bridge")
+VIR_ENUM_IMPL(virVSI, VIR_VSI_TYPE_LAST,
+ "none",
+ "802.1Qbg",
+ "802.1Qbh")
+
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
"utc",
"localtime",
@@ -1807,6 +1812,140 @@ isValidIfname(const char *ifname) {
}
+static void
+virVSIProfileDefParseXML(xmlNodePtr node,
+ virVSIProfileDefPtr vsi)
+{
+ char *vsiType;
+ char *vsiManagerID = NULL;
+ char *vsiTypeID = NULL;
+ char *vsiTypeIDVersion = NULL;
+ char *vsiInstanceID = NULL;
+ char *vsiProfileID = NULL;
+ xmlNodePtr cur = node->children;
+
+ vsiType = virXMLPropString(node, "type");
+ if (!vsiType)
+ return;
+
+ while (cur != NULL) {
+ if (xmlStrEqual(cur->name, BAD_CAST "parameters")) {
+
+ vsiManagerID = virXMLPropString(cur, "managerid");
+ vsiTypeID = virXMLPropString(cur, "typeid");
+ vsiTypeIDVersion = virXMLPropString(cur, "typeidversion");
+ vsiInstanceID = virXMLPropString(cur, "instanceid");
+ vsiProfileID = virXMLPropString(cur, "profileid");
+
+ break;
+ }
+
+ cur = cur->next;
+ }
+
+ vsi->vsiType = VIR_VSI_NONE;
+
+ switch (virVSITypeFromString(vsiType)) {
+
+ case VIR_VSI_8021QBG:
+ if (vsiManagerID != NULL && vsiTypeID != NULL &&
+ vsiTypeIDVersion != NULL && vsiInstanceID != NULL) {
+ unsigned int val;
+
+ if ((virStrToLong_ui(vsiManagerID, NULL, 10, &val) &&
+ virStrToLong_ui(vsiManagerID, NULL, 16, &val) ) ||
+ val > 0xff)
+ break;
+
+ vsi->u.vsi8021Qbg.managerID = (uint8_t)val;
+
+ if ((virStrToLong_ui(vsiTypeID, NULL, 10, &val) &&
+ virStrToLong_ui(vsiTypeID, NULL, 16, &val) ) ||
+ val > 0xffffff)
+ break;
+
+ vsi->u.vsi8021Qbg.typeID = (uint32_t)val;
+
+ if ((virStrToLong_ui(vsiTypeIDVersion, NULL, 10, &val) &&
+ virStrToLong_ui(vsiTypeIDVersion, NULL, 16, &val) )
||
+ val > 0xff)
+ break;
+
+ vsi->u.vsi8021Qbg.typeIDVersion = (uint8_t)val;
+
+ if (virUUIDParse(vsiInstanceID,
vsi->u.vsi8021Qbg.instanceID))
+ break;
+
+ vsi->vsiType = VIR_VSI_8021QBG;
+ }
+ break;
+
+ case VIR_VSI_8021QBH:
+ if (vsiProfileID != NULL) {
+ if (virStrcpyStatic(vsi->u.vsi8021Qbh.profileID,
+ vsiProfileID) != NULL)
+ vsi->vsiType = VIR_VSI_8021QBH;
+ }
+ break;
+
+
+ default:
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+ }
+
+ VIR_FREE(vsiManagerID);
+ VIR_FREE(vsiTypeID);
+ VIR_FREE(vsiTypeIDVersion);
+ VIR_FREE(vsiInstanceID);
+ VIR_FREE(vsiProfileID);
+ VIR_FREE(vsiType);
+}
+
+
+static void
+virVSIProfileFormat(virBufferPtr buf, virVSIProfileDefPtr vsi,
+ const char *indent)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ if (vsi->vsiType == VIR_VSI_NONE)
+ return;
+
+ virBufferVSprintf(buf, "%s<vsi type='%s'>\n",
+ indent, virVSITypeToString(vsi->vsiType));
+
+ switch (vsi->vsiType) {
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+
+ case VIR_VSI_8021QBG:
+ virUUIDFormat(vsi->u.vsi8021Qbg.instanceID,
+ uuidstr);
+ virBufferVSprintf(buf,
+ "%s <parameters managerid='%d' typeid='%d' "
+ "typeidversion='%d' instanceid='%s'/>\n",
+ indent,
+ vsi->u.vsi8021Qbg.managerID,
+ vsi->u.vsi8021Qbg.typeID,
+ vsi->u.vsi8021Qbg.typeIDVersion,
+ uuidstr);
+ break;
+
+ case VIR_VSI_8021QBH:
+ virBufferVSprintf(buf,
+ "%s <parameters profileid='%s'/>\n",
+ indent,
+ vsi->u.vsi8021Qbh.profileID);
+ break;
+ }
+
+ virBufferVSprintf(buf, "%s</vsi>\n", indent);
+}
+
+
/* Parse the XML definition for a network interface
* @param node XML nodeset to parse for net definition
* @return 0 on success, -1 on failure
@@ -1832,6 +1971,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *devaddr = NULL;
char *mode = NULL;
virNWFilterHashTablePtr filterparams = NULL;
+ virVSIProfileDef vsi;
+ bool vsiParsed = false;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
@@ -1873,6 +2014,11 @@ virDomainNetDefParseXML(virCapsPtr caps,
xmlStrEqual(cur->name, BAD_CAST "source")) {
dev = virXMLPropString(cur, "dev");
mode = virXMLPropString(cur, "mode");
+ } else if ((vsiParsed == false) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
+ xmlStrEqual(cur->name, BAD_CAST "vsi")) {
+ virVSIProfileDefParseXML(cur, &vsi);
+ vsiParsed = true;
} else if ((network == NULL) &&
((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
(def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
@@ -2049,6 +2195,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
} else
def->data.direct.mode =
VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA;
+ def->data.direct.vsiProfile = vsi;
+
def->data.direct.linkdev = dev;
dev = NULL;
@@ -5141,6 +5289,8 @@ virDomainNetDefFormat(virBufferPtr buf,
virBufferVSprintf(buf, " mode='%s'",
virDomainNetdevMacvtapTypeToString(def->data.direct.mode));
virBufferAddLit(buf, "/>\n");
+ virVSIProfileFormat(buf, &def->data.direct.vsiProfile,
+ " ");
break;
case VIR_DOMAIN_NET_TYPE_USER:
Index: libvirt-acl/src/conf/domain_conf.h
===================================================================
--- libvirt-acl.orig/src/conf/domain_conf.h
+++ libvirt-acl/src/conf/domain_conf.h
@@ -259,6 +259,39 @@ enum virDomainNetdevMacvtapType {
};
+enum virVSIType {
+ VIR_VSI_NONE,
+ VIR_VSI_8021QBG,
+ VIR_VSI_8021QBH,
+
+ VIR_VSI_TYPE_LAST,
+};
+
+# ifdef IFLA_VF_PORT_PROFILE_MAX
+# define LIBVIRT_IFLA_VF_PORT_PROFILE_MAX IFLA_VF_PORT_PROFILE_MAX
+# else
+# define LIBVIRT_IFLA_VF_PORT_PROFILE_MAX 40
+# endif
+
+/* profile data for macvtap (VEPA) */
+typedef struct _virVSIProfileDef virVSIProfileDef;
+typedef virVSIProfileDef *virVSIProfileDefPtr;
+struct _virVSIProfileDef {
+ enum virVSIType vsiType;
+ union {
+ struct {
+ uint8_t managerID;
+ uint32_t typeID; // 24 bit valid
+ uint8_t typeIDVersion;
+ unsigned char instanceID[VIR_UUID_BUFLEN];
+ } vsi8021Qbg;
+ struct {
+ char profileID[LIBVIRT_IFLA_VF_PORT_PROFILE_MAX];
+ } vsi8021Qbh;
+ } u;
+};
+
+
/* Stores the virtual network interface configuration */
typedef struct _virDomainNetDef virDomainNetDef;
typedef virDomainNetDef *virDomainNetDefPtr;
@@ -290,6 +323,7 @@ struct _virDomainNetDef {
struct {
char *linkdev;
int mode;
+ virVSIProfileDef vsiProfile;
} direct;
} data;
char *ifname;
@@ -1089,6 +1123,7 @@ VIR_ENUM_DECL(virDomainSeclabel)
VIR_ENUM_DECL(virDomainClockOffset)
VIR_ENUM_DECL(virDomainNetdevMacvtap)
+VIR_ENUM_DECL(virVSI)
VIR_ENUM_DECL(virDomainTimerName)
VIR_ENUM_DECL(virDomainTimerTrack)
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -46,6 +46,7 @@
# include "util.h"
# include "memory.h"
+# include "logging.h"
# include "macvtap.h"
# include "interface.h"
# include "conf/domain_conf.h"
@@ -751,36 +752,127 @@ configMacvtapTap(int tapfd, int vnet_hdr
/**
+ * associatePortProfile
+ *
+ * @linkdev: the link dev in case of macvtap
+ * @mac: the MAC address of the interface
+ * @mode: The vepa mode (private, bridge or vepa)
+ * @vsi: pointer to the object holding port profile parameters
+ * @vf: virtual function number, -1 if to be ignored
+ * @vmuuid : the UUID of the virtual machine
+ *
+ * Associate a port on a swtich with a profile. This function
+ * may notify a kernel driver or an external daemon to run
+ * the setup protocol. If profile parameters were not supplied
+ * by the user, then this function returns without doing
+ * anything.
+ *
+ * Returns 0 in case of success, != 0 otherwise with error
+ * having been reported.
+ */
+static int
+associatePortProfileId(const char *linkdev,
+ const unsigned char *mac,
+ int mode,
+ const virVSIProfileDefPtr vsi,
+ int vf,
+ const unsigned char *vmuuid)
+{
+ int rc = 0;
+ VIR_DEBUG("Associating port profile '%p' on link device '%s' mode %
d ",
+ vsi, linkdev, mode);
+ (void)mac;
+ (void)vf;
+ (void)vmuuid;
+
+ switch (vsi->vsiType) {
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+
+ case VIR_VSI_8021QBG:
+ rc = -1;
+ break;
+
+ case VIR_VSI_8021QBH:
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+
+/**
+ * disassociatePortProfile
+ *
+ * @linkdev: The link dev in case of a macvtap device
+ * @mac: The MAC address of the interface
+ * @vsi: point to object holding port profile parameters
+ *
+ * Returns 0 in case of success, != 0 otherwise with error
+ * having been reported.
+ */
+static int
+disassociatePortProfileId(const char *linkdev,
+ const unsigned char *mac,
+ const virVSIProfileDefPtr vsi)
+{
+ int rc = 0;
+ VIR_DEBUG("Disassociating port profile id '%p' on link device '%s'
",
+ vsi, linkdev);
+ (void)mac;
+
+ switch (vsi->vsiType) {
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+
+ case VIR_VSI_8021QBG:
+ rc = -1;
+ break;
+
+ case VIR_VSI_8021QBH:
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+
+/**
* openMacvtapTap:
* Create an instance of a macvtap device and open its tap character
* device.
* @tgifname: Interface name that the macvtap is supposed to have. May
* be NULL if this function is supposed to choose a name
- * @macaddress: The MAC address for the macvtap device
- * @linkdev: The interface name of the NIC to connect to the external
bridge
- * @mode_str: String describing the mode. Valid are 'bridge', 'vepa'
and
- * 'private'.
+ * @net: pointer to the virDomainNetDef object describing the direct
+ * type if an interface
* @res_ifname: Pointer to a string pointer where the actual name of
the
* interface will be stored into if everything succeeded. It is up
* to the caller to free the string.
+ * @vnet_hdr: Whether to enable IFF_VNET_HDR on the interface
+ * @vmuuid: The (raw) UUID of the VM
*
* Returns file descriptor of the tap device in case of success,
* negative value otherwise with error reported.
*
+ * Open a macvtap device and trigger the switch setup protocol
+ * if valid port profile parameters were provided.
*/
int
openMacvtapTap(const char *tgifname,
- const unsigned char *macaddress,
- const char *linkdev,
- int mode,
+ virDomainNetDefPtr net,
char **res_ifname,
- int vnet_hdr)
+ int vnet_hdr,
+ const unsigned char *vmuuid)
{
const char *type = "macvtap";
int c, rc;
char ifname[IFNAMSIZ];
int retries, do_retry = 0;
- uint32_t macvtapMode = macvtapModeFromInt(mode);
+ uint32_t macvtapMode = macvtapModeFromInt(net->data.direct.mode);
const char *cr_ifname;
int ifindex;
@@ -797,7 +889,7 @@ openMacvtapTap(const char *tgifname,
return -1;
}
cr_ifname = tgifname;
- rc = link_add(type, macaddress, 6, tgifname, linkdev,
+ rc = link_add(type, net->mac, 6, tgifname,
net->data.direct.linkdev,
macvtapMode, &do_retry);
if (rc)
return -1;
@@ -807,7 +899,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,
+ rc = link_add(type, net->mac, 6, ifname,
+ net->data.direct.linkdev,
macvtapMode, &do_retry);
if (rc == 0)
break;
@@ -820,6 +913,15 @@ create_name:
cr_ifname = ifname;
}
+ rc = associatePortProfileId(net->data.direct.linkdev,
+ net->mac,
+ net->data.direct.mode,
+ &net->data.direct.vsiProfile,
+ -1,
+ vmuuid);
+ if (rc != 0)
+ goto link_del_exit;
+
rc = ifaceUp(cr_ifname);
if (rc != 0) {
virReportSystemError(errno,
@@ -828,7 +930,7 @@ create_name:
"MAC address"),
cr_ifname);
rc = -1;
- goto link_del_exit;
+ goto disassociate_exit;
}
rc = openTap(cr_ifname, 10);
@@ -837,14 +939,19 @@ create_name:
if (configMacvtapTap(rc, vnet_hdr) < 0) {
close(rc);
rc = -1;
- goto link_del_exit;
+ goto disassociate_exit;
}
*res_ifname = strdup(cr_ifname);
} else
- goto link_del_exit;
+ goto disassociate_exit;
return rc;
+disassociate_exit:
+ disassociatePortProfileId(net->data.direct.linkdev,
+ net->mac,
+ &net->data.direct.vsiProfile);
+
link_del_exit:
link_del(cr_ifname);
@@ -854,14 +961,21 @@ link_del_exit:
/**
* delMacvtap:
- * @ifname : The name of the macvtap interface
+ * @net: pointer to virDomainNetDef object
*
- * Delete an interface given its name.
+ * Delete an interface given its name. Disassociate
+ * it with the switch if port profile parameters
+ * were provided.
*/
void
-delMacvtap(const char *ifname)
+delMacvtap(virDomainNetDefPtr net)
{
- link_del(ifname);
+ if (net->ifname) {
+ disassociatePortProfileId(net->data.direct.linkdev,
+ net->mac,
+ &net->data.direct.vsiProfile);
+ link_del(net->ifname);
+ }
}
#endif
Index: libvirt-acl/src/util/macvtap.h
===================================================================
--- libvirt-acl.orig/src/util/macvtap.h
+++ libvirt-acl/src/util/macvtap.h
@@ -27,15 +27,15 @@
# if defined(WITH_MACVTAP)
# include "internal.h"
+# include "conf/domain_conf.h"
int openMacvtapTap(const char *ifname,
- const unsigned char *macaddress,
- const char *linkdev,
- int mode,
+ virDomainNetDefPtr net,
char **res_ifname,
- int vnet_hdr);
+ int vnet_hdr,
+ const unsigned char *vmuuid);
-void delMacvtap(const char *ifname);
+void delMacvtap(virDomainNetDefPtr net);
# endif /* WITH_MACVTAP */
Index: libvirt-acl/tests/domainschemadata/portprofile.xml
===================================================================
--- /dev/null
+++ libvirt-acl/tests/domainschemadata/portprofile.xml
@@ -0,0 +1,30 @@
+<domain type='lxc'>
+ <name>portprofile</name>
+ <uuid>00000000-0000-0000-0000-000000000000</uuid>
+ <memory>1048576</memory>
+ <os>
+ <type>exe</type>
+ <init>/sh</init>
+ </os>
+ <devices>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ <vsi type='802.1Qbg'>
+ <parameters managerid='12' typeid='1193046' typeidversion='1'
+ instanceid='fa9b7fff-b0a0-4893-8e0e-beef4ff18f8f'/>
+ </vsi>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ <vsi type='802.1Qbh'>
+ <parameters profileid='my_profile'/>
+ </vsi>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ </interface>
+ </devices>
+</domain>
Index: libvirt-acl/src/qemu/qemu_conf.h
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.h
+++ libvirt-acl/src/qemu/qemu_conf.h
@@ -271,9 +271,8 @@ qemudOpenVhostNet(virDomainNetDefPtr net
int qemudPhysIfaceConnect(virConnectPtr conn,
struct qemud_driver *driver,
virDomainNetDefPtr net,
- char *linkdev,
- int brmode,
- unsigned long long qemuCmdFlags);
+ unsigned long long qemuCmdFlags,
+ const unsigned char *vmuuid);
int qemudProbeMachineTypes (const char *binary,
virCapsGuestMachinePtr
**machines,
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -3585,10 +3585,8 @@ static void qemudShutdownVMDaemon(struct
def = vm->def;
for (i = 0; i < def->nnets; i++) {
virDomainNetDefPtr net = def->nets[i];
- if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (net->ifname)
- delMacvtap(net->ifname);
- }
+ if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT)
+ delMacvtap(net);
}
#endif
@@ -7175,9 +7173,8 @@ static int qemudDomainAttachNetDevice(vi
}
if ((tapfd = qemudPhysIfaceConnect(conn, driver, net,
- net->data.direct.linkdev,
- net->data.direct.mode,
- qemuCmdFlags)) < 0)
+ qemuCmdFlags,
+ vm->def->uuid)) < 0)
return -1;
}
@@ -8146,10 +8143,8 @@ qemudDomainDetachNetDevice(struct qemud_
virNWFilterTearNWFilter(detach);
#if WITH_MACVTAP
- if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (detach->ifname)
- delMacvtap(detach->ifname);
- }
+ if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT)
+ delMacvtap(detach);
#endif
if ((driver->macFilter) && (detach->ifname != NULL)) {
Index: libvirt-acl/src/qemu/qemu_conf.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.c
+++ libvirt-acl/src/qemu/qemu_conf.c
@@ -1465,9 +1465,8 @@ int
qemudPhysIfaceConnect(virConnectPtr conn,
struct qemud_driver *driver,
virDomainNetDefPtr net,
- char *linkdev,
- int brmode,
- unsigned long long qemuCmdFlags)
+ unsigned long long qemuCmdFlags,
+ const unsigned char *vmuuid)
{
int rc;
#if WITH_MACVTAP
@@ -1479,8 +1478,7 @@ qemudPhysIfaceConnect(virConnectPtr conn
net->model && STREQ(net->model, "virtio"))
vnet_hdr = 1;
- rc = openMacvtapTap(net->ifname, net->mac, linkdev, brmode,
- &res_ifname, vnet_hdr);
+ rc = openMacvtapTap(net->ifname, net, &res_ifname, vnet_hdr,
vmuuid);
if (rc >= 0) {
VIR_FREE(net->ifname);
net->ifname = res_ifname;
@@ -1500,15 +1498,13 @@ qemudPhysIfaceConnect(virConnectPtr conn
if (err) {
close(rc);
rc = -1;
- delMacvtap(net->ifname);
+ delMacvtap(net);
}
}
}
#else
(void)conn;
(void)net;
- (void)linkdev;
- (void)brmode;
(void)qemuCmdFlags;
(void)driver;
qemuReportError(VIR_ERR_INTERNAL_ERROR,
@@ -4130,9 +4126,8 @@ int qemudBuildCommandLine(virConnectPtr
goto no_memory;
} else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
int tapfd = qemudPhysIfaceConnect(conn, driver, net,
-
net->data.direct.linkdev,
-
net->data.direct.mode,
- qemuCmdFlags);
+ qemuCmdFlags,
+ def->uuid);
if (tapfd < 0)
goto error;
5
10
* src/datatypes.c: Use correct word.
---
Pushing under the trivial rule.
src/datatypes.c | 18 +++++++++---------
1 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/datatypes.c b/src/datatypes.c
index 25962a6..88ad695 100644
--- a/src/datatypes.c
+++ b/src/datatypes.c
@@ -350,7 +350,7 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) {
}
virMutexLock(&conn->lock);
- /* TODO search by UUID first as they are better differenciators */
+ /* TODO search by UUID first as they are better differentiators */
ret = (virDomainPtr) virHashLookup(conn->domains, name);
/* TODO check the UUID */
@@ -413,7 +413,7 @@ virReleaseDomain(virDomainPtr domain) {
virConnectPtr conn = domain->conn;
DEBUG("release domain %p %s", domain, domain->name);
- /* TODO search by UUID first as they are better differenciators */
+ /* TODO search by UUID first as they are better differentiators */
if (virHashRemoveEntry(conn->domains, domain->name, NULL) < 0) {
virMutexUnlock(&conn->lock);
virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -495,7 +495,7 @@ virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) {
}
virMutexLock(&conn->lock);
- /* TODO search by UUID first as they are better differenciators */
+ /* TODO search by UUID first as they are better differentiators */
ret = (virNetworkPtr) virHashLookup(conn->networks, name);
/* TODO check the UUID */
@@ -553,7 +553,7 @@ virReleaseNetwork(virNetworkPtr network) {
virConnectPtr conn = network->conn;
DEBUG("release network %p %s", network, network->name);
- /* TODO search by UUID first as they are better differenciators */
+ /* TODO search by UUID first as they are better differentiators */
if (virHashRemoveEntry(conn->networks, network->name, NULL) < 0) {
virMutexUnlock(&conn->lock);
virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -815,7 +815,7 @@ virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uui
}
virMutexLock(&conn->lock);
- /* TODO search by UUID first as they are better differenciators */
+ /* TODO search by UUID first as they are better differentiators */
ret = (virStoragePoolPtr) virHashLookup(conn->storagePools, name);
/* TODO check the UUID */
@@ -874,7 +874,7 @@ virReleaseStoragePool(virStoragePoolPtr pool) {
virConnectPtr conn = pool->conn;
DEBUG("release pool %p %s", pool, pool->name);
- /* TODO search by UUID first as they are better differenciators */
+ /* TODO search by UUID first as they are better differentiators */
if (virHashRemoveEntry(conn->storagePools, pool->name, NULL) < 0) {
virMutexUnlock(&conn->lock);
virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -1022,7 +1022,7 @@ virReleaseStorageVol(virStorageVolPtr vol) {
virConnectPtr conn = vol->conn;
DEBUG("release vol %p %s", vol, vol->name);
- /* TODO search by UUID first as they are better differenciators */
+ /* TODO search by UUID first as they are better differentiators */
if (virHashRemoveEntry(conn->storageVols, vol->key, NULL) < 0) {
virMutexUnlock(&conn->lock);
virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -1428,7 +1428,7 @@ virGetNWFilter(virConnectPtr conn, const char *name, const unsigned char *uuid)
}
virMutexLock(&conn->lock);
- /* TODO search by UUID first as they are better differenciators */
+ /* TODO search by UUID first as they are better differentiators */
ret = (virNWFilterPtr) virHashLookup(conn->nwfilterPools, name);
/* TODO check the UUID */
@@ -1487,7 +1487,7 @@ virReleaseNWFilterPool(virNWFilterPtr pool) {
virConnectPtr conn = pool->conn;
DEBUG("release pool %p %s", pool, pool->name);
- /* TODO search by UUID first as they are better differenciators */
+ /* TODO search by UUID first as they are better differentiators */
if (virHashRemoveEntry(conn->nwfilterPools, pool->name, NULL) < 0) {
virMutexUnlock(&conn->lock);
virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s",
--
1.7.0.1
1
0
12 May '10
Just a reminder...The submission deadline is in two days.
thanks,
-KVM Forum 2010 Program Commitee
--
=================================================================
CALL FOR PAPERS
KVM Forum 2010
=================================================================
DESCRIPTION
The KVM Forum is back! After a break last year we're proud to present
this year's gathering around KVM again. The idea is to have everyone
involved with KVM development come together to talk about the future
and current state of KVM, teaching everyone some pieces of the puzzle
they might be missing without.
So if you're a KVM developer, mark the dates in your calendar! If
possible, also submit a talk -- we're interested in a wide variety of
KVM topics, so don't hesitate to propose a talk on your work.
If you're not a KVM developer, please read on nevertheless (or jump to
END USER COLLABORATION).
DATES / LOCATION
Conference: August 9 - 10, 2010
Location: Renaissance Boston Waterfront in Boston, MA
Abstracts due: May 14th, 2010
Notification: May 28th, 2010
Yes, we're colocated with LinuxCon. Tickets for the KVM Forum also count
for LinuxCon.
http://events.linuxfoundation.org/component/registrationpro/?func=details&d…
PROCESS
At first check if it's before May 14th. If you're past that date, you're
out of luck. Now try to think hard and come up with a great idea that
you could talk about. Once you have that set, we need you to write up
a short abstract (~150 words) on it. In your submission please note
how long your talk will take. Slots vary in length up to one hour.
Also include in your proposal the proposal type -- one of: technical talk,
breakout session, or end-user talk. Add that information to the abstract
and submit it at the following URL:
http://events.linuxfoundation.org/cfp/cfp-add
Now, wait until May 24th. You will receive a notification on whether
your talk was accepted or not.
SCOPE OF TALKS
We have a list of suggested presentation topics below. These suggestions
are just for guidance, please feel free to submit a proposal on any
of these or related topics. In general, the more it's about backend
infrastructure, the better.
KVM
- Scaling and performance
- Nested virtualization
- I/O improvements
- Driver domains
- Time keeping
- Memory management (page sharing, swapping, huge pages, etc)
- Fault tolerance
- VEPA, vswitch
Embedded KVM
- KVM on ARM, PPC, MIPS, ...?
- Real-time requirements host/guest
- Device pass-through w/o iommu
- Custom device/platform models
QEMU
- Device model improvements
- New devices
- Security model
- Scaling and performance
- Desktop virtualization
- Increasing robustness
- Management interfaces
- QMP protocol and implementation
- Live migration
Virtio
- Speeding up existing devices
- Vhost
- Alternatives
- Using virtio in non-kvm environments
- Virtio on non-Linux
Management infrastructure
- Libvirt
- Kvm autotest
- Easy networking
- Qemud
BREAKOUT SESSION
We will reserve some time each day to break out for working sessions.
These sessions will be less formal than a presentation and more focused
on developing a solution to some real development issue. If you are
interested in getting developers together to hack on some code, submit
your proposal and just make it clear it's a breakout session proposal.
END-USER COLLABORATION
One of the big challenges as developers is to know what, where and how
people actually use our software. To solve this issue at least a little,
there will be a few slots reserved for end users talking about their
deployments, problems and achievements.
So if you have a KVM based deployment running in production or are about
to roll out one, please also submit a talk (see PROCESS), and simply
mark it asn an end-user collaboration proposal. We would love to have
an open discussion of fields where KVM/Qemu can still improve and you
would have the unique chance to steer that process!
Keep in mind that most of the Forum will be focused on development though,
so we suggest you also come with a good portion of technical interest :-).
And of course, no product marketing please! The purpose is to engage
with KVM developers.
LIGHTNING TALKS
In addition to submitted talks we will also have some room for lightning
talks. So if you have something you think might be done until the KVM
Forum, but you're not sure you could fill 15 minutes with it. Or if you
don't know if you'll make it until there, just keep in mind that you
will still get the chance to talk about it. Lightning talk submissions
and scheduling will be handled on-site at KVM Forum.
Thank you for your interest in KVM. We're looking forward to your
submissions and seeing you at the KVM Forum 2010 in August! Now, start
thinking about that talk you want to give.
Thanks,
your KVM Forum 2010 Program Commitee
Alexander Graf, Novell
Anthony Liguori, IBM
Avi Kivity, Red Hat
Chris Wright, Red Hat
Dor Laor, Red Hat
Jan Kiszka, Siemens
Please contact us with any questions or comments.
KVM-Forum-2010-PC(a)redhat.com
1
0
12 May '10
From: Jiri Denemark <jdenemar(a)redhat.com>
As described in https://bugzilla.redhat.com/show_bug.cgi?id=582278
libvirt may hang during concurrent P2P migration of several KVM guests.
These two patches fix that for me. Hopefully the fix will be confirmed
by the reporter.
Jirka
Jiri Denemark (2):
Remove watches before calling REMOTE_PROC_CLOSE
Fix monitor ref counting when adding event handle
src/qemu/qemu_monitor.c | 11 ++++++++++-
src/remote/remote_driver.c | 10 +++++-----
2 files changed, 15 insertions(+), 6 deletions(-)
5
10
Posting as an RFC, since this patch series could be extended to do
a lot more cleanups - I don't want to do the extra work unless we
agree that this is worthwhile. See each patch for more comments.
[RFC PATCH 1/3] build: use gnulib func module
[PATCH 2/3] datatypes: avoid redundant __FUNCTION__
[RFC PATCH 3/3] libvirt: convert virLibNetworkError to avoid __FUNCTION__
bootstrap.conf | 1 +
src/datatypes.c | 36 ++++++++++++++++++------------------
src/libvirt.c | 52 +++++++++++++++++++++++++++-------------------------
3 files changed, 46 insertions(+), 43 deletions(-)
4
6