return true;
}
+/* virNetDevVPortProfileCheckComplete() checks that all attributes
+ * required for the type of virtport are specified. When
+ * generateMissing is true, any missing attribute that can be
+ * autogenerated, will be (instanceid, interfaceid). 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,
+ bool generateMissing)
+{
+ 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) {
+ if (generateMissing) {
+ if (virUUIDGenerate(virtport->instanceID) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot generate a random uuid for instanceid"));
+ return -1;
+ }
+ virtport->instanceID_specified = true;
+ } else {
+ 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) {
+ if (generateMissing) {
+ if (virUUIDGenerate(virtport->interfaceID) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot generate a random uuid for interfaceid"));
+ return -1;
+ }
+ virtport->interfaceID_specified = true;
+ } else {
+ 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 0;
+ }
+
+ /* 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