This patch adds three utility functions that operate on
virNetDevVPortProfile objects.
* virNetDevVPortProfileCheckComplete() - verifies that all attributes
required for the type of the given virtport are specified.
* virNetDevVPortProfileCheckNoExtras() - verifies that there are no
attributes specified which are inappropriate for the type of the
given virtport.
* virNetDevVPortProfileMerge3() - merges 3 virtports into a single,
newly allocated virtport. If any attributes are specified in
more than one of the three sources, and do not exactly match,
an error is logged and the function fails.
These new functions depend on new fields in the virNetDevVPortProfile
object that keep track of whether or not each attribute was
specified. Since the higher level parse function doesn't yet set those
fields, these functions are not actually usable yet (but that's okay,
because they also aren't yet used - all of that functionality comes in
a later patch.)
Note that these three functions return 0 on success and -1 on
failure. This may seem odd for the first two Check functions, since
they could also easily return true/false, but since they actually log
an error when the requested condition isn't met (and should result in
a failure of the calling function), I thought 0/-1 was more
appropriate.
---
src/libvirt_private.syms | 3 +
src/util/virnetdevvportprofile.c | 291 +++++++++++++++++++++++++++++++++++++++
src/util/virnetdevvportprofile.h | 16 ++-
3 files changed, 309 insertions(+), 1 deletion(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 44b6652..5d46e61 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1428,8 +1428,11 @@ virNetDevVethDelete;
# virnetdevvportprofile.h
virNetDevVPortProfileAssociate;
+virNetDevVPortProfileCheckComplete;
+virNetDevVPortProfileCheckNoExtras;
virNetDevVPortProfileDisassociate;
virNetDevVPortProfileEqual;
+virNetDevVPortProfileMerge3;
virNetDevVPortProfileOpTypeFromString;
virNetDevVPortProfileOpTypeToString;
diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c
index 6db04f7..176190f 100644
--- a/src/util/virnetdevvportprofile.c
+++ b/src/util/virnetdevvportprofile.c
@@ -120,6 +120,297 @@ virNetDevVPortProfileEqual(virNetDevVPortProfilePtr a,
virNetDevVPortProfilePtr
return true;
}
+/* virNetDevVPortProfileCheckComplete() checks that all attributes
+ * required for the type of virtport are specified. if virtport ==
+ * NULL or virtPortType == NONE, then the result is always 0
+ * (success). If a required attribute is missing, an error is logged
+ * and -1 is returned.
+ */
+int
+virNetDevVPortProfileCheckComplete(virNetDevVPortProfilePtr virtport)
+{
+ const char *missing = NULL;
+
+ if (!virtport || virtport->virtPortType == VIR_NETDEV_VPORT_PROFILE_NONE)
+ return 0;
+
+ switch (virtport->virtPortType) {
+ case VIR_NETDEV_VPORT_PROFILE_8021QBG:
+ if (!virtport->managerID_specified)
+ missing = "managerid";
+ else if (!virtport->typeID_specified)
+ missing = "typeid";
+ else if (!virtport->typeIDVersion_specified)
+ missing = "typeidversion";
+ else if (!virtport->instanceID_specified)
+ missing = "instanceid";
+ break;
+
+ case VIR_NETDEV_VPORT_PROFILE_8021QBH:
+ if (!virtport->profileID[0])
+ missing = "profileid";
+ break;
+
+ case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
+ /* profileid is optional for openvswitch */
+ if (!virtport->interfaceID_specified) {
+ missing = "interfaceid";
+ }
+ break;
+ }
+
+ if (missing) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("missing %s in <virtualport
type='%s'>"), missing,
+ virNetDevVPortTypeToString(virtport->virtPortType));
+ return -1;
+ }
+
+ return 0;
+}
+
+/* virNetDevVPortProfileCheckNoExtras() checks that there are no
+ * attributes specified in this virtport that are inappropriate for
+ * the type. if virtport == NULL or virtPortType == NONE, then the
+ * result is always 0 (success). If an extra attribute is present,
+ * an error is logged and -1 is returned.
+ */
+int
+virNetDevVPortProfileCheckNoExtras(virNetDevVPortProfilePtr virtport)
+{
+ const char *extra = NULL;
+
+ if (!virtport || virtport->virtPortType == VIR_NETDEV_VPORT_PROFILE_NONE)
+ return 0;
+
+ switch (virtport->virtPortType) {
+ case VIR_NETDEV_VPORT_PROFILE_8021QBG:
+ if (virtport->profileID[0])
+ extra = "profileid";
+ else if (virtport->interfaceID_specified)
+ extra = "interfaceid";
+ break;
+
+ case VIR_NETDEV_VPORT_PROFILE_8021QBH:
+ if (virtport->managerID_specified)
+ extra = "managerid";
+ else if (virtport->typeID_specified)
+ extra = "typeid";
+ else if (virtport->typeIDVersion_specified)
+ extra = "typeidversion";
+ else if (virtport->instanceID_specified)
+ extra = "instanceid";
+ else if (virtport->interfaceID_specified)
+ extra = "interfaceid";
+ break;
+
+ case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
+ if (virtport->managerID_specified)
+ extra = "managerid";
+ else if (virtport->typeID_specified)
+ extra = "typeid";
+ else if (virtport->typeIDVersion_specified)
+ extra = "typeidversion";
+ else if (virtport->instanceID_specified)
+ extra = "instanceid";
+ break;
+ }
+
+ if (extra) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("extra %s unsupported in <virtualport
type='%s'>"),
+ extra,
+ virNetDevVPortTypeToString(virtport->virtPortType));
+ return -1;
+ }
+
+ return 0;
+}
+
+/* virNetDevVPortProfileMerge() - merge the attributes in mods into
+ * orig. If anything that is set in mods has already been set in orig
+ * *and doesn't match*, log an error and return -1, otherwise return 0.
+ */
+static int
+virNetDevVPortProfileMerge(virNetDevVPortProfilePtr orig,
+ virNetDevVPortProfilePtr mods)
+{
+ enum virNetDevVPortProfile otype;
+
+ if (!orig || !mods)
+ return 0;
+
+ otype = orig->virtPortType;
+
+ if (mods->virtPortType != VIR_NETDEV_VPORT_PROFILE_NONE) {
+ if (otype != VIR_NETDEV_VPORT_PROFILE_NONE &&
+ otype != mods->virtPortType) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("attempt to merge virtualports "
+ "with mismatched types (%s and %s)"),
+ virNetDevVPortTypeToString(otype),
+ virNetDevVPortTypeToString(mods->virtPortType));
+ return -1;
+ }
+ otype = orig->virtPortType = mods->virtPortType;
+ }
+
+ if (mods->managerID_specified &&
+ (otype == VIR_NETDEV_VPORT_PROFILE_8021QBG ||
+ otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
+ if (orig->managerID_specified &&
+ (orig->managerID != mods->managerID)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("attempt to merge virtualports "
+ "with mismatched managerids (%d and %d)"),
+ orig->managerID, mods->managerID);
+ return -1;
+ }
+ orig->managerID = mods->managerID;
+ orig->managerID_specified = true;
+ }
+
+ if (mods->typeID_specified &&
+ (otype == VIR_NETDEV_VPORT_PROFILE_8021QBG ||
+ otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
+ if (orig->typeID_specified &&
+ (orig->typeID != mods->typeID)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("attempt to merge virtualports "
+ "with mismatched typeids (%d and %d)"),
+ orig->typeID, mods->typeID);
+ return -1;
+ }
+ orig->typeID = mods->typeID;
+ orig->typeID_specified = true;
+ }
+
+ if (mods->typeIDVersion_specified &&
+ (otype == VIR_NETDEV_VPORT_PROFILE_8021QBG ||
+ otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
+ if (orig->typeIDVersion_specified &&
+ (orig->typeIDVersion != mods->typeIDVersion)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("attempt to merge virtualports with "
+ "mismatched typeidversions (%d and %d)"),
+ orig->typeIDVersion, mods->typeIDVersion);
+ return -1;
+ }
+ orig->typeIDVersion = mods->typeIDVersion;
+ orig->typeIDVersion_specified = true;
+ }
+
+ if (mods->instanceID_specified &&
+ (otype == VIR_NETDEV_VPORT_PROFILE_8021QBG ||
+ otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
+ if (orig->instanceID_specified &&
+ memcmp(orig->instanceID, mods->instanceID,
+ sizeof(orig->instanceID))) {
+ char origuuid[VIR_UUID_STRING_BUFLEN];
+ char modsuuid[VIR_UUID_STRING_BUFLEN];
+
+ virReportError(VIR_ERR_XML_ERROR,
+ _("attempt to merge virtualports with "
+ "mismatched instanceids ('%s' and
'%s')"),
+ virUUIDFormat(orig->instanceID, origuuid),
+ virUUIDFormat(mods->instanceID, modsuuid));
+ return -1;
+ }
+ memcpy(orig->instanceID, mods->instanceID, sizeof(orig->instanceID));
+ orig->instanceID_specified = true;
+ }
+
+ if (mods->interfaceID_specified &&
+ (otype == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH ||
+ otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
+ if (orig->interfaceID_specified &&
+ memcmp(orig->interfaceID, mods->interfaceID,
+ sizeof(orig->interfaceID))) {
+ char origuuid[VIR_UUID_STRING_BUFLEN];
+ char modsuuid[VIR_UUID_STRING_BUFLEN];
+
+ virReportError(VIR_ERR_XML_ERROR,
+ _("attempt to merge virtualports with "
+ "mismatched interfaceids ('%s' and
'%s')"),
+ virUUIDFormat(orig->interfaceID, origuuid),
+ virUUIDFormat(mods->interfaceID, modsuuid));
+ return -1;
+ }
+ memcpy(orig->interfaceID, mods->interfaceID,
sizeof(orig->interfaceID));
+ orig->interfaceID_specified = true;
+ }
+
+ if (mods->profileID[0] &&
+ (otype == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH ||
+ otype == VIR_NETDEV_VPORT_PROFILE_8021QBH ||
+ otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
+ if (orig->profileID[0] &&
+ STRNEQ(orig->profileID, mods->profileID)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("attempt to merge virtualports with "
+ "mismatched profileids ('%s' and
'%s')"),
+ orig->profileID, mods->profileID);
+ return -1;
+ }
+ if (virStrcpyStatic(orig->profileID, mods->profileID)) {
+ /* this should never happen - it indicates mods->profileID
+ * isn't properly null terminated. */
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("corrupted profileid string"));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* virNetDevVPortProfileMerge3() - create a new virNetDevVPortProfile
+ * that is a combination of the three input profiles. fromInterface is
+ * highest priority and fromPortgroup is lowest. As lower priority
+ * objects' attributes are merged in, if the attribute is unset in the
+ * result object, it is set from the lower priority object, but if it
+ * is already set in the result and the lower priority object wants to
+ * change it, that is an error.
+ */
+
+int virNetDevVPortProfileMerge3(virNetDevVPortProfilePtr *result,
+ virNetDevVPortProfilePtr fromInterface,
+ virNetDevVPortProfilePtr fromNetwork,
+ virNetDevVPortProfilePtr fromPortgroup)
+{
+ int ret = -1;
+ *result = NULL;
+
+ if ((!fromInterface || (fromInterface->virtPortType ==
VIR_NETDEV_VPORT_PROFILE_NONE)) &&
+ (!fromNetwork || (fromNetwork->virtPortType ==
VIR_NETDEV_VPORT_PROFILE_NONE)) &&
+ (!fromPortgroup || (fromPortgroup->virtPortType ==
VIR_NETDEV_VPORT_PROFILE_NONE))) {
+ return ret;
+ }
+
+ /* at least one of the source profiles is non-empty */
+ if (VIR_ALLOC(*result) < 0) {
+ virReportOOMError();
+ return ret;
+ }
+
+ /* start with the interface's profile. There are no pointers in a
+ * virtualPortProfile, so a shallow copy is sufficient.
+ */
+ if (fromInterface)
+ **result = *fromInterface;
+
+ if (virNetDevVPortProfileMerge(*result, fromNetwork) < 0)
+ goto error;
+ if (virNetDevVPortProfileMerge(*result, fromPortgroup) < 0)
+ goto error;
+
+ ret = 0;
+
+error:
+ if (ret < 0)
+ VIR_FREE(*result);
+ return ret;
+}
+
#if WITH_VIRTUALPORT
diff --git a/src/util/virnetdevvportprofile.h b/src/util/virnetdevvportprofile.h
index e204c95..f5f9b12 100644
--- a/src/util/virnetdevvportprofile.h
+++ b/src/util/virnetdevvportprofile.h
@@ -60,18 +60,24 @@ VIR_ENUM_DECL(virNetDevVPortProfileOp)
typedef struct _virNetDevVPortProfile virNetDevVPortProfile;
typedef virNetDevVPortProfile *virNetDevVPortProfilePtr;
struct _virNetDevVPortProfile {
- enum virNetDevVPortProfile virtPortType;
+ int virtPortType; /* enum virNetDevVPortProfile */
/* these members are used when virtPortType == 802.1Qbg */
uint8_t managerID;
+ bool managerID_specified;
uint32_t typeID; /* 24 bit valid */
+ bool typeID_specified;
uint8_t typeIDVersion;
+ bool typeIDVersion_specified;
unsigned char instanceID[VIR_UUID_BUFLEN];
+ bool instanceID_specified;
/* this member is used when virtPortType == 802.1Qbh|openvswitch */
+ /* this is a null-terminated character string */
char profileID[LIBVIRT_IFLA_VF_PORT_PROFILE_MAX];
/* this member is used when virtPortType == openvswitch */
unsigned char interfaceID[VIR_UUID_BUFLEN];
+ bool interfaceID_specified;
/* NB - if virtPortType == NONE, any/all of the items could be used */
};
@@ -79,6 +85,14 @@ struct _virNetDevVPortProfile {
bool virNetDevVPortProfileEqual(virNetDevVPortProfilePtr a,
virNetDevVPortProfilePtr b);
+int virNetDevVPortProfileCheckComplete(virNetDevVPortProfilePtr virtport);
+int virNetDevVPortProfileCheckNoExtras(virNetDevVPortProfilePtr virtport);
+
+int virNetDevVPortProfileMerge3(virNetDevVPortProfilePtr *result,
+ virNetDevVPortProfilePtr fromInterface,
+ virNetDevVPortProfilePtr fromNetwork,
+ virNetDevVPortProfilePtr fromPortgroup);
+
int virNetDevVPortProfileAssociate(const char *ifname,
const virNetDevVPortProfilePtr virtPort,
const virMacAddrPtr macaddr,
--
1.7.11.2