Bug 5008 - QoS and Queue fixes for ovsdb southbound 36/32836/3
authorEric Multanen <eric.w.multanen@intel.com>
Mon, 14 Dec 2015 15:10:10 +0000 (07:10 -0800)
committerSam Hague <shague@redhat.com>
Mon, 25 Jan 2016 15:01:08 +0000 (15:01 +0000)
Update the operational MD-SAL for Queue and Qos updates from the OVS
host.

Support configuration of QoS and Queue via configuration MD-SAL.

- Support for adding and deleting QoS entries.  A qos-id is used
  as a handle for qos entries in the MD-SAL.  This is added to
  the 'external-ids' of the qos entry.  Qos entries originating
  from the OVS host are assigned a qos-id of "qos://<uuid>".
- Qos entries can be assigned to a Port (termination point)
  which is present in the MD-SAL by setting the port qos
  attribute to the UUID of the relevant Qos entry.
- Qos entries are cleared from a port by updating the
  port configuration with the qos attribute removed.
- Support for adding and deleting Queue entries. a queue-id
  is used as a handle for queue entries in the MD-SAL.  This
  is added to the 'external-ids' of the queue entry.  Queue
  entries originating from the OVS host are assign a qos-id
  of "queue://<uuid>".
- Queue entries can be added or deleted to the queue list
  of a Qos entry present in the config by filling out (or
  removing from) the queue-list attribute of the qos entry.

v2 - added setting of exising qos uuid to an existing port
   - added clearing of a qos setting for a port
v3 - ovsdb.yang whitespace fixes
   - fixes for failed tests
v4 - fixed model - queue list in Qos entries needed
     a queuenumber key value
   - fixed up comments on whitespace and log messages
v5 - finished set/clear of queues list in a qos entry
   - added more description about the functionality in
     the patch set.
v6 - fixed up more whitespace, and copyright comments.
v7 - address review comments:
     - white space
     - remove unnecessary code
     - remove commented out code
     - adjust some LOG levels
     - remove unused imports

Change-Id: Idec02aaa82e1ffa66e58862ecfc5edff05050444
Signed-off-by: Eric Multanen <eric.w.multanen@intel.com>
(cherry picked from commit d64c55d65dda23f61737086d1522b0c2347b2391)

17 files changed:
southbound/southbound-api/src/main/yang/ovsdb.yang
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/SouthboundConstants.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/SouthboundMapper.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QosRemovedCommand.java [new file with mode: 0644]
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QosUpdateCommand.java [new file with mode: 0644]
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QueueRemovedCommand.java [new file with mode: 0644]
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QueueUpdateCommand.java [new file with mode: 0644]
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TerminationPointUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactCommandAggregator.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbOperationalCommandAggregator.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbPortUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQosRemovedCommand.java [new file with mode: 0644]
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQosUpdateCommand.java [new file with mode: 0644]
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQueueRemovedCommand.java [new file with mode: 0644]
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQueueUpdateCommand.java [new file with mode: 0644]
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactCommandAggregatorTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbOperationalCommandAggregatorTest.java

index 70459cf54811ab6179a3981f19943e24dfd67874..b32c0f0ddcd043edbdcd5cb88d9c86a38cb8402e 100755 (executable)
@@ -457,7 +457,7 @@ module ovsdb {
                in the datapath.
 
              other_config : enable-statistics: optional string
-               either ture or false. Set this value to true to enable populating the
+                either ture or false. Set this value to true to enable populating the
                 statistics column or to false to explicitly disable it.";
 
             key "other-config-key";
@@ -488,7 +488,11 @@ module ovsdb {
         }
 
         list qos-entries {
-            key "qos-uuid";
+            key "qos-id";
+            leaf qos-id {
+                description "An identifier used for QoS entries in the MD-SAL.";
+                type inet:uri;
+            }
             leaf qos-uuid {
                 description "The unique identifier of the QoS.";
                 type yang:uuid;
@@ -500,9 +504,13 @@ module ovsdb {
             }
             list queue-list {
                 description "The list of queues used by the QoS";
-                key "queue-uuid";
+                key "queue-number";
+                leaf queue-number {
+                       description "The queue number of the record in the QoS entry";
+                       type uint32;
+                }
                 leaf queue-uuid {
-                    description "The unique identifier of the queue.";
+                    description "The unique identifier of the queue record.";
                     type yang:uuid;
                 }
             }
@@ -537,7 +545,11 @@ module ovsdb {
         }
 
         list queues {
-            key "queue-uuid";
+            key "queue-id";
+            leaf queue-id {
+                description "An identifier used for Queue entries in the MD-SAL.";
+                type inet:uri;
+            }
             leaf queue-uuid {
                 description "The unique identifier of the queue.";
                 type yang:uuid;
@@ -545,6 +557,19 @@ module ovsdb {
             leaf dscp {
                 type uint8;
             }
+            list queues-external-ids {
+                key "queues-external-id-key";
+                leaf queues-external-id-key {
+                    description "queues external-id name/key";
+                    type string;
+                    mandatory true;
+                }
+                leaf queues-external-id-value {
+                    description "queues-external-id value";
+                    type string;
+                    mandatory true;
+                }
+            }
             list queues-other-config {
                 description "
                 Configuration for linux-htb QoS:
@@ -821,7 +846,7 @@ module ovsdb {
 
             other_config : lacp-fallback-ab: optional string
                 either true or false Determines the behavior of openvswitch bond in LACP mode.
-               If the partner switch does not support LACP, setting this
+                If the partner switch does not support LACP, setting this
                 option to true allows openvswitch to fallback to active-backup.
                 If the option is set to false, the bond will be disabled.
                 In both the cases, once the partner switch is configured
index 26dde438c9591fabd90cd1e1213febcbf5913475..d577ed46b33d2444126e9e4dce02a3da71d89f7c 100755 (executable)
@@ -38,6 +38,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeSystem;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeNetdev;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.QosTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.QosTypeLinuxHfsc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.QosTypeLinuxHtb;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
 
 import com.google.common.collect.ImmutableBiMap;
@@ -48,10 +51,20 @@ public class SouthboundConstants {
     public static final String OVSDB_URI_PREFIX = "ovsdb";
     public static final String BRIDGE_URI_PREFIX = "bridge";
     public static final String TP_URI_PREFIX = "terminationpoint";
+    public static final String QOS_URI_PREFIX = "qos";
+    public static final String QUEUE_URI_PREFIX = "queue";
     public static final Integer DEFAULT_OVSDB_PORT = 6640;
     public static final String DEFAULT_OPENFLOW_PORT = "6653";
     public static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
     public static final String UUID = "uuid";
+    public static final String QOS_LINUX_HTB = "linux-htb";
+    public static final String QOS_LINUX_HFSC = "linux-hfsc";
+    public static final ImmutableBiMap<Class<? extends QosTypeBase>,String> QOS_TYPE_MAP
+        = new ImmutableBiMap.Builder<Class<? extends QosTypeBase>,String>()
+            .put(QosTypeLinuxHtb.class,QOS_LINUX_HTB)
+            .put(QosTypeLinuxHfsc.class,QOS_LINUX_HFSC)
+            .build();
+
     public static final ImmutableBiMap<Class<? extends OvsdbBridgeProtocolBase>,String> OVSDB_PROTOCOL_MAP
         = new ImmutableBiMap.Builder<Class<? extends OvsdbBridgeProtocolBase>,String>()
             .put(OvsdbBridgeProtocolOpenflow10.class,"OpenFlow10")
@@ -94,6 +107,8 @@ public class SouthboundConstants {
             .put(DatapathTypeNetdev.class,"netdev")
             .build();
     public static final String IID_EXTERNAL_ID_KEY = "opendaylight-iid";
+    public static final String QOS_ID_EXTERNAL_ID_KEY = "opendaylight-qos-id";
+    public static final String QUEUE_ID_EXTERNAL_ID_KEY = "opendaylight-queue-id";
 
     public enum VLANMODES {
         ACCESS("access"),
index 4f5ae1730bc35538099d788e9f221848cb273f09..e041365be38dd76119200dd1ccd8b2445b03f9ac 100644 (file)
@@ -16,6 +16,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 import org.opendaylight.ovsdb.lib.OvsdbClient;
@@ -27,11 +28,13 @@ import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.ovsdb.schema.openvswitch.Controller;
 import org.opendaylight.ovsdb.schema.openvswitch.Manager;
 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
+import org.opendaylight.ovsdb.schema.openvswitch.Qos;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeSystem;
@@ -39,6 +42,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.QosTypeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
@@ -47,6 +51,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntries;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntriesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfigBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
@@ -454,6 +462,42 @@ public class SouthboundMapper {
         }
     }
 
+    /**
+     * Return the MD-SAL QoS type class corresponding to the QoS type {@link Qos}
+     *
+     * @param type the QoS type to match {@link String}
+     * @return class matching the input QoS type {@link QosTypeBase}
+     */
+    public static  Class<? extends QosTypeBase> createQosType(String type) {
+        Preconditions.checkNotNull(type);
+        if (type.isEmpty()) {
+            LOG.info("QoS type not supplied");
+            return QosTypeBase.class;
+        } else {
+            ImmutableBiMap<String, Class<? extends QosTypeBase>> mapper =
+                    SouthboundConstants.QOS_TYPE_MAP.inverse();
+            if (mapper.get(type) == null) {
+                LOG.info("QoS type not found in model: {}", type);
+                return QosTypeBase.class;
+            } else {
+                return mapper.get(type);
+            }
+        }
+    }
+
+    public static String createQosType(Class<? extends QosTypeBase> qosTypeClass) {
+    String qosType = SouthboundConstants.DATAPATH_TYPE_MAP.get(QosTypeBase.class);
+
+        if (qosTypeClass != null && !qosTypeClass.equals(QosTypeBase.class)) {
+            qosType = SouthboundConstants.QOS_TYPE_MAP.get(qosTypeClass);
+            if (qosType == null) {
+                throw new IllegalArgumentException("Unknown QoS type" + qosTypeClass.getName());
+            }
+        }
+        return qosType;
+    }
+
+
     public static InstanceIdentifier<Node> getInstanceIdentifier(OpenVSwitch ovs) {
         InstanceIdentifier<Node> iid = null;
         if (ovs.getExternalIdsColumn() != null
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QosRemovedCommand.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QosRemovedCommand.java
new file mode 100644 (file)
index 0000000..03036e9
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016 Intel Corporation and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.southbound.ovsdb.transact;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.ovsdb.lib.notation.Mutator;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Qos;
+import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntries;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+
+public class QosRemovedCommand extends AbstractTransactCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(QosRemovedCommand.class);
+
+    public QosRemovedCommand(BridgeOperationalState state,
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        super(state, changes);
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        Set<InstanceIdentifier<QosEntries>> removed =
+                TransactUtils.extractRemoved(getChanges(),QosEntries.class);
+
+        Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> originals
+            = TransactUtils.extractOriginal(getChanges(),OvsdbNodeAugmentation.class);
+
+        Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> updated
+        = TransactUtils.extractUpdated(getChanges(), OvsdbNodeAugmentation.class);
+
+        Iterator<InstanceIdentifier<OvsdbNodeAugmentation>> itr = originals.keySet().iterator();
+        while (itr.hasNext()) {
+            InstanceIdentifier<OvsdbNodeAugmentation> ovsdbNodeIid = itr.next();
+            OvsdbNodeAugmentation original = originals.get(ovsdbNodeIid);
+            OvsdbNodeAugmentation update = updated.get(ovsdbNodeIid);
+
+            if (original != null && update != null) {
+                List<QosEntries> origQosEntries = original.getQosEntries();
+                List<QosEntries> updatedQosEntries = update.getQosEntries();
+                if (origQosEntries != null && !origQosEntries.isEmpty()) {
+                    for (QosEntries origQosEntry : origQosEntries) {
+                        OvsdbNodeAugmentation operNode = getOperationalState().getBridgeNode(ovsdbNodeIid).get().getAugmentation(OvsdbNodeAugmentation.class);
+                        List<QosEntries> operQosEntries = operNode.getQosEntries();
+
+                        boolean found = false;
+                        if (updatedQosEntries != null && !updatedQosEntries.isEmpty()) {
+                            for (QosEntries updatedQosEntry : updatedQosEntries) {
+                                if (origQosEntry.getQosId().equals(updatedQosEntry.getQosId())) {
+                                    found = true;
+                                    break;
+                                }
+                            }
+                        }
+                        if (!found) {
+                            LOG.debug("Received request to delete QoS entry {}",origQosEntry.getQosId());
+                            Uuid qosUuid = getQosEntryUuid(operQosEntries, origQosEntry.getQosId());
+                            if (qosUuid != null) {
+                                Qos qos = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Qos.class, null);
+                                  transaction.add(op.delete(qos.getSchema())
+                                          .where(qos.getUuidColumn().getSchema().opEqual(new UUID(qosUuid.getValue())))
+                                          .build());
+                            } else {
+                                LOG.warn("Unable to delete QoS{} for node {} because it was not found in the operational store, "
+                                        + "and thus we cannot retrieve its UUID", origQosEntry.getQosId(), ovsdbNodeIid);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private Uuid getQosEntryUuid(List<QosEntries> operQosEntries, Uri qosId) {
+        if (operQosEntries != null && !operQosEntries.isEmpty()) {
+            for (QosEntries qosEntry : operQosEntries) {
+                if (qosEntry.getQosId().equals(qosId)) {
+                    return qosEntry.getQosUuid();
+                }
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QosUpdateCommand.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QosUpdateCommand.java
new file mode 100644 (file)
index 0000000..46d845e
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2016 Intel Corporation and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.southbound.ovsdb.transact;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.ovsdb.lib.notation.Condition;
+import org.opendaylight.ovsdb.lib.notation.Mutator;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.operations.Mutate;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Port;
+import org.opendaylight.ovsdb.schema.openvswitch.Qos;
+import org.opendaylight.ovsdb.southbound.SouthboundConstants;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntries;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QueueList;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+public class QosUpdateCommand extends AbstractTransactCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(QosUpdateCommand.class);
+
+
+    public QosUpdateCommand(BridgeOperationalState state, AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        super(state, changes);
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> created =
+                TransactUtils.extractCreated(getChanges(),OvsdbNodeAugmentation.class);
+        for (Entry<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> ovsdbNodeEntry:
+            created.entrySet()) {
+            updateQos(transaction,  ovsdbNodeEntry.getKey(), ovsdbNodeEntry.getValue());
+        }
+        Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> updated =
+                TransactUtils.extractUpdated(getChanges(),OvsdbNodeAugmentation.class);
+        for (Entry<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> ovsdbNodeEntry:
+            updated.entrySet()) {
+            updateQos(transaction,  ovsdbNodeEntry.getKey(), ovsdbNodeEntry.getValue());
+        }
+    }
+
+    private void updateQos(
+            TransactionBuilder transaction,
+            InstanceIdentifier<OvsdbNodeAugmentation> iid, OvsdbNodeAugmentation ovsdbNode) {
+
+        List<QosEntries> qosEntries = ovsdbNode.getQosEntries();
+
+        if (!getOperationalState().getBridgeNode(iid).isPresent()) {
+            return;
+        }
+        OvsdbNodeAugmentation operNode = getOperationalState().getBridgeNode(iid).get().getAugmentation(OvsdbNodeAugmentation.class);
+        List<QosEntries> operQosEntries = operNode.getQosEntries();
+
+        if (qosEntries != null) {
+            for (QosEntries qosEntry : qosEntries) {
+                Qos qos = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Qos.class);
+
+                if (qosEntry.getQosType() != null) {
+                    qos.setType(SouthboundMapper.createQosType(qosEntry.getQosType()));
+                }
+
+                Uuid qosUuid = getQosEntryUuid(operQosEntries, qosEntry.getQosId());
+                UUID uuid = null;
+                if (qosUuid != null) {
+                    uuid = new UUID(qosUuid.getValue());
+                }
+
+                List<QueueList> queueList = qosEntry.getQueueList();
+                Map<Long, UUID>newQueueList = new HashMap<>();
+                if (queueList != null && !queueList.isEmpty()) {
+                    for (QueueList queue : queueList) {
+                        newQueueList.put(queue.getQueueNumber(), new UUID(queue.getQueueUuid().getValue()));
+                    }
+                }
+                qos.setQueues(newQueueList);
+
+                List<QosExternalIds> externalIds = qosEntry.getQosExternalIds();
+                Map<String, String> externalIdsMap = new HashMap<>();
+                if (externalIds != null) {
+                    for (QosExternalIds externalId : externalIds) {
+                        externalIdsMap.put(externalId.getQosExternalIdKey(), externalId.getQosExternalIdValue());
+                    }
+                }
+                externalIdsMap.put(SouthboundConstants.QOS_ID_EXTERNAL_ID_KEY, qosEntry.getQosId().getValue());
+                try {
+                    qos.setExternalIds(ImmutableMap.copyOf(externalIdsMap));
+                } catch (NullPointerException e) {
+                    LOG.warn("Incomplete Qos external IDs");
+                }
+
+                List<QosOtherConfig> otherConfigs = qosEntry.getQosOtherConfig();
+                if (otherConfigs != null) {
+                    Map<String, String> otherConfigsMap = new HashMap<>();
+                    for (QosOtherConfig otherConfig : otherConfigs) {
+                        otherConfigsMap.put(otherConfig.getOtherConfigKey(), otherConfig.getOtherConfigValue());
+                    }
+                    try {
+                        qos.setOtherConfig(ImmutableMap.copyOf(otherConfigsMap));
+                    } catch (NullPointerException e) {
+                        LOG.warn("Incomplete Qos other_config", e);
+                    }
+                }
+                if (uuid == null) {
+                    transaction.add(op.insert(qos)).build();
+                } else {
+                    Qos extraQos = TyperUtils.getTypedRowWrapper(
+                            transaction.getDatabaseSchema(), Qos.class, null);
+                    extraQos.getUuidColumn().setData(uuid);
+                    transaction.add(op.update(qos)
+                            .where(extraQos.getUuidColumn().getSchema().opEqual(uuid)).build());
+                }
+                transaction.build();
+            }
+        }
+    }
+
+    private Uuid getQosEntryUuid(List<QosEntries> operQosEntries, Uri qosId) {
+        if (operQosEntries != null && !operQosEntries.isEmpty()) {
+            for (QosEntries qosEntry : operQosEntries) {
+                if (qosEntry.getQosId().equals(qosId)) {
+                    return qosEntry.getQosUuid();
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QueueRemovedCommand.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QueueRemovedCommand.java
new file mode 100644 (file)
index 0000000..de083f9
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016 Intel  Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.southbound.ovsdb.transact;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.ovsdb.lib.notation.Mutator;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Queue;
+import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.Queues;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+
+public class QueueRemovedCommand extends AbstractTransactCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(QueueRemovedCommand.class);
+
+    public QueueRemovedCommand(BridgeOperationalState state,
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        super(state, changes);
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        Set<InstanceIdentifier<Queues>> removed =
+                TransactUtils.extractRemoved(getChanges(),Queues.class);
+
+        Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> originals
+            = TransactUtils.extractOriginal(getChanges(),OvsdbNodeAugmentation.class);
+
+        Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> updated
+        = TransactUtils.extractUpdated(getChanges(), OvsdbNodeAugmentation.class);
+
+        Iterator<InstanceIdentifier<OvsdbNodeAugmentation>> itr = originals.keySet().iterator();
+        while (itr.hasNext()) {
+            InstanceIdentifier<OvsdbNodeAugmentation> ovsdbNodeIid = itr.next();
+            OvsdbNodeAugmentation original = originals.get(ovsdbNodeIid);
+            OvsdbNodeAugmentation update = updated.get(ovsdbNodeIid);
+
+            if (original != null && update != null) {
+                List<Queues> origQueues = original.getQueues();
+                List<Queues> updatedQueues = update.getQueues();
+                if (origQueues != null && !origQueues.isEmpty()) {
+                    for (Queues origQueue : origQueues) {
+                        OvsdbNodeAugmentation operNode = getOperationalState().getBridgeNode(ovsdbNodeIid).get().getAugmentation(OvsdbNodeAugmentation.class);
+                        List<Queues> operQueues = operNode.getQueues();
+
+                        boolean found = false;
+                        if (updatedQueues != null && !updatedQueues.isEmpty()) {
+                            for (Queues updatedQueue : updatedQueues) {
+                                if (origQueue.getQueueId().equals(updatedQueue.getQueueId())) {
+                                    found = true;
+                                    break;
+                                }
+                            }
+                        }
+                        if (!found) {
+                            LOG.debug("Received request to delete Queue entry {}",origQueue.getQueueId());
+                            Uuid queueUuid = getQueueUuid(operQueues, origQueue.getQueueId());
+                            if (queueUuid != null) {
+                                Queue queue = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Queue.class, null);
+                                  transaction.add(op.delete(queue.getSchema())
+                                          .where(queue.getUuidColumn().getSchema().opEqual(new UUID(queueUuid.getValue())))
+                                          .build());
+                            } else {
+                                LOG.warn("Unable to delete Queue{} for node {} because it was not found in the operational store, "
+                                        + "and thus we cannot retrieve its UUID", ovsdbNodeIid, origQueue.getQueueId());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private Uuid getQueueUuid(List<Queues> operQueues, Uri queueId) {
+        if (operQueues != null && !operQueues.isEmpty()) {
+            for (Queues queueEntry : operQueues) {
+                if (queueEntry.getQueueId().equals(queueId)) {
+                    return queueEntry.getQueueUuid();
+                }
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QueueUpdateCommand.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QueueUpdateCommand.java
new file mode 100644 (file)
index 0000000..8cd6ab9
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2016 Intel Corporation and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.southbound.ovsdb.transact;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.ovsdb.lib.notation.Mutator;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.operations.Mutate;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Qos;
+import org.opendaylight.ovsdb.schema.openvswitch.Queue;
+import org.opendaylight.ovsdb.southbound.SouthboundConstants;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntries;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.Queues;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.queues.QueuesExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.queues.QueuesOtherConfig;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+public class QueueUpdateCommand extends AbstractTransactCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(QueueUpdateCommand.class);
+
+
+    public QueueUpdateCommand(BridgeOperationalState state, AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        super(state, changes);
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> created =
+                TransactUtils.extractCreated(getChanges(),OvsdbNodeAugmentation.class);
+        for (Entry<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> ovsdbNodeEntry:
+            created.entrySet()) {
+            updateQueue(transaction,  ovsdbNodeEntry.getKey(), ovsdbNodeEntry.getValue());
+        }
+        Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> updated =
+                TransactUtils.extractUpdated(getChanges(),OvsdbNodeAugmentation.class);
+        for (Entry<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> ovsdbNodeEntry:
+            updated.entrySet()) {
+            updateQueue(transaction,  ovsdbNodeEntry.getKey(), ovsdbNodeEntry.getValue());
+        }
+    }
+
+    private void updateQueue(
+            TransactionBuilder transaction,
+            InstanceIdentifier<OvsdbNodeAugmentation> iid, OvsdbNodeAugmentation ovsdbNode) {
+
+        List<Queues> queueList = ovsdbNode.getQueues();
+
+        if (!getOperationalState().getBridgeNode(iid).isPresent()) {
+            return;
+        }
+        OvsdbNodeAugmentation operNode = getOperationalState().getBridgeNode(iid).get().getAugmentation(OvsdbNodeAugmentation.class);
+        List<Queues> operQueues = operNode.getQueues();
+
+        if (queueList != null) {
+            for (Queues queueEntry : queueList) {
+                Queue queue = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Queue.class);
+
+                if (queueEntry.getDscp() != null) {
+                    try {
+                        Set<Long> dscpSet = new HashSet<>();
+                            if (dscpSet.add(new Long(queueEntry.getDscp().toString()))) {
+                            queue.setDscp(dscpSet);
+                        }
+                    } catch (NumberFormatException e) {
+                        LOG.warn("Invalid DSCP {} setting for Queue {}", queueEntry.getDscp(), queueEntry, e);
+                    }
+                }
+
+                Uuid queueUuid = getQueueEntryUuid(operQueues, queueEntry.getQueueId());
+                UUID uuid = null;
+                if (queueUuid != null) {
+                    uuid = new UUID(queueUuid.getValue());
+                }
+
+                List<QueuesExternalIds> externalIds = queueEntry.getQueuesExternalIds();
+                Map<String, String> externalIdsMap = new HashMap<>();
+                if (externalIds != null) {
+                    for (QueuesExternalIds externalId : externalIds) {
+                        externalIdsMap.put(externalId.getQueuesExternalIdKey(), externalId.getQueuesExternalIdValue());
+                    }
+                }
+                externalIdsMap.put(SouthboundConstants.QUEUE_ID_EXTERNAL_ID_KEY, queueEntry.getQueueId().getValue());
+                try {
+                    queue.setExternalIds(ImmutableMap.copyOf(externalIdsMap));
+                } catch (NullPointerException e) {
+                    LOG.warn("Incomplete Queue external IDs");
+                }
+
+                List<QueuesOtherConfig> otherConfigs = queueEntry.getQueuesOtherConfig();
+                if (otherConfigs != null) {
+                    Map<String, String> otherConfigsMap = new HashMap<>();
+                    for (QueuesOtherConfig otherConfig : otherConfigs) {
+                        otherConfigsMap.put(otherConfig.getQueueOtherConfigKey(), otherConfig.getQueueOtherConfigValue());
+                    }
+                    try {
+                        queue.setOtherConfig(ImmutableMap.copyOf(otherConfigsMap));
+                    } catch (NullPointerException e) {
+                        LOG.warn("Incomplete Queue other_config", e);
+                    }
+                }
+                if (uuid == null) {
+                    transaction.add(op.insert(queue)).build();
+                } else {
+                    transaction.add(op.update(queue)).build();
+                    Queue extraQueue = TyperUtils.getTypedRowWrapper(
+                            transaction.getDatabaseSchema(), Queue.class, null);
+                    extraQueue.getUuidColumn().setData(uuid);
+                    transaction.add(op.update(queue.getSchema())
+                            .where(extraQueue.getUuidColumn().getSchema().opEqual(uuid)).build());
+                }
+                transaction.build();
+            }
+        }
+    }
+
+    private Uuid getQueueEntryUuid(List<Queues> operQueues, Uri queueId) {
+        if (operQueues != null && !operQueues.isEmpty()) {
+            for (Queues queueEntry : operQueues) {
+                if (queueEntry.getQueueId().equals(queueId)) {
+                    return queueEntry.getQueueUuid();
+                }
+            }
+        }
+        return null;
+    }
+}
index 525ab09c08429b3569c538ad4cfa6511eaaaa9da..2023374db99b4eb270cbdd1052516f7185c8c6e1 100644 (file)
@@ -17,11 +17,13 @@ import java.util.Map.Entry;
 import java.util.Set;
 
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
 import org.opendaylight.ovsdb.schema.openvswitch.Port;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes.VlanMode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
@@ -119,8 +121,22 @@ public class TerminationPointUpdateCommand extends AbstractTransactCommand {
         updatePortVlanTrunk(terminationPoint, port);
         updatePortVlanMode(terminationPoint, port);
         updatePortExternalIds(terminationPoint, port);
+        updatePortQos(terminationPoint, port);
     }
 
+    private void updatePortQos(
+            final OvsdbTerminationPointAugmentation terminationPoint,
+            final Port port) {
+
+        Set<UUID> uuidSet = Sets.newHashSet();
+        Uuid qosUuid = terminationPoint.getQos();
+        if (qosUuid != null) {
+            uuidSet.add(new UUID(qosUuid.getValue()));
+        }
+        port.setQos(uuidSet);
+    }
+
+
     private void updateOfPort(
             final OvsdbTerminationPointAugmentation terminationPoint,
             final Interface ovsInterface) {
index 9bcddbfeaacef5565a79cdca26514e8cab597845..70e6f58693a1c22f168b69eec5847be7d647deec 100644 (file)
@@ -35,6 +35,10 @@ public class TransactCommandAggregator implements TransactCommand {
         commands.add(new TerminationPointCreateCommand(state,changes));
         commands.add(new TerminationPointDeleteCommand(state, changes));
         commands.add(new OvsdbNodeUpdateCommand(changes));
+        commands.add(new QosUpdateCommand(state, changes));
+        commands.add(new QosRemovedCommand(state, changes));
+        commands.add(new QueueUpdateCommand(state, changes));
+        commands.add(new QueueRemovedCommand(state, changes));
         commands.add(new TerminationPointUpdateCommand(state, changes));
     }
 
index c1fece74ca029e523a370b4cad3ab391305765f5..09564bfb7113e60aad68dfbaa05b06457167b78e 100644 (file)
@@ -26,6 +26,10 @@ public class OvsdbOperationalCommandAggregator implements TransactionCommand {
         commands.add(new OpenVSwitchUpdateCommand(key, updates, dbSchema));
         commands.add(new OvsdbManagersUpdateCommand(key, updates,  dbSchema));
         commands.add(new OvsdbManagersRemovedCommand(key, updates,  dbSchema));
+        commands.add(new OvsdbQosUpdateCommand(key, updates,  dbSchema));
+        commands.add(new OvsdbQosRemovedCommand(key, updates,  dbSchema));
+        commands.add(new OvsdbQueueUpdateCommand(key, updates,  dbSchema));
+        commands.add(new OvsdbQueueRemovedCommand(key, updates,  dbSchema));
         commands.add(new OvsdbBridgeUpdateCommand(key, updates,  dbSchema));
         commands.add(new OvsdbBridgeRemovedCommand(key, updates,  dbSchema));
         commands.add(new OvsdbControllerUpdateCommand(key, updates,  dbSchema));
index 0646f6be05007c11ec3a8085cc884b3cb5ef520d..597caa4eedea2e8ccdc7e00b570649729076e9bb 100644 (file)
@@ -126,7 +126,7 @@ public class OvsdbPortUpdateCommand extends AbstractTransactionCommand {
                     interfaceOldRows.remove(interfaceUUID);
                 }
                 tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
-                if (portOldRows.containsKey(portUpdate.getKey())) {
+                if (portOldRows.containsKey(portUpdate.getKey()) && !portQosCleared(portUpdate)) {
                     transaction.merge(LogicalDatastoreType.OPERATIONAL,
                             tpPath, tpBuilder.build());
                 } else {
@@ -236,6 +236,7 @@ public class OvsdbPortUpdateCommand extends AbstractTransactionCommand {
         updateVlan(port, ovsdbTerminationPointBuilder);
         updateVlanTrunks(port, ovsdbTerminationPointBuilder);
         updateVlanMode(port, ovsdbTerminationPointBuilder);
+        updateQos(port, ovsdbTerminationPointBuilder);
         updatePortExternalIds(port, ovsdbTerminationPointBuilder);
         updatePortOtherConfig(port, ovsdbTerminationPointBuilder);
     }
@@ -308,6 +309,19 @@ public class OvsdbPortUpdateCommand extends AbstractTransactionCommand {
         }
     }
 
+    private void updateQos(final Port port,
+            final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
+        if (port.getQosColumn() == null) {
+            return;
+        }
+        Collection<UUID> qosUuidCol = port.getQosColumn().getData();
+        if (!qosUuidCol.isEmpty()) {
+            Iterator<UUID> itr = qosUuidCol.iterator();
+            UUID qosUuid = itr.next();
+            ovsdbTerminationPointBuilder.setQos(new Uuid(qosUuid.toString()));
+        }
+    }
+
     private void updateOfPort(final Interface interf,
             final OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder) {
 
@@ -448,6 +462,23 @@ public class OvsdbPortUpdateCommand extends AbstractTransactionCommand {
         }
     }
 
+    private boolean portQosCleared(Entry<UUID, Port> portUpdate) {
+        if (portUpdate.getValue().getQosColumn() == null) {
+            return false;
+        }
+        Collection<UUID> newQos = portUpdate.getValue().getQosColumn().getData();
+        if (portOldRows.get(portUpdate.getKey()).getQosColumn() == null) {
+            return false;
+        }
+        Collection<UUID> oldQos = portOldRows.get(portUpdate.getKey()).getQosColumn().getData();
+
+        if (newQos.isEmpty() && !oldQos.isEmpty()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     private InstanceIdentifier<TerminationPoint> getInstanceIdentifier(InstanceIdentifier<Node> bridgeIid,Port port) {
         if (port.getExternalIdsColumn() != null
                 && port.getExternalIdsColumn().getData() != null
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQosRemovedCommand.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQosRemovedCommand.java
new file mode 100644 (file)
index 0000000..53f9687
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016 Intel Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.southbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Qos;
+import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
+import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.ovsdb.southbound.SouthboundUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntries;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntriesKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class OvsdbQosRemovedCommand extends AbstractTransactionCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(OvsdbQueueUpdateCommand.class);
+
+    private Map<UUID, Qos> removedQosRows;
+    private Map<UUID, OpenVSwitch> updatedOpenVSwitchRows;
+
+    public OvsdbQosRemovedCommand(OvsdbConnectionInstance key,
+            TableUpdates updates, DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedOpenVSwitchRows = TyperUtils.extractRowsUpdated(OpenVSwitch.class, getUpdates(), getDbSchema());
+        removedQosRows = TyperUtils.extractRowsRemoved(Qos.class, getUpdates(), getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        final InstanceIdentifier<Node> nodeIId = getOvsdbConnectionInstance().getInstanceIdentifier();
+        final Optional<Node> ovsdbNode = SouthboundUtil.readNode(transaction, nodeIId);
+        if (ovsdbNode.isPresent()) {
+            for (@SuppressWarnings("unused") OpenVSwitch openVSwitch : updatedOpenVSwitchRows.values()) {
+                List<InstanceIdentifier<QosEntries>> result = new ArrayList<>();
+                InstanceIdentifier<Node> ovsdbNodeIid =
+                        SouthboundMapper.createInstanceIdentifier(getOvsdbConnectionInstance().getNodeId());
+                if (removedQosRows != null && !removedQosRows.isEmpty()) {
+                    for (UUID qosUuid : removedQosRows.keySet()) {
+                        QosEntriesKey qosKey = getQosEntriesKey(ovsdbNode.get(), qosUuid);
+                        if (qosKey != null) {
+                            InstanceIdentifier<QosEntries> iid = ovsdbNodeIid
+                                .augmentation(OvsdbNodeAugmentation.class)
+                                .child(QosEntries.class, qosKey);
+                            result.add(iid);
+                        }
+                    }
+                }
+                deleteQos(transaction, result);
+            }
+        }
+    }
+
+    private QosEntriesKey getQosEntriesKey(Node node, UUID qosUuid) {
+        List<QosEntries> qosList = node.getAugmentation(OvsdbNodeAugmentation.class).getQosEntries();
+        if (qosList == null || qosList.isEmpty()) {
+            LOG.debug("Deleting Qos {}, Ovsdb Node {} does not have a Qos list.", qosUuid.toString(), node);
+            return null;
+        }
+        Iterator<QosEntries> itr = qosList.iterator();
+        Uuid qUuid = new Uuid(qosUuid.toString());
+        while (itr.hasNext()) {
+            QosEntries qos = itr.next();
+            if (qos.getQosUuid().equals(qUuid)) {
+                return qos.getKey();
+            }
+        }
+        LOG.debug("Deleted Queue {} not found in Ovsdb Node {}", qosUuid.toString(), node);
+        return null;
+    }
+
+    private void deleteQos(ReadWriteTransaction transaction,
+            List<InstanceIdentifier<QosEntries>> qosEntryIids) {
+        for (InstanceIdentifier<QosEntries> qosEntryIid: qosEntryIids) {
+            transaction.delete(LogicalDatastoreType.OPERATIONAL, qosEntryIid);
+        }
+    }
+}
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQosUpdateCommand.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQosUpdateCommand.java
new file mode 100644 (file)
index 0000000..231c722
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2016 Intel Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.southbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Qos;
+import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+import org.opendaylight.ovsdb.southbound.SouthboundConstants;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.ovsdb.southbound.SouthboundUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntries;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntriesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosExternalIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosExternalIdsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfigBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfigKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QueueList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QueueListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QueueListKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class OvsdbQosUpdateCommand extends AbstractTransactionCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(OvsdbQosUpdateCommand.class);
+
+    private Map<UUID, Qos> updatedQosRows;
+    private Map<UUID, Qos> oldQosRows;
+
+    public OvsdbQosUpdateCommand(OvsdbConnectionInstance key,
+            TableUpdates updates, DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedQosRows = TyperUtils.extractRowsUpdated(Qos.class,getUpdates(), getDbSchema());
+        oldQosRows = TyperUtils.extractRowsOld(Qos.class, getUpdates(), getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        if (updatedQosRows != null && !updatedQosRows.isEmpty()) {
+            updateQos(transaction, updatedQosRows);
+        }
+    }
+
+    /**
+     * Update the QosEntries values after finding the related {@link OpenVSwitch} list.
+     * <p>
+     * Qos and OpenVSwitch are independent tables in the Open_vSwitch schema
+     * but the OVSDB yang model includes the Qos fields in the
+     * OvsdbNode data. In some cases the OVSDB will send OpenVSwitch and Qos
+     * updates together and in other cases independently. This method here
+     * assumes the latter.
+     * </p>
+     *
+     * @param transaction the {@link ReadWriteTransaction}
+     * @param updatedQosRows updated {@link Qos} rows
+
+     */
+    private void updateQos(ReadWriteTransaction transaction,
+                                  Map<UUID, Qos> updatedQosRows) {
+
+        final InstanceIdentifier<Node> nodeIId = getOvsdbConnectionInstance().getInstanceIdentifier();
+        final Optional<Node> ovsdbNode = SouthboundUtil.readNode(transaction, nodeIId);
+        if (ovsdbNode.isPresent()) {
+            for (Entry<UUID, Qos> entry : updatedQosRows.entrySet()) {
+                Qos qos = entry.getValue();
+                Qos oldQos = oldQosRows.get(entry.getKey());
+                QosEntriesBuilder qosEntryBuilder = new QosEntriesBuilder();
+                qosEntryBuilder.setQosId(new Uri(getQosId(qos)));
+                qosEntryBuilder.setQosUuid(new Uuid(entry.getKey().toString()));
+                qosEntryBuilder.setQosType(
+                        SouthboundMapper.createQosType(qos.getTypeColumn().getData().toString()));
+                setOtherConfig(transaction, qosEntryBuilder, oldQos, qos, nodeIId);
+                setExternalIds(transaction, qosEntryBuilder, oldQos, qos, nodeIId);
+                setQueueList(transaction, qosEntryBuilder, oldQos, qos, nodeIId);
+
+                QosEntries qosEntry = qosEntryBuilder.build();
+                LOG.debug("Update Ovsdb Node {} with qos entries {}",ovsdbNode.get(), qosEntry);
+                InstanceIdentifier<QosEntries> iid = nodeIId
+                        .augmentation(OvsdbNodeAugmentation.class)
+                        .child(QosEntries.class, qosEntry.getKey());
+                transaction.merge(LogicalDatastoreType.OPERATIONAL,
+                        iid, qosEntry);
+            }
+        }
+    }
+
+    private String getQosId(Qos qos) {
+        if (qos.getExternalIdsColumn() != null
+                && qos.getExternalIdsColumn().getData() != null
+                && qos.getExternalIdsColumn().getData().containsKey(SouthboundConstants.QOS_ID_EXTERNAL_ID_KEY)) {
+            return qos.getExternalIdsColumn().getData().get(SouthboundConstants.QOS_ID_EXTERNAL_ID_KEY);
+        } else {
+            return SouthboundConstants.QOS_URI_PREFIX + "://" + qos.getUuid().toString();
+        }
+    }
+
+    private void setOtherConfig(ReadWriteTransaction transaction,
+            QosEntriesBuilder qosEntryBuilder, Qos oldQos, Qos qos,
+            InstanceIdentifier<Node> nodeIId) {
+        Map<String, String> oldOtherConfigs = null;
+        Map<String, String> otherConfigs = null;
+
+        if (qos.getOtherConfigColumn() != null) {
+            otherConfigs = qos.getOtherConfigColumn().getData();
+        }
+        if (oldQos != null && oldQos.getOtherConfigColumn() != null) {
+            oldOtherConfigs = oldQos.getOtherConfigColumn().getData();
+        }
+        if ((oldOtherConfigs != null) && !oldOtherConfigs.isEmpty()) {
+            removeOldConfigs(transaction, qosEntryBuilder, oldOtherConfigs, qos, nodeIId);
+        }
+        if (otherConfigs != null && !otherConfigs.isEmpty()) {
+            setNewOtherConfigs(qosEntryBuilder, otherConfigs);
+        }
+    }
+
+    private void removeOldConfigs(ReadWriteTransaction transaction,
+            QosEntriesBuilder qosEntryBuilder, Map<String, String> oldOtherConfigs,
+            Qos qos, InstanceIdentifier<Node> nodeIId) {
+        InstanceIdentifier<QosEntries> qosIId = nodeIId
+                .augmentation(OvsdbNodeAugmentation.class)
+                .child(QosEntries.class, qosEntryBuilder.build().getKey());
+        Set<String> otherConfigKeys = oldOtherConfigs.keySet();
+        for (String otherConfigKey : otherConfigKeys) {
+            KeyedInstanceIdentifier<QosOtherConfig, QosOtherConfigKey> otherIId =
+                    qosIId
+                    .child(QosOtherConfig.class, new QosOtherConfigKey(otherConfigKey));
+            transaction.delete(LogicalDatastoreType.OPERATIONAL, otherIId);
+        }
+    }
+
+    private void setNewOtherConfigs(QosEntriesBuilder qosEntryBuilder,
+            Map<String, String> otherConfig) {
+        Set<String> otherConfigKeys = otherConfig.keySet();
+        List<QosOtherConfig> otherConfigList = new ArrayList<>();
+        String otherConfigValue;
+        for (String otherConfigKey : otherConfigKeys) {
+            otherConfigValue = otherConfig.get(otherConfigKey);
+            if (otherConfigKey != null && otherConfigValue != null) {
+                otherConfigList.add(new QosOtherConfigBuilder().setOtherConfigKey(otherConfigKey)
+                        .setOtherConfigValue(otherConfigValue).build());
+            }
+        }
+        qosEntryBuilder.setQosOtherConfig(otherConfigList);
+    }
+
+    private void setExternalIds(ReadWriteTransaction transaction,
+            QosEntriesBuilder qosEntryBuilder, Qos oldQos, Qos qos,
+            InstanceIdentifier<Node> nodeIId) {
+        Map<String, String> oldExternalIds = null;
+        Map<String, String> externalIds = null;
+
+        if (qos.getExternalIdsColumn() != null) {
+            externalIds = qos.getExternalIdsColumn().getData();
+        }
+        if (oldQos != null && oldQos.getExternalIdsColumn() != null) {
+            oldExternalIds = oldQos.getExternalIdsColumn().getData();
+        }
+        if ((oldExternalIds != null) && !oldExternalIds.isEmpty()) {
+            removeOldExternalIds(transaction, qosEntryBuilder, oldExternalIds, qos, nodeIId);
+        }
+        if (externalIds != null && !externalIds.isEmpty()) {
+            setNewExternalIds(qosEntryBuilder, externalIds);
+        }
+    }
+
+    private void removeOldExternalIds(ReadWriteTransaction transaction,
+            QosEntriesBuilder qosEntryBuilder, Map<String, String> oldExternalIds,
+            Qos qos, InstanceIdentifier<Node> nodeIId) {
+        InstanceIdentifier<QosEntries> qosIId = nodeIId
+                .augmentation(OvsdbNodeAugmentation.class)
+                .child(QosEntries.class, qosEntryBuilder.build().getKey());
+        Set<String> externalIdsKeys = oldExternalIds.keySet();
+        for (String extIdKey : externalIdsKeys) {
+            KeyedInstanceIdentifier<QosExternalIds, QosExternalIdsKey> externalIId =
+                    qosIId
+                    .child(QosExternalIds.class, new QosExternalIdsKey(extIdKey));
+            transaction.delete(LogicalDatastoreType.OPERATIONAL, externalIId);
+        }
+    }
+
+    private void setNewExternalIds(QosEntriesBuilder qosEntryBuilder,
+            Map<String, String> externalIds) {
+        Set<String> externalIdsKeys = externalIds.keySet();
+        List<QosExternalIds> externalIdsList = new ArrayList<>();
+        String extIdValue;
+        for (String extIdKey : externalIdsKeys) {
+            extIdValue = externalIds.get(extIdKey);
+            if (extIdKey != null && extIdValue != null) {
+                externalIdsList.add(new QosExternalIdsBuilder().setQosExternalIdKey(extIdKey)
+                        .setQosExternalIdValue(extIdValue).build());
+            }
+        }
+        qosEntryBuilder.setQosExternalIds(externalIdsList);
+    }
+
+    private void setQueueList(ReadWriteTransaction transaction,
+            QosEntriesBuilder qosEntryBuilder, Qos oldQos, Qos qos,
+            InstanceIdentifier<Node> nodeIId) {
+        Map<Long,UUID> oldQueueList = null;
+        Map<Long,UUID> queueList = null;
+
+        if (qos.getQueuesColumn() != null) {
+            queueList = qos.getQueuesColumn().getData();
+        }
+        if (oldQos != null && oldQos.getQueuesColumn() != null) {
+            oldQueueList = oldQos.getQueuesColumn().getData();
+        }
+        if ((oldQueueList != null) && !oldQueueList.isEmpty()) {
+            removeOldQueues(transaction, qosEntryBuilder, oldQueueList, qos, nodeIId);
+        }
+        if (queueList != null && !queueList.isEmpty()) {
+            setNewQueues(qosEntryBuilder, queueList);
+        }
+    }
+
+    private void removeOldQueues(ReadWriteTransaction transaction,
+            QosEntriesBuilder qosEntryBuilder, Map<Long, UUID> oldQueueList,
+            Qos qos, InstanceIdentifier<Node> nodeIId) {
+        InstanceIdentifier<QosEntries> qosIId = nodeIId
+                .augmentation(OvsdbNodeAugmentation.class)
+                .child(QosEntries.class, qosEntryBuilder.build().getKey());
+        Collection<Long> queueListKeys = oldQueueList.keySet();
+        for (Long queueListKey : queueListKeys) {
+            KeyedInstanceIdentifier<QueueList, QueueListKey> otherIId =
+                    qosIId
+                    .child(QueueList.class, new QueueListKey(new Long(queueListKey.toString())));
+            transaction.delete(LogicalDatastoreType.OPERATIONAL, otherIId);
+        }
+    }
+
+    private void setNewQueues(QosEntriesBuilder qosEntryBuilder,
+            Map<Long, UUID> queueList) {
+        Set<Entry<Long, UUID>> queueEntries = queueList.entrySet();
+        List<QueueList> newQueueList = new ArrayList<>();
+        for (Entry<Long, UUID> queueEntry : queueEntries) {
+            newQueueList.add(
+                    new QueueListBuilder().setQueueNumber(queueEntry.getKey())
+                    .setQueueUuid(new Uuid(queueEntry.getValue().toString())).build());
+        }
+        qosEntryBuilder.setQueueList(newQueueList);
+    }
+}
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQueueRemovedCommand.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQueueRemovedCommand.java
new file mode 100644 (file)
index 0000000..3844934
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016 Intel Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.southbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
+import org.opendaylight.ovsdb.schema.openvswitch.Queue;
+import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.ovsdb.southbound.SouthboundUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.Queues;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QueuesKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class OvsdbQueueRemovedCommand extends AbstractTransactionCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(OvsdbQueueUpdateCommand.class);
+
+    private Map<UUID, Queue> removedQueueRows;
+    private Map<UUID, OpenVSwitch> updatedOpenVSwitchRows;
+
+    public OvsdbQueueRemovedCommand(OvsdbConnectionInstance key,
+            TableUpdates updates, DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedOpenVSwitchRows = TyperUtils.extractRowsUpdated(OpenVSwitch.class, getUpdates(), getDbSchema());
+        removedQueueRows = TyperUtils.extractRowsRemoved(Queue.class, getUpdates(), getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        final InstanceIdentifier<Node> nodeIId = getOvsdbConnectionInstance().getInstanceIdentifier();
+        final Optional<Node> ovsdbNode = SouthboundUtil.readNode(transaction, nodeIId);
+        if (ovsdbNode.isPresent()) {
+            for (@SuppressWarnings("unused") OpenVSwitch openVSwitch : updatedOpenVSwitchRows.values()) {
+                List<InstanceIdentifier<Queues>> result = new ArrayList<>();
+                InstanceIdentifier<Node> ovsdbNodeIid =
+                        SouthboundMapper.createInstanceIdentifier(getOvsdbConnectionInstance().getNodeId());
+                if (removedQueueRows != null && !removedQueueRows.isEmpty()) {
+                    for (UUID queueUuid : removedQueueRows.keySet()) {
+                        QueuesKey queueKey = getQueueKey(ovsdbNode.get(), queueUuid);
+                        if (queueKey != null) {
+                            InstanceIdentifier<Queues> iid = ovsdbNodeIid
+                                .augmentation(OvsdbNodeAugmentation.class)
+                                .child(Queues.class, queueKey);
+                            result.add(iid);
+                        }
+                    }
+                }
+                deleteQueue(transaction, result);
+            }
+        }
+    }
+
+    private QueuesKey getQueueKey(Node node, UUID queueUuid) {
+        List<Queues> queueList = node.getAugmentation(OvsdbNodeAugmentation.class).getQueues();
+        if (queueList == null || queueList.isEmpty()) {
+            LOG.debug("Deleting Queue {}, Ovsdb Node {} does not have a Queue list.", queueUuid.toString(), node);
+            return null;
+        }
+        Iterator<Queues> itr = queueList.iterator();
+        Uuid qUuid = new Uuid(queueUuid.toString());
+        while (itr.hasNext()) {
+            Queues queue = itr.next();
+            if (queue.getQueueUuid().equals(qUuid)) {
+                return queue.getKey();
+            }
+        }
+        LOG.debug("Deleted Queue {} not found in Ovsdb Node {}", queueUuid.toString(), node);
+        return null;
+    }
+
+    private void deleteQueue(ReadWriteTransaction transaction,
+            List<InstanceIdentifier<Queues>> queueIids) {
+        for (InstanceIdentifier<Queues> queueIid: queueIids) {
+            transaction.delete(LogicalDatastoreType.OPERATIONAL, queueIid);
+        }
+    }
+}
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQueueUpdateCommand.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbQueueUpdateCommand.java
new file mode 100644 (file)
index 0000000..f45c251
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2016 Intel Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.southbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Queue;
+import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+import org.opendaylight.ovsdb.southbound.SouthboundConstants;
+import org.opendaylight.ovsdb.southbound.SouthboundUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.Queues;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QueuesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.queues.QueuesExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.queues.QueuesExternalIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.queues.QueuesExternalIdsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.queues.QueuesOtherConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.queues.QueuesOtherConfigBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.queues.QueuesOtherConfigKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class OvsdbQueueUpdateCommand extends AbstractTransactionCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(OvsdbQueueUpdateCommand.class);
+
+    private Map<UUID, Queue> updatedQueueRows;
+    private Map<UUID, Queue> oldQueueRows;
+
+    public OvsdbQueueUpdateCommand(OvsdbConnectionInstance key,
+            TableUpdates updates, DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedQueueRows = TyperUtils.extractRowsUpdated(Queue.class,getUpdates(), getDbSchema());
+        oldQueueRows = TyperUtils.extractRowsOld(Queue.class, getUpdates(), getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        if (updatedQueueRows != null && !updatedQueueRows.isEmpty()) {
+            updateQueue(transaction);
+        }
+    }
+
+    /**
+     * Update the Queues values after finding the related {@OpenVSwitch} list.
+     * <p>
+     * Queue and OpenVSwitch are independent tables in the Open_vSwitch schema
+     * but the OVSDB yang model includes the Queue fields in the
+     * OvsdbNode data. In some cases the OVSDB will send OpenVSwitch and Queue
+     * updates together and in other cases independently. This method here
+     * assumes the latter.
+     * </p>
+     *
+     * @param transaction the {@link ReadWriteTransaction}
+     * @param updatedQueueRows updated {@link Queue} rows
+
+     */
+    private void updateQueue(ReadWriteTransaction transaction) {
+
+        final InstanceIdentifier<Node> nodeIId = getOvsdbConnectionInstance().getInstanceIdentifier();
+        final Optional<Node> ovsdbNode = SouthboundUtil.readNode(transaction, nodeIId);
+        if (ovsdbNode.isPresent()) {
+            for (Entry<UUID, Queue> entry : updatedQueueRows.entrySet()) {
+                Queue queue = entry.getValue();
+                Queue oldQueue = oldQueueRows.get(entry.getKey());
+                QueuesBuilder queuesBuilder = new QueuesBuilder();
+                queuesBuilder.setQueueId(new Uri(getQueueId(queue)));
+                queuesBuilder.setQueueUuid(new Uuid(entry.getKey().toString()));
+                Collection<Long> dscp = queue.getDscpColumn().getData();
+                if (!dscp.isEmpty()) {
+                    try {
+                        queuesBuilder.setDscp(new Short(dscp.iterator().next().toString()));
+                    } catch (NumberFormatException e) {
+                        queuesBuilder.setDscp(new Short("0"));
+                    }
+                }
+                setOtherConfig(transaction, queuesBuilder, oldQueue, queue, nodeIId);
+                setExternalIds(transaction, queuesBuilder, oldQueue, queue, nodeIId);
+
+                Queues queues = queuesBuilder.build();
+                LOG.debug("Update Ovsdb Node {} with queue entries {}",ovsdbNode.get(), queues);
+                InstanceIdentifier<Queues> iid = nodeIId
+                        .augmentation(OvsdbNodeAugmentation.class)
+                        .child(Queues.class, queues.getKey());
+                transaction.merge(LogicalDatastoreType.OPERATIONAL,
+                        iid, queues);
+            }
+        }
+    }
+
+    private String getQueueId(Queue queue) {
+        if (queue.getExternalIdsColumn() != null
+                && queue.getExternalIdsColumn().getData() != null
+                && queue.getExternalIdsColumn().getData().containsKey(SouthboundConstants.QUEUE_ID_EXTERNAL_ID_KEY)) {
+            return queue.getExternalIdsColumn().getData().get(SouthboundConstants.QUEUE_ID_EXTERNAL_ID_KEY);
+        } else {
+            return SouthboundConstants.QUEUE_URI_PREFIX + "://" + queue.getUuid().toString();
+        }
+    }
+
+    private void setOtherConfig(ReadWriteTransaction transaction,
+            QueuesBuilder queuesBuilder, Queue oldQueue, Queue queue,
+            InstanceIdentifier<Node> nodeIId) {
+        Map<String, String> oldOtherConfigs = null;
+        Map<String, String> otherConfigs = null;
+
+        if (queue.getOtherConfigColumn() != null) {
+            otherConfigs = queue.getOtherConfigColumn().getData();
+        }
+        if (oldQueue != null && oldQueue.getOtherConfigColumn() != null) {
+            oldOtherConfigs = oldQueue.getOtherConfigColumn().getData();
+        }
+        if ((oldOtherConfigs != null) && !oldOtherConfigs.isEmpty()) {
+            removeOldConfigs(transaction, queuesBuilder, oldOtherConfigs, queue, nodeIId);
+        }
+        if (otherConfigs != null && !otherConfigs.isEmpty()) {
+            setNewOtherConfigs(queuesBuilder, otherConfigs);
+        }
+    }
+
+    private void removeOldConfigs(ReadWriteTransaction transaction,
+            QueuesBuilder queuesBuilder, Map<String, String> oldOtherConfigs,
+            Queue queue, InstanceIdentifier<Node> nodeIId) {
+        InstanceIdentifier<Queues> queueIId = nodeIId
+                .augmentation(OvsdbNodeAugmentation.class)
+                .child(Queues.class, queuesBuilder.build().getKey());
+        Set<String> otherConfigKeys = oldOtherConfigs.keySet();
+        for (String otherConfigKey : otherConfigKeys) {
+            KeyedInstanceIdentifier<QueuesOtherConfig, QueuesOtherConfigKey> otherIId =
+                    queueIId
+                    .child(QueuesOtherConfig.class, new QueuesOtherConfigKey(otherConfigKey));
+            transaction.delete(LogicalDatastoreType.OPERATIONAL, otherIId);
+        }
+    }
+
+    private void setNewOtherConfigs(QueuesBuilder queuesBuilder,
+            Map<String, String> otherConfig) {
+        Set<String> otherConfigKeys = otherConfig.keySet();
+        List<QueuesOtherConfig> otherConfigList = new ArrayList<>();
+        String otherConfigValue;
+        for (String otherConfigKey : otherConfigKeys) {
+            otherConfigValue = otherConfig.get(otherConfigKey);
+            if (otherConfigKey != null && otherConfigValue != null) {
+                otherConfigList.add(new QueuesOtherConfigBuilder().setQueueOtherConfigKey(otherConfigKey)
+                        .setQueueOtherConfigValue(otherConfigValue).build());
+            }
+        }
+        queuesBuilder.setQueuesOtherConfig(otherConfigList);
+    }
+
+    private void setExternalIds(ReadWriteTransaction transaction,
+            QueuesBuilder queuesBuilder, Queue oldQueue, Queue queue,
+            InstanceIdentifier<Node> nodeIId) {
+        Map<String, String> oldExternalIds = null;
+        Map<String, String> externalIds = null;
+
+        if (queue.getExternalIdsColumn() != null) {
+            externalIds = queue.getExternalIdsColumn().getData();
+        }
+        if (oldQueue != null && oldQueue.getExternalIdsColumn() != null) {
+            oldExternalIds = oldQueue.getExternalIdsColumn().getData();
+        }
+        if ((oldExternalIds != null) && !oldExternalIds.isEmpty()) {
+            removeOldExternalIds(transaction, queuesBuilder, oldExternalIds, queue, nodeIId);
+        }
+        if (externalIds != null && !externalIds.isEmpty()) {
+            setNewExternalIds(queuesBuilder, externalIds);
+        }
+    }
+
+    private void removeOldExternalIds(ReadWriteTransaction transaction,
+            QueuesBuilder queuesBuilder, Map<String, String> oldExternalIds,
+            Queue queue, InstanceIdentifier<Node> nodeIId) {
+        InstanceIdentifier<Queues> queueIId = nodeIId
+                .augmentation(OvsdbNodeAugmentation.class)
+                .child(Queues.class, queuesBuilder.build().getKey());
+        Set<String> externalIdsKeys = oldExternalIds.keySet();
+        for (String extIdKey : externalIdsKeys) {
+            KeyedInstanceIdentifier<QueuesExternalIds, QueuesExternalIdsKey> externalIId =
+                    queueIId
+                    .child(QueuesExternalIds.class, new QueuesExternalIdsKey(extIdKey));
+            transaction.delete(LogicalDatastoreType.OPERATIONAL, externalIId);
+        }
+    }
+
+    private void setNewExternalIds(QueuesBuilder queuesBuilder,
+            Map<String, String> externalIds) {
+        Set<String> externalIdsKeys = externalIds.keySet();
+        List<QueuesExternalIds> externalIdsList = new ArrayList<>();
+        String externalIdValue;
+        for (String extIdKey : externalIdsKeys) {
+            externalIdValue = externalIds.get(extIdKey);
+            if (extIdKey != null && externalIdValue != null) {
+                externalIdsList.add(new QueuesExternalIdsBuilder().setQueuesExternalIdKey(extIdKey)
+                        .setQueuesExternalIdValue(externalIdValue).build());
+            }
+        }
+        queuesBuilder.setQueuesExternalIds(externalIdsList);
+    }
+
+}
index d1870fdf49b260a65ea3f0dd08009bc9c37d3bc3..918b33c7ec1a74629c691d024a3735ee23639317 100644 (file)
@@ -35,7 +35,7 @@ import org.powermock.reflect.Whitebox;
 @PrepareForTest({})
 @RunWith(PowerMockRunner.class)
 public class TransactCommandAggregatorTest {
-    private static final int NUMBER_OF_COMMANDS = 11;
+    private static final int NUMBER_OF_COMMANDS = 15;
     private List<TransactCommand> commands = new ArrayList<>();
     private TransactCommandAggregator transactCommandAggregator;
     @Mock private AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes;
@@ -56,6 +56,10 @@ public class TransactCommandAggregatorTest {
         commands.add(mock(TerminationPointCreateCommand.class));
         commands.add(mock(TerminationPointDeleteCommand.class));
         commands.add(mock(OvsdbNodeUpdateCommand.class));
+        commands.add(mock(QosUpdateCommand.class));
+        commands.add(mock(QosRemovedCommand.class));
+        commands.add(mock(QueueUpdateCommand.class));
+        commands.add(mock(QueueRemovedCommand.class));
         commands.add(mock(TerminationPointUpdateCommand.class));
         MemberModifier.field(TransactCommandAggregator.class, "commands").set(transactCommandAggregator, commands);
     }
index e2955720a0d2ad5e07ee5e831ec56396b2fd242b..c3d3fd0471d3e3e1af5a9f02e6b75fe6bcf2a637 100644 (file)
@@ -31,7 +31,7 @@ import org.powermock.reflect.Whitebox;
 @PrepareForTest({})
 @RunWith(PowerMockRunner.class)
 public class OvsdbOperationalCommandAggregatorTest {
-    private static final int NUMBER_OF_COMMANDS = 9;
+    private static final int NUMBER_OF_COMMANDS = 13;
     private List<TransactionCommand> commands = new ArrayList<>();
     private OvsdbOperationalCommandAggregator ovsdbOperationalCommandAggregator;
 
@@ -43,6 +43,10 @@ public class OvsdbOperationalCommandAggregatorTest {
         commands.add(mock(OpenVSwitchUpdateCommand.class));
         commands.add(mock(OvsdbManagersUpdateCommand.class));
         commands.add(mock(OvsdbManagersRemovedCommand.class));
+        commands.add(mock(OvsdbQosUpdateCommand.class));
+        commands.add(mock(OvsdbQosRemovedCommand.class));
+        commands.add(mock(OvsdbQueueUpdateCommand.class));
+        commands.add(mock(OvsdbQueueRemovedCommand.class));
         commands.add(mock(OvsdbBridgeUpdateCommand.class));
         commands.add(mock(OvsdbBridgeRemovedCommand.class));
         commands.add(mock(OvsdbControllerUpdateCommand.class));