Merge "Added support to update flows for induvidual security rule add/remove , after...
authorSam Hague <shague@redhat.com>
Mon, 16 Nov 2015 17:46:17 +0000 (17:46 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 16 Nov 2015 17:46:18 +0000 (17:46 +0000)
120 files changed:
features/ovsdb/pom.xml
features/ovsdb/src/main/features/features.xml
hwvtepsouthbound/hwvtepsouthbound-api/src/main/yang/hwvtep.yang
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionInstance.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDataChangeListener.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundMapper.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/AbstractTransactCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/HwvtepOperationalState.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchRemoveCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalLocatorRemoveCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalLocatorUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalPortRemoveCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalPortUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommandAggregator.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactUtils.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/AbstractTransactionCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/GlobalUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepGlobalRemoveCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepManagerUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepOperationalCommandAggregator.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepTunnelUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/LogicalSwitchUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/McastMacsLocalUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/McastMacsRemoteUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalLocatorSetUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalLocatorUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalPortUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalSwitchRemoveCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalSwitchUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/UcastMacsLocalUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/UcastMacsRemoteUpdateCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-karaf/pom.xml
library/impl/src/main/java/org/opendaylight/ovsdb/lib/error/SchemaVersionMismatchException.java
library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TyperUtils.java
library/it/src/test/java/org/opendaylight/ovsdb/integrationtest/schema/openvswitch/OpenVSwitchIT.java
openstack/net-virt-it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/it/NetvirtIT.java
openstack/net-virt-providers/pom.xml
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/PipelineOrchestrator.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/PipelineOrchestratorImpl.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/Service.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/EgressAclService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/IngressAclService.java
openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/EgressAclServiceTest.java
openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/IngressAclServiceTest.java
openstack/net-virt-sfc/api/pom.xml
openstack/net-virt-sfc/api/src/main/yang/netvirt-acl.yang
openstack/net-virt-sfc/api/src/main/yang/netvirt-classifier.yang
openstack/net-virt-sfc/features/production/pom.xml
openstack/net-virt-sfc/features/production/src/main/features/features.xml
openstack/net-virt-sfc/impl/pom.xml
openstack/net-virt-sfc/impl/src/main/config/default-config.xml
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/AbstractDataTreeListener.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/INetvirtSfcOF13Provider.java [moved from openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/INetvirtSfcOF13Provider.java with 72% similarity]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/ISfcClassifierService.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcAclListener.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcClassifierListener.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcProvider.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NshUtils.java [moved from openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/NshUtils.java with 98% similarity]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/SfcUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/standalone/openflow13/NetvirtSfcStandaloneOF13Provider.java [moved from openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/NetvirtSfcOF13Provider.java with 54% similarity]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/standalone/openflow13/SfcClassifier.java [moved from openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/SfcClassifier.java with 72% similarity]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/standalone/openflow13/services/SfcClassifierService.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/NetvirtSfcWorkaroundOF13Provider.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/SfcClassifierService.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/rev141210/NetvirtSfcModule.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/rev141210/NetvirtSfcModuleFactory.java
openstack/net-virt-sfc/impl/src/main/yang/netvirt-sfc.yang
openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/rev141210/NetvirtSfcModuleTest.java
openstack/net-virt-sfc/it/pom.xml
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcIT.java
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/AbstractUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/AclUtils.java
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ClassifierUtils.java
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionChainUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionForwarderUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionPathUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionUtils.java [new file with mode: 0644]
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/SfcUtils.java
openstack/net-virt/pom.xml
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/ConfigActivator.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/MdsalHelper.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/Southbound.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/MdsalUtils.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/NeutronL3Adapter.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/NodeCacheManagerImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SouthboundImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronPortInterface.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronIAwareUtil.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronPortChangeListener.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/impl/MdsalUtilsTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/impl/NeutronL3AdapterTest.java
resources/commons/Ovsdb-HwvtepSouthbound-Collection.json.postman_collection [new file with mode: 0755]
resources/commons/README
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/OvsdbConnectionInstance.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/OvsdbConnectionManager.java
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/SouthboundProvider.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/ProtocolUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OpenVSwitchUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbBridgeUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbNodeRemoveCommand.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/DataChangesManagedByOvsdbNodeEventTest.java [new file with mode: 0644]
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/OpenVSwitchBridgeAddCommandTest.java [new file with mode: 0644]
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/OvsdbNodeUpdateCommandTest.java [new file with mode: 0644]
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/ProtocolUpdateCommandTest.java [new file with mode: 0644]
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TerminationPointDeleteCommandTest.java [new file with mode: 0644]
southbound/southbound-it/src/test/java/org/opendaylight/ovsdb/southbound/it/SouthboundIT.java
utils/mdsal-openflow/pom.xml
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/ActionUtils.java
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/FlowUtils.java [new file with mode: 0644]
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/InstructionUtils.java
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/MatchUtils.java
utils/mdsal-utils/pom.xml
utils/mdsal-utils/src/main/java/org/opendaylight/ovsdb/utils/mdsal/utils/NeutronModelsDataStoreHelper.java [new file with mode: 0644]
utils/servicehelper/pom.xml
utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java

index 94cf2abe84776cdcc62da6497ad6fa5bcd7dbe87..4d7745686318a066b5bff51f346db2fd0f337059 100644 (file)
@@ -285,6 +285,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>utils.servicehelper</artifactId>
       <version>${ovsdb.utils.servicehelper.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
index 1abdab4e67534b0040e3952a154e7fc7f6c2d862..f301542343636a8668e8747223f4d55369f82516 100644 (file)
@@ -36,6 +36,7 @@
     <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
     <feature version="${openflowplugin.version}">odl-openflowplugin-nxm-extensions</feature>
     <bundle>mvn:org.opendaylight.ovsdb/utils.servicehelper/${ovsdb.utils.servicehelper.version}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt/${openstack.netvirt.version}</bundle>
     <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-providers/${openstack.netvirt.providers.version}</bundle>
     <bundle>mvn:org.opendaylight.neutron/dummyprovider/${networkconfig.neutron.version}</bundle>
index 8b5bdbee1cd6cca06ac9faab6dd8e669a5d2f8c7..6244999fa1165ac50e770d3aa4c74fcf385891cc 100644 (file)
@@ -256,6 +256,10 @@ module hwvtep {
             description "Per Logical Switch tunnel key";
             type string;
         }
+        leaf logical-switch-managed-by {
+            description "The hwvtep global node to which this logical switch belongs to";
+            type hwvtep-global-ref;
+        }
     }
 
     grouping hwvtep-physical-port-attributes {
index 11b3052290425730aef2d7f7359224f982826482..7eec7e18a55ae15b2d880116f0917a54ac7d2cf9 100644 (file)
@@ -108,12 +108,9 @@ public class HwvtepConnectionInstance implements OvsdbClient{
         if (transactInvokers == null) {
             try {
                 transactInvokers = new HashMap<>();
-                List<String> databases = getDatabases().get();
-                for (String database : databases) {
-                    DatabaseSchema dbSchema = getSchema(database).get();
-                    if (dbSchema != null) {
-                        transactInvokers.put(dbSchema, new TransactInvokerImpl(this,dbSchema));
-                    }
+                DatabaseSchema dbSchema = getSchema(HwvtepSchemaConstants.databaseName).get();
+                if(dbSchema != null) {
+                    transactInvokers.put(dbSchema, new TransactInvokerImpl(this,dbSchema));
                 }
             } catch (InterruptedException | ExecutionException e) {
                 LOG.warn("Exception attempting to createTransactionInvokers {}: {}",connectionInfo,e);
index 54640a202c15efc3f112bb30802c714a8521c7fc..694542463f683326b47adf230793a1268edb2119 100644 (file)
@@ -21,6 +21,8 @@ import java.util.concurrent.ExecutionException;
 import javax.annotation.Nonnull;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
@@ -29,6 +31,10 @@ import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipL
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.HwvtepGlobalRemoveCommand;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.PhysicalSwitchRemoveCommand;
 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
 import org.opendaylight.ovsdb.lib.OvsdbClient;
 import org.opendaylight.ovsdb.lib.OvsdbConnectionListener;
@@ -41,6 +47,8 @@ import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
 import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
 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;
@@ -49,16 +57,21 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
 
 public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoCloseable{
-    private Map<ConnectionInfo, HwvtepConnectionInstance> clients = new ConcurrentHashMap<>();
+    private Map<ConnectionInfo, HwvtepConnectionInstance> clients =
+                    new ConcurrentHashMap<ConnectionInfo,HwvtepConnectionInstance>();
     private static final Logger LOG = LoggerFactory.getLogger(HwvtepConnectionManager.class);
     private static final String ENTITY_TYPE = "hwvtep";
 
     private DataBroker db;
     private TransactionInvoker txInvoker;
-    private Map<ConnectionInfo,InstanceIdentifier<Node>> instanceIdentifiers = new ConcurrentHashMap<>();
-    private Map<Entity, HwvtepConnectionInstance> entityConnectionMap = new ConcurrentHashMap<>();
+    private Map<ConnectionInfo,InstanceIdentifier<Node>> instanceIdentifiers =
+                    new ConcurrentHashMap<ConnectionInfo,InstanceIdentifier<Node>>();
+    private Map<Entity, HwvtepConnectionInstance> entityConnectionMap =
+                    new ConcurrentHashMap<>();
     private EntityOwnershipService entityOwnershipService;
     private HwvtepDeviceEntityOwnershipListener hwvtepDeviceEntityOwnershipListener;
 
@@ -96,7 +109,8 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
         ConnectionInfo key = HwvtepSouthboundMapper.createConnectionInfo(client);
         HwvtepConnectionInstance hwvtepConnectionInstance = getConnectionInstance(key);
         if (hwvtepConnectionInstance != null) {
-            //TODO: txInvoker.invoke(new HwvtepNodeRemoveCommand(hwvtepConnectionInstance, null, null));
+            //TODO: remove all the hwvtep nodes
+            txInvoker.invoke(new HwvtepGlobalRemoveCommand(hwvtepConnectionInstance, null, null));
             removeConnectionInstance(key);
 
             // Unregister Cluster Ownership for ConnectionInfo
@@ -115,6 +129,7 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
             putInstanceIdentifier(hwvtepGlobal.getConnectionInfo(), iid.firstIdentifierOf(Node.class));
             HwvtepConnectionInstance hwvtepConnectionInstance = connectedButCallBacksNotRegistered(client);
             hwvtepConnectionInstance.setHwvtepGlobalAugmentation(hwvtepGlobal);
+            hwvtepConnectionInstance.setInstanceIdentifier(iid.firstIdentifierOf(Node.class));
 
             // Register Cluster Ownership for ConnectionInfo
             registerEntityForOwnership(hwvtepConnectionInstance);
@@ -162,18 +177,6 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
         return hwvtepConnectionInstance;
     }
 
-    /* TODO:
-    public OvsdbClient connect(InstanceIdentifier<Node> iid, OvsdbNodeAugmentation ovsdbNode)
-                    throws UnknownHostException {
-    }
-
-    public void disconnect(OvsdbNodeAugmentation ovsdbNode) throws UnknownHostException {
-        OvsdbConnectionInstance client = getConnectionInstance(ovsdbNode.getConnectionInfo());
-
-    }
-
-    */
-
     private void putConnectionInstance(ConnectionInfo key,HwvtepConnectionInstance instance) {
         ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
         clients.put(connectionInfo, instance);
@@ -185,6 +188,49 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
         return clients.get(connectionInfo);
     }
 
+    public HwvtepConnectionInstance getConnectionInstance(Node node) {
+        Preconditions.checkNotNull(node);
+        HwvtepGlobalAugmentation hwvtepGlobal = node.getAugmentation(HwvtepGlobalAugmentation.class);
+        PhysicalSwitchAugmentation pSwitchNode = node.getAugmentation(PhysicalSwitchAugmentation.class);
+        if (hwvtepGlobal != null) {
+            return getConnectionInstance(hwvtepGlobal.getConnectionInfo());
+        } //TODO: We could get it from Managers also.
+        else if(pSwitchNode != null){
+            return getConnectionInstance(pSwitchNode);
+        } else {
+            LOG.warn("This is not a node that gives any hint how to find its OVSDB Manager: {}",node);
+            return null;
+        }
+    }
+
+    public HwvtepConnectionInstance getConnectionInstance(InstanceIdentifier<Node> nodePath) {
+        try {
+            ReadOnlyTransaction transaction = db.newReadOnlyTransaction();
+            CheckedFuture<Optional<Node>, ReadFailedException> nodeFuture = transaction.read(
+                    LogicalDatastoreType.OPERATIONAL, nodePath);
+            transaction.close();
+            Optional<Node> optional = nodeFuture.get();
+            if (optional != null && optional.isPresent() && optional.get() instanceof Node) {
+                return this.getConnectionInstance(optional.get());
+            } else {
+                LOG.warn("Found non-topological node {} on path {}",optional);
+                return null;
+            }
+        } catch (Exception e) {
+            LOG.warn("Failed to get Hwvtep Node {}",nodePath, e);
+            return null;
+        }
+    }
+
+    private HwvtepConnectionInstance getConnectionInstance(HwvtepPhysicalSwitchAttributes pNode) {
+        Optional<HwvtepGlobalAugmentation> optional = HwvtepSouthboundUtil.getManagingNode(db, pNode);
+        if(optional.isPresent()) {
+            return getConnectionInstance(optional.get().getConnectionInfo());
+        } else {
+            return null;
+        }
+    }
+
     private void removeConnectionInstance(ConnectionInfo key) {
         ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
         clients.remove(connectionInfo);
@@ -198,7 +244,8 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
 
     public InstanceIdentifier<Node> getInstanceIdentifier(ConnectionInfo key) {
         ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
-        return instanceIdentifiers.get(connectionInfo);
+        InstanceIdentifier<Node> iid = instanceIdentifiers.get(connectionInfo);
+        return iid;
     }
 
     private void removeInstanceIdentifier(ConnectionInfo key) {
@@ -257,17 +304,18 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
         if (dbSchema != null) {
             GenericTableSchema hwvtepSchema = TyperUtils.getTableSchema(dbSchema, Global.class);
 
-            List<String> hwvtepTableColumn = new ArrayList<>();
+            List<String> hwvtepTableColumn = new ArrayList<String>();
             hwvtepTableColumn.addAll(hwvtepSchema.getColumns());
             Select<GenericTableSchema> selectOperation = op.select(hwvtepSchema);
-            selectOperation.setColumns(hwvtepTableColumn);
+            selectOperation.setColumns(hwvtepTableColumn);;
 
-            List<Operation> operations = new ArrayList<>();
+            ArrayList<Operation> operations = new ArrayList<Operation>();
             operations.add(selectOperation);
             operations.add(op.comment("Fetching hardware_vtep table rows"));
 
+            List<OperationResult> results = null;
             try {
-                List<OperationResult> results = connectionInstance.transact(dbSchema, operations).get();
+                results = connectionInstance.transact(dbSchema, operations).get();
                 if (results != null ) {
                     OperationResult selectResult = results.get(0);
                     globalRow = TyperUtils.getTypedRowWrapper(
@@ -289,6 +337,8 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
             //TODO: Is Global the right one?
             Global hwvtepGlobalRow = getHwvtepGlobalTableEntry(hwvtepConnectionInstance);
             iid = HwvtepSouthboundMapper.getInstanceIdentifier(hwvtepGlobalRow);
+            /* Let's set the iid now */
+            hwvtepConnectionInstance.setInstanceIdentifier(iid);
             LOG.info("InstanceIdentifier {} generated for device "
                     + "connection {}",iid, hwvtepConnectionInstance.getConnectionInfo());
 
@@ -370,8 +420,14 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
     }
 
     private void cleanEntityOperationalData(Entity entity) {
-        //TODO: remove entity from Operational DataStore
-        LOG.error("cleanEntityOperationalData(): Code incomplete");
+        InstanceIdentifier<Node> nodeIid = (InstanceIdentifier<Node>) HwvtepSouthboundUtil
+                .getInstanceIdentifierCodec().bindingDeserializer(entity.getId());
+
+        final ReadWriteTransaction transaction = db.newReadWriteTransaction();
+        Optional<Node> node = HwvtepSouthboundUtil.readNode(transaction, nodeIid);
+        if (node.isPresent()) {
+            HwvtepSouthboundUtil.deleteNode(transaction, nodeIid);
+        }
     }
 
     private HwvtepConnectionInstance getConnectionInstanceFromEntity(Entity entity) {
@@ -394,5 +450,4 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
             hcm.handleOwnershipChanged(ownershipChange);
         }
     }
-
 }
index e2243b611282db087931c24fccefb4b2bab4cad7..bdf84e614c9fb739057221ded2e2228611133881 100644 (file)
@@ -9,7 +9,14 @@
 package org.opendaylight.ovsdb.hwvtepsouthbound;
 
 import java.net.UnknownHostException;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
@@ -18,10 +25,17 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.HwvtepOperationalState;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactCommandAggregator;
 import org.opendaylight.ovsdb.lib.OvsdbClient;
+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.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfoBuilder;
 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;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
@@ -46,7 +60,7 @@ public class HwvtepDataChangeListener implements DataTreeChangeListener<Node>, A
 
     private void registerListener(final DataBroker db) {
         final DataTreeIdentifier<Node> treeId =
-                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, getWildcardPath());
+                        new DataTreeIdentifier<Node>(LogicalDatastoreType.CONFIGURATION, getWildcardPath());
         try {
             LOG.trace("Registering on path: {}", treeId);
             registration = db.registerDataTreeChangeListener(treeId, HwvtepDataChangeListener.this);
@@ -114,21 +128,22 @@ public class HwvtepDataChangeListener implements DataTreeChangeListener<Node>, A
             Node node = getCreated(mod);
             if (node != null) {
                 HwvtepGlobalAugmentation hwvtepGlobal = node.getAugmentation(HwvtepGlobalAugmentation.class);
-                ConnectionInfo connection = hwvtepGlobal.getConnectionInfo();
-                InstanceIdentifier<Node> iid = hcm.getInstanceIdentifier(connection);
-                if (iid != null) {
-                    LOG.warn("Connection to device {} already exists. Plugin does not allow multiple connections "
-                                    + "to same device, hence dropping the request {}", connection, hwvtepGlobal);
-                } else {
-                    try {
-                        hcm.connect(HwvtepSouthboundMapper.createInstanceIdentifier(node.getNodeId()), hwvtepGlobal);
-                    } catch (UnknownHostException e) {
-                        LOG.warn("Failed to connect to OVSDB node", e);
+                if (hwvtepGlobal != null) {
+                    ConnectionInfo connection = hwvtepGlobal.getConnectionInfo();
+                    InstanceIdentifier<Node> iid = hcm.getInstanceIdentifier(connection);
+                    if (iid != null) {
+                        LOG.warn("Connection to device {} already exists. Plugin does not allow multiple connections "
+                                        + "to same device, hence dropping the request {}", connection, hwvtepGlobal);
+                    } else {
+                        try {
+                            hcm.connect(HwvtepSouthboundMapper.createInstanceIdentifier(node.getNodeId()), hwvtepGlobal);
+                        } catch (UnknownHostException e) {
+                            LOG.warn("Failed to connect to OVSDB node", e);
+                        }
                     }
                 }
             }
         }
-
     }
 
     private void updateConnections(Collection<DataTreeModification<Node>> changes) {
@@ -140,18 +155,19 @@ public class HwvtepDataChangeListener implements DataTreeChangeListener<Node>, A
                 Node original = getOriginal(mod);
                 HwvtepGlobalAugmentation hgUpdated = updated.getAugmentation(HwvtepGlobalAugmentation.class);
                 HwvtepGlobalAugmentation hgOriginal = original.getAugmentation(HwvtepGlobalAugmentation.class);
-                OvsdbClient client = hcm.getClient(hgUpdated.getConnectionInfo());
-                if (client == null) {
-                    try {
-                        hcm.disconnect(hgOriginal);
-                        hcm.connect(HwvtepSouthboundMapper.createInstanceIdentifier(original.getNodeId()), hgUpdated);
-                    } catch (UnknownHostException e) {
-                        LOG.warn("Failed to update connection on OVSDB Node", e);
+                if (hgUpdated != null && hgOriginal != null) {
+                    OvsdbClient client = hcm.getClient(hgUpdated.getConnectionInfo());
+                    if (client == null) {
+                        try {
+                            hcm.disconnect(hgOriginal);
+                            hcm.connect(HwvtepSouthboundMapper.createInstanceIdentifier(original.getNodeId()), hgUpdated);
+                        } catch (UnknownHostException e) {
+                            LOG.warn("Failed to update connection on OVSDB Node", e);
+                        }
                     }
                 }
             }
         }
-
     }
 
     private void updateData(Collection<DataTreeModification<Node>> changes) {
@@ -160,7 +176,12 @@ public class HwvtepDataChangeListener implements DataTreeChangeListener<Node>, A
          * Update data for each connection
          * Requires Command patterns. TBD.
          */
-        
+        for (Entry<HwvtepConnectionInstance, Collection<DataTreeModification<Node>>> changesEntry :
+                changesByConnectionInstance(changes).entrySet()) {
+            HwvtepConnectionInstance connectionInstance = changesEntry.getKey();
+            connectionInstance.transact(new TransactCommandAggregator(
+                new HwvtepOperationalState(db, changesEntry.getValue()),changesEntry.getValue()));
+        }
     }
 
     private void disconnect(Collection<DataTreeModification<Node>> changes) {
@@ -170,17 +191,19 @@ public class HwvtepDataChangeListener implements DataTreeChangeListener<Node>, A
             Node deleted = getRemoved(mod);
             if (deleted != null) {
                 HwvtepGlobalAugmentation hgDeleted = deleted.getAugmentation(HwvtepGlobalAugmentation.class);
-                try {
-                    hcm.disconnect(hgDeleted);
-                } catch (UnknownHostException e) {
-                    LOG.warn("Failed to disconnect OVSDB Node", e);
+                if (hgDeleted != null) {
+                    try {
+                        hcm.disconnect(hgDeleted);
+                    } catch (UnknownHostException e) {
+                        LOG.warn("Failed to disconnect OVSDB Node", e);
+                    }
                 }
             }
         }
     }
 
     private Node getCreated(DataObjectModification<Node> mod) {
-        if((mod.getModificationType() == ModificationType.WRITE) 
+        if((mod.getModificationType() == ModificationType.WRITE)
                         && (mod.getDataBefore() == null)){
             return mod.getDataAfter();
         }
@@ -232,9 +255,35 @@ public class HwvtepDataChangeListener implements DataTreeChangeListener<Node>, A
     }
 
     private InstanceIdentifier<Node> getWildcardPath() {
-        return InstanceIdentifier
+        InstanceIdentifier<Node> path = InstanceIdentifier
                         .create(NetworkTopology.class)
                         .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
                         .child(Node.class);
+        return path;
+    }
+
+    private Map<HwvtepConnectionInstance, Collection<DataTreeModification<Node>>> changesByConnectionInstance(
+            Collection<DataTreeModification<Node>> changes) {
+        Map<HwvtepConnectionInstance, Collection<DataTreeModification<Node>>> result =
+                new HashMap<HwvtepConnectionInstance, Collection<DataTreeModification<Node>>>();
+        for (DataTreeModification<Node> change : changes) {
+            final DataObjectModification<Node> mod = change.getRootNode();
+            //From original node to get connection instance
+            Node node = mod.getDataBefore()!=null ? mod.getDataBefore() : mod.getDataAfter();
+            HwvtepConnectionInstance connection = hcm.getConnectionInstance(node);
+            if (connection != null) {
+                if (!result.containsKey(connection)) {
+                    List<DataTreeModification<Node>> tempChanges= new ArrayList<DataTreeModification<Node>>();
+                    tempChanges.add(change);
+                    result.put(connection, tempChanges);
+                } else {
+                    result.get(connection).add(change);
+                }
+            } else {
+                LOG.warn("Failed to get the connection of changed node: {}", node);
+            }
+        }
+        LOG.trace("Connection Change Map: {}", result);
+        return result;
     }
-}
+}
\ No newline at end of file
index 5fe2f0c7776a1f6dc2c3c8065cc2f9a954683799..e487f25dc2eb5855280e2edde7c531f57946137b 100644 (file)
@@ -15,6 +15,7 @@ import java.net.UnknownHostException;
 
 import org.opendaylight.ovsdb.lib.OvsdbClient;
 import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
+import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
 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;
@@ -43,10 +44,11 @@ public class HwvtepSouthboundMapper {
     }
 
     public static InstanceIdentifier<Node> createInstanceIdentifier(NodeId nodeId) {
-        return InstanceIdentifier
+        InstanceIdentifier<Node> nodePath = InstanceIdentifier
                 .create(NetworkTopology.class)
                 .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
                 .child(Node.class,new NodeKey(nodeId));
+        return nodePath;
     }
 
     public static InstanceIdentifier<Node> createInstanceIdentifier (OvsdbClient client) {
@@ -119,13 +121,8 @@ public class HwvtepSouthboundMapper {
 
     public static InstanceIdentifier<Node> getInstanceIdentifier(Global global) {
         InstanceIdentifier<Node> iid = null;
-        if (global.getManagersColumn() != null
-                && global.getManagersColumn().getData() != null) {
-            String iidString = global.getManagersColumn().getData().iterator().next().toString();
-            iid = (InstanceIdentifier<Node>) HwvtepSouthboundUtil.deserializeInstanceIdentifier(iidString);
-        } else {
-            String nodeString = HwvtepSouthboundConstants.HWVTEP_URI_PREFIX + "://" +
-                            HwvtepSouthboundConstants.UUID + "/" + global.getUuid().toString();
+        String nodeString = HwvtepSouthboundConstants.HWVTEP_URI_PREFIX + "://" +
+                        HwvtepSouthboundConstants.UUID + "/" + global.getUuid().toString();
             NodeId nodeId = new NodeId(new Uri(nodeString));
             NodeKey nodeKey = new NodeKey(nodeId);
             TopologyKey topoKey = new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
@@ -133,7 +130,18 @@ public class HwvtepSouthboundMapper {
                             .child(Topology.class, topoKey)
                             .child(Node.class,nodeKey)
                             .build();
-        }
+        return iid;
+    }
+
+    public static InstanceIdentifier<Node> createInstanceIdentifier(HwvtepConnectionInstance client,
+                    PhysicalSwitch pSwitch) {
+        InstanceIdentifier<Node> iid = null;
+        String nodeString = client.getNodeKey().getNodeId().getValue() + "/physicalswitch/" + pSwitch.getName();
+        NodeId nodeId = new NodeId(new Uri(nodeString));
+        NodeKey nodeKey = new NodeKey(nodeId);
+        iid =InstanceIdentifier.builder(NetworkTopology.class)
+                        .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+                        .child(Node.class, nodeKey).build();
         return iid;
     }
 }
index 9616f2c483056eb345da9042c4aeb8f3e14cbdf4..483cf1567d7a1ac52ccb6aa49e950c12c8879c7b 100644 (file)
@@ -1,17 +1,33 @@
 /*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound;
 
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchAttributes;
+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.data.impl.codec.DeserializationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+
 public class HwvtepSouthboundUtil {
 
     private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundUtil.class);
@@ -44,5 +60,101 @@ public class HwvtepSouthboundUtil {
         return result;
     }
 
+    public static <D extends org.opendaylight.yangtools.yang.binding.DataObject> Optional<D> readNode(
+                    ReadWriteTransaction transaction, final InstanceIdentifier<D> connectionIid) {
+        Optional<D> node = Optional.absent();
+        try {
+            node = transaction.read(LogicalDatastoreType.OPERATIONAL, connectionIid).checkedGet();
+        } catch (final ReadFailedException e) {
+            LOG.warn("Read Operational/DS for Node failed! {}", connectionIid, e);
+        }
+        return node;
+    }
+
+    public static <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean deleteNode(
+                    ReadWriteTransaction transaction, final InstanceIdentifier<D> connectionIid) {
+        boolean result = false;
+        transaction.delete(LogicalDatastoreType.OPERATIONAL, connectionIid);
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        try {
+            future.checkedGet();
+            result = true;
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Failed to delete {} ", connectionIid, e);
+        }
+        return result;
+    }
+
+    public static Optional<HwvtepGlobalAugmentation> getManagingNode(DataBroker db,
+                    HwvtepPhysicalSwitchAttributes pNode) {
+        Preconditions.checkNotNull(pNode);
+        Optional<HwvtepGlobalAugmentation> result = null;
+        HwvtepGlobalRef ref = pNode.getManagedBy();
+        if (ref != null && ref.getValue() != null) {
+            result = getManagingNode(db, ref);
+        } else {
+            LOG.warn("Cannot find client for PhysicalSwitch without a specified ManagedBy {}", pNode);
+            return Optional.absent();
+        }
+        if (!result.isPresent()) {
+            LOG.warn("Failed to find managing node for PhysicalSwitch {}", pNode);
+        }
+        return result;
+    }
+
+    public static Optional<HwvtepGlobalAugmentation> getManagingNode(DataBroker db,
+                    HwvtepLogicalSwitchAttributes lNode) {
+        Preconditions.checkNotNull(lNode);
+        Optional<HwvtepGlobalAugmentation> result = null;
+
+        HwvtepGlobalRef ref = lNode.getLogicalSwitchManagedBy();
+        if (ref != null && ref.getValue() != null) {
+            result = getManagingNode(db, ref);
+        } else {
+            LOG.warn("Cannot find client for LogicalSwitch without a specified ManagedBy {}", lNode);
+            return Optional.absent();
+        }
+        if(!result.isPresent()) {
+            LOG.warn("Failed to find managing node for PhysicalSwitch {}",lNode);
+        }
+        return result;
+    }
+
+    private static Optional<HwvtepGlobalAugmentation> getManagingNode(DataBroker db, HwvtepGlobalRef ref) {
+        try {
+            ReadOnlyTransaction transaction = db.newReadOnlyTransaction();
+            @SuppressWarnings("unchecked")
+            // Note: erasure makes this safe in combination with the typecheck
+            // below
+            InstanceIdentifier<Node> path = (InstanceIdentifier<Node>) ref.getValue();
+
+            CheckedFuture<Optional<Node>, ReadFailedException> nf =
+                            transaction.read(LogicalDatastoreType.OPERATIONAL, path);
+            transaction.close();
+            Optional<Node> optional = nf.get();
+            if (optional != null && optional.isPresent()) {
+                HwvtepGlobalAugmentation hwvtepNode = null;
+                Node node = optional.get();
+                if (node instanceof HwvtepGlobalAugmentation) {
+                    hwvtepNode = (HwvtepGlobalAugmentation) node;
+                } else if (node != null) {
+                    hwvtepNode = node.getAugmentation(HwvtepGlobalAugmentation.class);
+                }
+                if (hwvtepNode != null) {
+                    return Optional.of(hwvtepNode);
+                } else {
+                    LOG.warn("Hwvtep switch claims to be managed by {} but " + "that HwvtepNode does not exist",
+                                    ref.getValue());
+                    return Optional.absent();
+                }
+            } else {
+                LOG.warn("Mysteriously got back a thing which is *not* a topology Node: {}", optional);
+                return Optional.absent();
+            }
+        } catch (Exception e) {
+            LOG.warn("Failed to get HwvtepNode {}", ref, e);
+            return Optional.absent();
+        }
+    }
 
 }
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/AbstractTransactCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/AbstractTransactCommand.java
new file mode 100644 (file)
index 0000000..d766f19
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute 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.hwvtepsouthbound.transact;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+public abstract class AbstractTransactCommand implements TransactCommand {
+
+    private HwvtepOperationalState operationalState;
+    private Collection<DataTreeModification<Node>> changes;
+
+    protected AbstractTransactCommand() {
+        // NO OP
+    }
+
+    public AbstractTransactCommand(HwvtepOperationalState state, Collection<DataTreeModification<Node>> changes) {
+        this.operationalState = state;
+        this.changes = changes;
+    }
+
+    public HwvtepOperationalState getOperationalState() {
+        return operationalState;
+    }
+
+    public Collection<DataTreeModification<Node>> getChanges() {
+        return changes;
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/HwvtepOperationalState.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/HwvtepOperationalState.java
new file mode 100644 (file)
index 0000000..26c515d
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute 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.hwvtepsouthbound.transact;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorSetAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalPortAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+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.util.concurrent.CheckedFuture;
+
+public class HwvtepOperationalState {
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepOperationalState.class);
+    private Map<InstanceIdentifier<Node>, Node> operationalNodes = new HashMap<>();
+
+    public HwvtepOperationalState(DataBroker db, Collection<DataTreeModification<Node>> changes) {
+        ReadOnlyTransaction transaction = db.newReadOnlyTransaction();
+        Map<InstanceIdentifier<Node>, Node> nodeCreateOrUpdate =
+            extractCreatedOrUpdatedOrRemoved(changes, Node.class);
+            //TransactUtils.extractCreatedOrUpdatedOrRemoved(changes, Node.class);
+        if (nodeCreateOrUpdate != null) {
+            for (Entry<InstanceIdentifier<Node>, Node> entry: nodeCreateOrUpdate.entrySet()) {
+                CheckedFuture<Optional<Node>, ReadFailedException> nodeFuture =
+                        transaction.read(LogicalDatastoreType.OPERATIONAL, entry.getKey());
+                try {
+                    Optional<Node> nodeOptional = nodeFuture.get();
+                    if (nodeOptional.isPresent()) {
+                        operationalNodes.put(entry.getKey(), nodeOptional.get());
+                    }
+                } catch (InterruptedException | ExecutionException e) {
+                    LOG.warn("Error reading from datastore",e);
+                }
+            }
+        }
+        transaction.close();
+    }
+
+    private Node getCreated(DataObjectModification<Node> mod) {
+        if((mod.getModificationType() == ModificationType.WRITE)
+                        && (mod.getDataBefore() == null)){
+            return mod.getDataAfter();
+        }
+        return null;
+    }
+
+    private Node getRemoved(DataObjectModification<Node> mod) {
+        if(mod.getModificationType() == ModificationType.DELETE){
+            return mod.getDataBefore();
+        }
+        return null;
+    }
+
+    private Node getUpdated(DataObjectModification<Node> mod) {
+        Node node = null;
+        switch(mod.getModificationType()) {
+            case SUBTREE_MODIFIED:
+                node = mod.getDataAfter();
+                break;
+            case WRITE:
+                if(mod.getDataBefore() !=  null) {
+                    node = mod.getDataAfter();
+                }
+                break;
+            default:
+                break;
+        }
+        return node;
+    }
+
+    private Node getOriginal(DataObjectModification<Node> mod) {
+        Node node = null;
+        switch(mod.getModificationType()) {
+            case SUBTREE_MODIFIED:
+                node = mod.getDataBefore();
+                break;
+            case WRITE:
+                if(mod.getDataBefore() !=  null) {
+                    node = mod.getDataBefore();
+                }
+                break;
+            case DELETE:
+                node = mod.getDataBefore();
+                break;
+            default:
+                break;
+        }
+        return node;
+    }
+
+    private Map<InstanceIdentifier<Node>, Node> extractCreatedOrUpdatedOrRemoved(
+            Collection<DataTreeModification<Node>> changes, Class<Node> class1) {
+        // TODO Auto-generated method stub
+        Map<InstanceIdentifier<Node>, Node> result = new HashMap<InstanceIdentifier<Node>, Node>();
+        for (DataTreeModification<Node> change : changes) {
+            final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
+            final DataObjectModification<Node> mod = change.getRootNode();
+            Node created = getCreated(mod);
+            result.put(key, created);
+            Node updated = getUpdated(mod);
+            result.put(key, updated);
+            Node deleted = getRemoved(mod);
+            result.put(key, deleted);
+        }
+        return result;
+    }
+
+    public Optional<Node> getGlobalNode(InstanceIdentifier<?> iid) {
+        InstanceIdentifier<Node> nodeIid = iid.firstIdentifierOf(Node.class);
+        return Optional.fromNullable(operationalNodes.get(nodeIid));
+    }
+
+    public Optional<HwvtepLogicalSwitchAugmentation> getLogicalSwitchAugmentation(InstanceIdentifier<?> iid) {
+        Optional<Node> nodeOptional = getGlobalNode(iid);
+        if (nodeOptional.isPresent()) {
+            return Optional.fromNullable(nodeOptional.get().getAugmentation(HwvtepLogicalSwitchAugmentation.class));
+        }
+        return Optional.absent();
+    }
+
+    public Optional<PhysicalSwitchAugmentation> getPhysicalSwitchAugmentation(InstanceIdentifier<?> iid) {
+        Optional<Node> nodeOptional = getGlobalNode(iid);
+        if (nodeOptional.isPresent()) {
+            return Optional.fromNullable(nodeOptional.get().getAugmentation(PhysicalSwitchAugmentation.class));
+        }
+        return Optional.absent();
+    }
+
+    public Optional<HwvtepPhysicalLocatorSetAugmentation> getPhysicalLocatorSetAugmentation(InstanceIdentifier<?> iid) {
+        Optional<Node> nodeOptional = getGlobalNode(iid);
+        if (nodeOptional.isPresent()) {
+            return Optional.fromNullable(nodeOptional.get().getAugmentation(HwvtepPhysicalLocatorSetAugmentation.class));
+        }
+        return Optional.absent();
+    }
+
+    public Optional<TerminationPoint> getHwvtepTerminationPoint(InstanceIdentifier<?> iid) {
+        if (iid != null) {
+            Optional<Node> nodeOptional = getGlobalNode(iid);
+            if (nodeOptional.isPresent() && nodeOptional.get().getTerminationPoint() != null) {
+                TerminationPointKey key = iid.firstKeyOf(TerminationPoint.class, TerminationPointKey.class);
+                if (key != null) {
+                    for (TerminationPoint tp:nodeOptional.get().getTerminationPoint()) {
+                        if (tp.getKey().equals(key)) {
+                            return Optional.of(tp);
+                        }
+                    }
+                }
+            }
+        }
+        return Optional.absent();
+    }
+
+    public Optional<HwvtepPhysicalLocatorAugmentation> getPhysicalLocatorAugmentation(InstanceIdentifier<?> iid) {
+        Optional<TerminationPoint> nodeOptional = getHwvtepTerminationPoint(iid);
+        if (nodeOptional.isPresent()) {
+            return Optional.fromNullable(nodeOptional.get().getAugmentation(HwvtepPhysicalLocatorAugmentation.class));
+        }
+        return Optional.absent();
+    }
+
+    public Optional<HwvtepPhysicalPortAugmentation> getPhysycalPortAugmentation(InstanceIdentifier<?> iid) {
+        Optional<TerminationPoint> tpOptional = getHwvtepTerminationPoint(iid);
+        if (tpOptional.isPresent()) {
+            return Optional.fromNullable(tpOptional.get().getAugmentation(HwvtepPhysicalPortAugmentation.class));
+        }
+        return Optional.absent();
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchRemoveCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchRemoveCommand.java
new file mode 100644 (file)
index 0000000..6be3c44
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute 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.hwvtepsouthbound.transact;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+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.hardwarevtep.Global;
+import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchAugmentation;
+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 LogicalSwitchRemoveCommand extends AbstractTransactCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchRemoveCommand.class);
+
+    public LogicalSwitchRemoveCommand(HwvtepOperationalState state,
+            Collection<DataTreeModification<Node>> changes) {
+        super(state, changes);
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        //TODO
+        /*Set<InstanceIdentifier<HwvtepLogicalSwitchAugmentation>> removeds =
+                TransactUtils.extractRemoved(getChanges(),HwvtepLogicalSwitchAugmentation.class);
+        Map<InstanceIdentifier<HwvtepLogicalSwitchAugmentation>, HwvtepLogicalSwitchAugmentation> originals
+            = TransactUtils.extractOriginal(getChanges(),HwvtepLogicalSwitchAugmentation.class);
+        for (InstanceIdentifier<HwvtepLogicalSwitchAugmentation> removed: removeds) {
+            LOG.info("Received request to delete ovsdb node {}",removed);
+            HwvtepLogicalSwitchAugmentation original = originals.get(removed);
+            LogicalSwitch bridge = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), LogicalSwitch.class, null);
+            Optional<HwvtepLogicalSwitchAugmentation> lsAugmentationOptional = getOperationalState()
+                    .getLogicalSwitchAugmentation(removed);
+            if (lsAugmentationOptional.isPresent() && lsAugmentationOptional.get().getHwvtepLogicalSwitchExternalId() != null) {
+                UUID lsUuid = new UUID(lsAugmentationOptional.get().getHwvtepLogicalSwitchExternalId().getValue());
+                Global ovs = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
+                        Global.class,null);
+                transaction.add(op.delete(bridge.getSchema())
+                        .where(bridge.getUuidColumn().getSchema().opEqual(lsUuid)).build());
+                transaction.add(op.comment("Logical Switch: Deleting " + original.getHwvtepNodeName()));
+            } else {
+                LOG.warn("Unable to delete logical switch {} because it was not found in the operational store, "
+                        + "and thus we cannot retrieve its UUID", removed);
+            }
+
+        }*/
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchUpdateCommand.java
new file mode 100644 (file)
index 0000000..730c936
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute 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.hwvtepsouthbound.transact;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchAugmentation;
+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 LogicalSwitchUpdateCommand extends AbstractTransactCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchUpdateCommand.class);
+
+    public LogicalSwitchUpdateCommand(HwvtepOperationalState state,
+            Collection<DataTreeModification<Node>> changes) {
+        super(state, changes);
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        Map<InstanceIdentifier<HwvtepLogicalSwitchAugmentation>, HwvtepLogicalSwitchAugmentation> created =
+                extractCreated(getChanges(),HwvtepLogicalSwitchAugmentation.class);
+        if(created != null) {
+            for(Entry<InstanceIdentifier<HwvtepLogicalSwitchAugmentation>, HwvtepLogicalSwitchAugmentation> logicalSwitchEntry:
+                created.entrySet()) {
+                updateLogicalSwitch(transaction,  logicalSwitchEntry.getKey(), logicalSwitchEntry.getValue());
+            }
+        }
+    }
+
+
+    private void updateLogicalSwitch(TransactionBuilder transaction,
+            InstanceIdentifier<HwvtepLogicalSwitchAugmentation> iid, HwvtepLogicalSwitchAugmentation logicalSwitchAugmentation) {
+        LOG.debug("Creating a logical switch named: {}", logicalSwitchAugmentation.getHwvtepNodeName());
+        Optional<HwvtepLogicalSwitchAugmentation> operationalLogicalSwitchOptional =
+                getOperationalState().getLogicalSwitchAugmentation(iid);
+        DatabaseSchema dbSchema = transaction.getDatabaseSchema();
+        LogicalSwitch logicalSwitch = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), LogicalSwitch.class);
+        if(!operationalLogicalSwitchOptional.isPresent()) {
+            setName(logicalSwitch, logicalSwitchAugmentation, operationalLogicalSwitchOptional);
+            setTunnelKey(logicalSwitch, logicalSwitchAugmentation, operationalLogicalSwitchOptional);
+            transaction.add(op.insert(logicalSwitch));
+        } else {
+            String existingLogicalSwitchName = operationalLogicalSwitchOptional.get().getHwvtepNodeName().getValue();
+            // Name is immutable, and so we *can't* update it.  So we use extraBridge for the schema stuff
+            LogicalSwitch extraLogicalSwitch = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), LogicalSwitch.class);
+            extraLogicalSwitch.setName("");
+            transaction.add(op.update(logicalSwitch)
+                    .where(extraLogicalSwitch.getNameColumn().getSchema().opEqual(existingLogicalSwitchName))
+                    .build());
+            //stampInstanceIdentifier(transaction, iid.firstIdentifierOf(Node.class),existingBridgeName);
+        }
+    }
+
+    private void setName(LogicalSwitch logicalSwitch, HwvtepLogicalSwitchAugmentation logicalSwitchAugmentation,
+            Optional<HwvtepLogicalSwitchAugmentation> operationalLogicalSwitchOptional) {
+        if(logicalSwitchAugmentation.getHwvtepNodeName() != null) {
+            logicalSwitch.setName(logicalSwitchAugmentation.getHwvtepNodeName().getValue());
+        } else if(operationalLogicalSwitchOptional.isPresent() && operationalLogicalSwitchOptional.get().getHwvtepNodeName() != null) {
+            logicalSwitch.setName(operationalLogicalSwitchOptional.get().getHwvtepNodeName().getValue());
+        }
+    }
+
+    private void setTunnelKey(LogicalSwitch logicalSwitch, HwvtepLogicalSwitchAugmentation logicalSwitchAugmentation,
+            Optional<HwvtepLogicalSwitchAugmentation> operationalLogicalSwitchOptional) {
+        if(logicalSwitchAugmentation.getTunnelKey() != null) {
+            Set<Long> tunnel = new HashSet<Long>();
+            tunnel.add(Long.valueOf(logicalSwitchAugmentation.getTunnelKey()));
+            logicalSwitch.setTunnelKey(tunnel);
+        } else if(operationalLogicalSwitchOptional.isPresent() && operationalLogicalSwitchOptional.get().getTunnelKey() != null) {
+            Set<Long> tunnel = new HashSet<Long>();
+            tunnel.add(Long.valueOf(operationalLogicalSwitchOptional.get().getTunnelKey()));
+            logicalSwitch.setTunnelKey(tunnel);
+        }
+    }
+
+    private Node getCreated(DataObjectModification<Node> mod) {
+        if((mod.getModificationType() == ModificationType.WRITE)
+                        && (mod.getDataBefore() == null)){
+            return mod.getDataAfter();
+        }
+        return null;
+    }
+
+    private Map<InstanceIdentifier<HwvtepLogicalSwitchAugmentation>, HwvtepLogicalSwitchAugmentation> extractCreated(
+            Collection<DataTreeModification<Node>> changes, Class<HwvtepLogicalSwitchAugmentation> class1) {
+        Map<InstanceIdentifier<HwvtepLogicalSwitchAugmentation>, HwvtepLogicalSwitchAugmentation> result
+            = new HashMap<InstanceIdentifier<HwvtepLogicalSwitchAugmentation>, HwvtepLogicalSwitchAugmentation>();
+        if(changes != null && !changes.isEmpty()) {
+            for(DataTreeModification<Node> change : changes) {
+                final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
+                final DataObjectModification<Node> mod = change.getRootNode();
+                Node created = getCreated(mod);
+                if(created != null) {
+                    HwvtepLogicalSwitchAugmentation logicalSwitch = created.getAugmentation(HwvtepLogicalSwitchAugmentation.class);
+                    InstanceIdentifier<HwvtepLogicalSwitchAugmentation> iid = change.getRootPath().getRootIdentifier().augmentation(HwvtepLogicalSwitchAugmentation.class);
+                    if(logicalSwitch != null) {
+                        result.put(iid, logicalSwitch);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalLocatorRemoveCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalLocatorRemoveCommand.java
new file mode 100644 (file)
index 0000000..8206b4c
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute 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.hwvtepsouthbound.transact;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PhysicalLocatorRemoveCommand extends AbstractTransactCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(PhysicalLocatorRemoveCommand.class);
+
+    public PhysicalLocatorRemoveCommand(HwvtepOperationalState state,
+            Collection<DataTreeModification<Node>> changes) {
+        super(state, changes);
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        //TODO
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalLocatorUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalLocatorUpdateCommand.java
new file mode 100644 (file)
index 0000000..113d78b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute 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.hwvtepsouthbound.transact;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PhysicalLocatorUpdateCommand extends AbstractTransactCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(PhysicalLocatorUpdateCommand.class);
+
+    public PhysicalLocatorUpdateCommand(HwvtepOperationalState state,
+            Collection<DataTreeModification<Node>> changes) {
+        super(state, changes);
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        //TODO
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalPortRemoveCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalPortRemoveCommand.java
new file mode 100644 (file)
index 0000000..aafc847
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute 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.hwvtepsouthbound.transact;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PhysicalPortRemoveCommand extends AbstractTransactCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(PhysicalPortRemoveCommand.class);
+
+    public PhysicalPortRemoveCommand(HwvtepOperationalState state,
+            Collection<DataTreeModification<Node>> changes) {
+        super(state, changes);
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        //TODO
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalPortUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalPortUpdateCommand.java
new file mode 100644 (file)
index 0000000..caef6cb
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute 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.hwvtepsouthbound.transact;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PhysicalPortUpdateCommand extends AbstractTransactCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(PhysicalPortUpdateCommand.class);
+
+    public PhysicalPortUpdateCommand(HwvtepOperationalState state,
+            Collection<DataTreeModification<Node>> changes) {
+        super(state, changes);
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        //TODO
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommandAggregator.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommandAggregator.java
new file mode 100644 (file)
index 0000000..3d15f38
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute 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.hwvtepsouthbound.transact;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+public class TransactCommandAggregator implements TransactCommand {
+
+    private List<TransactCommand> commands = new ArrayList<TransactCommand>();
+
+    public TransactCommandAggregator(HwvtepOperationalState state, Collection<DataTreeModification<Node>> changes) {
+        commands.add(new LogicalSwitchUpdateCommand(state,changes));
+        commands.add(new LogicalSwitchRemoveCommand(state,changes));
+        commands.add(new PhysicalLocatorUpdateCommand(state,changes));
+        commands.add(new PhysicalLocatorRemoveCommand(state,changes));
+        commands.add(new PhysicalPortUpdateCommand(state,changes));
+        commands.add(new PhysicalPortRemoveCommand(state,changes));
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        for (TransactCommand command:commands) {
+            command.execute(transaction);
+        }
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactUtils.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactUtils.java
new file mode 100644 (file)
index 0000000..e8a01e6
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute 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.hwvtepsouthbound.transact;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchAugmentation;
+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.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TransactUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(TransactUtils.class);
+
+    public static Node getCreated(DataObjectModification<Node> mod) {
+        if((mod.getModificationType() == ModificationType.WRITE)
+                        && (mod.getDataBefore() == null)){
+            return mod.getDataAfter();
+        }
+        return null;
+    }
+
+    public static Node getRemoved(DataObjectModification<Node> mod) {
+        if(mod.getModificationType() == ModificationType.DELETE){
+            return mod.getDataBefore();
+        }
+        return null;
+    }
+
+    public static Node getUpdated(DataObjectModification<Node> mod) {
+        Node node = null;
+        switch(mod.getModificationType()) {
+            case SUBTREE_MODIFIED:
+                node = mod.getDataAfter();
+                break;
+            case WRITE:
+                if(mod.getDataBefore() !=  null) {
+                    node = mod.getDataAfter();
+                }
+                break;
+            default:
+                break;
+        }
+        return node;
+    }
+
+    public static Node getOriginal(DataObjectModification<Node> mod) {
+        Node node = null;
+        switch(mod.getModificationType()) {
+            case SUBTREE_MODIFIED:
+                node = mod.getDataBefore();
+                break;
+            case WRITE:
+                if(mod.getDataBefore() !=  null) {
+                    node = mod.getDataBefore();
+                }
+                break;
+            case DELETE:
+                node = mod.getDataBefore();
+                break;
+            default:
+                break;
+        }
+        return node;
+    }
+
+    public static Map<InstanceIdentifier<Node>, Node> extractCreatedOrUpdatedOrRemoved(
+            Collection<DataTreeModification<Node>> changes, Class<Node> class1) {
+        // TODO Auto-generated method stub
+        Map<InstanceIdentifier<Node>, Node> result = new HashMap<InstanceIdentifier<Node>, Node>();
+        for(DataTreeModification<Node> change : changes) {
+            final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
+            final DataObjectModification<Node> mod = change.getRootNode();
+            Node created = getCreated(mod);
+            result.put(key, created);
+            Node updated = getUpdated(mod);
+            result.put(key, updated);
+            Node deleted = getRemoved(mod);
+            result.put(key, deleted);
+        }
+        return null;
+    }
+
+    /*
+    public static <T extends Augmentation<Node>> Map<InstanceIdentifier<? extends DataObject>, T> extractCreated(
+            Collection<DataTreeModification<Node>> changes, Class<T> class1) {
+        // TODO Auto-generated method stub
+        Map<InstanceIdentifier<?>, T> result =
+            new HashMap<InstanceIdentifier<?>, T>();
+        if(changes != null && !changes.isEmpty()) {
+            for(DataTreeModification<Node> change : changes) {
+                final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
+                final DataObjectModification<Node> mod = change.getRootNode();
+                Node created = getCreated(mod);
+                if(created != null) {
+                    T logicalSwitch = created.getAugmentation(class1);
+                    created.getKey().getNodeId().get
+                    logicalSwitch.
+                    InstanceIdentifier<?> iid = change.getRootPath().getRootIdentifier()..augmentation(class1);
+                    if(logicalSwitch != null) {
+                        result.put(iid, logicalSwitch);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+    */
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/AbstractTransactionCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/AbstractTransactionCommand.java
new file mode 100644 (file)
index 0000000..67f507d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+
+public abstract class AbstractTransactionCommand implements TransactionCommand{
+
+    private TableUpdates updates;
+    private DatabaseSchema dbSchema;
+    private HwvtepConnectionInstance key;
+
+    public TableUpdates getUpdates() {
+        return updates;
+    }
+
+    public DatabaseSchema getDbSchema() {
+        return dbSchema;
+    }
+
+    public ConnectionInfo getConnectionInfo() {
+        return key.getMDConnectionInfo();
+    }
+
+    public HwvtepConnectionInstance getOvsdbConnectionInstance() {
+        return key;
+    }
+
+    protected AbstractTransactionCommand() {
+        // NO OP
+    }
+
+    public AbstractTransactionCommand(HwvtepConnectionInstance key,TableUpdates updates, DatabaseSchema dbSchema) {
+        this.updates = updates;
+        this.dbSchema = dbSchema;
+        this.key = key;
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/GlobalUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/GlobalUpdateCommand.java
new file mode 100644 (file)
index 0000000..656fd23
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+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.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
+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.hardwarevtep.Global;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder;
+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.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GlobalUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GlobalUpdateCommand.class);
+    private Map<UUID, Global> updatedHwvtepRows =
+                    TyperUtils.extractRowsUpdated(Global.class, getUpdates(),getDbSchema());
+    private Map<UUID, Global> oldHwvtepRows =
+                    TyperUtils.extractRowsUpdated(Global.class, getUpdates(),getDbSchema());
+
+    public GlobalUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+                super(key, updates, dbSchema);
+            }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        for (Entry<UUID, Global> entry : updatedHwvtepRows.entrySet()) {
+            Global hwvtepGlobal = entry.getValue();
+            Global oldEntry = oldHwvtepRows.get(entry.getKey());
+            final InstanceIdentifier<Node> nodePath = getInstanceIdentifier(hwvtepGlobal);
+            LOG.trace("Processing hardware_vtep update for nodePath: {}", nodePath);
+
+            HwvtepGlobalAugmentationBuilder hwvtepGlobalBuilder = new HwvtepGlobalAugmentationBuilder();
+            hwvtepGlobalBuilder.setConnectionInfo(getConnectionInfo());
+            NodeBuilder nodeBuilder = new NodeBuilder();
+            nodeBuilder.setNodeId(getNodeId(hwvtepGlobal));
+            nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, hwvtepGlobalBuilder.build());
+            transaction.merge(LogicalDatastoreType.OPERATIONAL, nodePath, nodeBuilder.build());
+        }
+    }
+
+    private InstanceIdentifier<Node> getInstanceIdentifier(Global hwvtep) {
+        InstanceIdentifier<Node> iid = getOvsdbConnectionInstance().getInstanceIdentifier();
+        if(iid == null) {
+            LOG.warn("InstanceIdentifier was null when it shouldn't be");
+            /* This can be case for switch initiated connection */
+            iid = HwvtepSouthboundMapper.getInstanceIdentifier(hwvtep);
+            getOvsdbConnectionInstance().setInstanceIdentifier(iid);
+        }
+        return getOvsdbConnectionInstance().getInstanceIdentifier();
+    }
+
+    private NodeId getNodeId(Global hwvtep) {
+        NodeKey nodeKey = getInstanceIdentifier(hwvtep).firstKeyOf(Node.class, NodeKey.class);
+        return nodeKey.getNodeId();
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepGlobalRemoveCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepGlobalRemoveCommand.java
new file mode 100644 (file)
index 0000000..acf2ee9
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.Managers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.Switches;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+public class HwvtepGlobalRemoveCommand extends AbstractTransactionCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepGlobalRemoveCommand.class);
+    private static final long ONE_CONNECTED_MANAGER = 1;
+    private static final long ONE_ACTIVE_CONNECTION_IN_PASSIVE_MODE = 1;
+
+    public HwvtepGlobalRemoveCommand(HwvtepConnectionInstance key,TableUpdates updates,DatabaseSchema dbSchema) {
+        super(key,updates,dbSchema);
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        CheckedFuture<Optional<Node>, ReadFailedException> hwvtepGlobalFuture = transaction.read(
+                LogicalDatastoreType.OPERATIONAL, getOvsdbConnectionInstance().getInstanceIdentifier());
+        Optional<Node> hwvtepGlobalOptional;
+        try {
+            hwvtepGlobalOptional = hwvtepGlobalFuture.get();
+            if (hwvtepGlobalOptional.isPresent()) {
+                Node hwvtepNode = hwvtepGlobalOptional.get();
+                HwvtepGlobalAugmentation hgAugmentation = hwvtepNode.getAugmentation(HwvtepGlobalAugmentation.class);
+                if (checkIfOnlyConnectedManager(hgAugmentation)) {
+                    if (hgAugmentation != null) {
+                        if (hgAugmentation.getSwitches() != null) {
+                            for (Switches hwSwitch : hgAugmentation.getSwitches()) {
+                                LOG.debug("Deleting hwvtep switch {}", hwSwitch);
+                                transaction.delete(
+                                        LogicalDatastoreType.OPERATIONAL, hwSwitch.getSwitchRef().getValue());
+                            }
+                        } else {
+                            LOG.debug("{} had no switches", hwvtepNode.getNodeId().getValue());
+                        }
+                    } else {
+                        LOG.warn("{} had no HwvtepGlobalAugmentation", hwvtepNode.getNodeId().getValue());
+                    }
+                    transaction.delete(LogicalDatastoreType.OPERATIONAL,
+                            getOvsdbConnectionInstance().getInstanceIdentifier());
+                } else {
+                    LOG.debug("Other southbound plugin instances in cluster are connected to the device,"
+                            + " not deleting OvsdbNode form data store.");
+                }
+            }
+        } catch (Exception e) {
+            LOG.warn("Failure to delete ovsdbNode {}",e);
+        }
+    }
+
+    private boolean checkIfOnlyConnectedManager(HwvtepGlobalAugmentation hgAugmentation) {
+        Managers onlyConnectedManager = null;
+        if (hgAugmentation != null) {
+            int connectedManager = 0;
+            if (hgAugmentation.getManagers() != null) {
+                for (Managers manager : hgAugmentation.getManagers()) {
+                    if (manager.isIsConnected()) {
+                        connectedManager++;
+                        if (connectedManager > ONE_CONNECTED_MANAGER) {
+                            return false;
+                        }
+                        onlyConnectedManager = manager;
+                    }
+                }
+            }
+            if (connectedManager == 0) {
+                return true;
+            }
+        }
+        /*When switch is listening in passive mode, this number represent number of active connection to the device
+        This is to handle the controller initiated connection scenario, where all the controller will connect, but
+        switch will have only one manager.
+        */
+        /* CLUSTERING-TODO-ITEM: For hwvtep we don't have getNumberOfConnections()
+         * FIXME: Add it to yang?
+        if (onlyConnectedManager.getNumberOfConnections() > ONE_ACTIVE_CONNECTION_IN_PASSIVE_MODE) {
+            return false;
+        }*/
+        return true;
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepManagerUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepManagerUpdateCommand.java
new file mode 100644 (file)
index 0000000..8c8710b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+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.hardwarevtep.Manager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepManagerUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepManagerUpdateCommand.class);
+    private Map<UUID, Manager> updatedMgrRows;
+    private Map<UUID, Manager> oldMgrRows;
+
+    public HwvtepManagerUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedMgrRows = TyperUtils.extractRowsUpdated(Manager.class, getUpdates(),getDbSchema());
+        oldMgrRows = TyperUtils.extractRowsOld(Manager.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        // TODO Auto-generated method stub
+    }
+
+}
index 94116e37b6c1539789a231f58fcc71f22d236a79..b0bcdf3c0ea9f24b6caa25460fc0ec177b6bdc70 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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,
@@ -19,11 +19,24 @@ import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
 public class HwvtepOperationalCommandAggregator implements TransactionCommand {
 
 
-    private List<TransactionCommand> commands = new ArrayList<>();
+    private List<TransactionCommand> commands = new ArrayList<TransactionCommand>();
 
     public HwvtepOperationalCommandAggregator(HwvtepConnectionInstance key,TableUpdates updates,
             DatabaseSchema dbSchema) {
         //TODO: Add commands in here
+        commands.add(new GlobalUpdateCommand(key, updates, dbSchema));
+        commands.add(new PhysicalSwitchUpdateCommand(key, updates, dbSchema));
+        commands.add(new PhysicalSwitchRemoveCommand(key, updates, dbSchema));
+        commands.add(new HwvtepManagerUpdateCommand(key, updates, dbSchema));
+        commands.add(new LogicalSwitchUpdateCommand(key, updates, dbSchema));
+        commands.add(new PhysicalPortUpdateCommand(key, updates, dbSchema));
+        commands.add(new HwvtepTunnelUpdateCommand(key, updates, dbSchema));
+        commands.add(new PhysicalLocatorUpdateCommand(key, updates, dbSchema));
+        commands.add(new PhysicalLocatorSetUpdateCommand(key, updates, dbSchema));
+        commands.add(new UcastMacsLocalUpdateCommand(key, updates, dbSchema));
+        commands.add(new UcastMacsRemoteUpdateCommand(key, updates, dbSchema));
+        commands.add(new McastMacsLocalUpdateCommand(key, updates, dbSchema));
+        commands.add(new McastMacsRemoteUpdateCommand(key, updates, dbSchema));
     }
 
     @Override
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepTunnelUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepTunnelUpdateCommand.java
new file mode 100644 (file)
index 0000000..3c51cac
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+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.hardwarevtep.Tunnel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepTunnelUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepTunnelUpdateCommand.class);
+    private Map<UUID, Tunnel> updatedTunnelRows;
+    private Map<UUID, Tunnel> oldTunnelRows;
+
+    public HwvtepTunnelUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedTunnelRows = TyperUtils.extractRowsUpdated(Tunnel.class, getUpdates(),getDbSchema());
+        oldTunnelRows = TyperUtils.extractRowsOld(Tunnel.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        // TODO Auto-generated method stub
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/LogicalSwitchUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/LogicalSwitchUpdateCommand.java
new file mode 100644 (file)
index 0000000..87464cd
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+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.hardwarevtep.LogicalSwitch;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LogicalSwitchUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchUpdateCommand.class);
+    private Map<UUID, LogicalSwitch> updatedLSRows;
+    private Map<UUID, LogicalSwitch> oldLSRows;
+
+    public LogicalSwitchUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedLSRows = TyperUtils.extractRowsUpdated(LogicalSwitch.class, getUpdates(),getDbSchema());
+        oldLSRows = TyperUtils.extractRowsOld(LogicalSwitch.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        // TODO Auto-generated method stub
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/McastMacsLocalUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/McastMacsLocalUpdateCommand.java
new file mode 100644 (file)
index 0000000..06ab9e4
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+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.hardwarevtep.McastMacsLocal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class McastMacsLocalUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(McastMacsLocalUpdateCommand.class);
+    private Map<UUID, McastMacsLocal> updatedMMacsLocalRows;
+    private Map<UUID, McastMacsLocal> oldMMacsLocalRows;
+
+    public McastMacsLocalUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedMMacsLocalRows = TyperUtils.extractRowsUpdated(McastMacsLocal.class, getUpdates(),getDbSchema());
+        oldMMacsLocalRows = TyperUtils.extractRowsOld(McastMacsLocal.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        // TODO Auto-generated method stub
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/McastMacsRemoteUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/McastMacsRemoteUpdateCommand.java
new file mode 100644 (file)
index 0000000..10ec57e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+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.hardwarevtep.McastMacsRemote;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class McastMacsRemoteUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(McastMacsRemoteUpdateCommand.class);
+    private Map<UUID, McastMacsRemote> updatedMMacsRemoteRows;
+    private Map<UUID, McastMacsRemote> oldMMacsRemoteRows;
+
+    public McastMacsRemoteUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedMMacsRemoteRows = TyperUtils.extractRowsUpdated(McastMacsRemote.class, getUpdates(),getDbSchema());
+        oldMMacsRemoteRows = TyperUtils.extractRowsOld(McastMacsRemote.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        // TODO Auto-generated method stub
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalLocatorSetUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalLocatorSetUpdateCommand.java
new file mode 100644 (file)
index 0000000..9be6116
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+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.hardwarevtep.PhysicalLocatorSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PhysicalLocatorSetUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PhysicalLocatorSetUpdateCommand.class);
+    private Map<UUID, PhysicalLocatorSet> updatedPLocSetRows;
+    private Map<UUID, PhysicalLocatorSet> oldPLocSetRows;
+
+    public PhysicalLocatorSetUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedPLocSetRows = TyperUtils.extractRowsUpdated(PhysicalLocatorSet.class, getUpdates(),getDbSchema());
+        oldPLocSetRows = TyperUtils.extractRowsOld(PhysicalLocatorSet.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        // TODO Auto-generated method stub
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalLocatorUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalLocatorUpdateCommand.java
new file mode 100644 (file)
index 0000000..307da2d
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+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.hardwarevtep.PhysicalLocator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PhysicalLocatorUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PhysicalLocatorUpdateCommand.class);
+    private Map<UUID, PhysicalLocator> updatedPLocRows;
+    private Map<UUID, PhysicalLocator> oldPLocRows;
+
+    public PhysicalLocatorUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedPLocRows = TyperUtils.extractRowsUpdated(PhysicalLocator.class, getUpdates(),getDbSchema());
+        updatedPLocRows = TyperUtils.extractRowsOld(PhysicalLocator.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        // TODO Auto-generated method stub
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalPortUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalPortUpdateCommand.java
new file mode 100644 (file)
index 0000000..3585894
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+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.hardwarevtep.PhysicalPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PhysicalPortUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PhysicalPortUpdateCommand.class);
+    private Map<UUID, PhysicalPort> updatedPPRows;
+    private Map<UUID, PhysicalPort> oldPPRows;
+
+    public PhysicalPortUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedPPRows = TyperUtils.extractRowsUpdated(PhysicalPort.class, getUpdates(),getDbSchema());
+        oldPPRows = TyperUtils.extractRowsOld(PhysicalPort.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        // TODO Auto-generated method stub
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalSwitchRemoveCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalSwitchRemoveCommand.java
new file mode 100644 (file)
index 0000000..1f2a9eb
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Collection;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.Switches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.SwitchesKey;
+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;
+
+public class PhysicalSwitchRemoveCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PhysicalSwitchRemoveCommand.class);
+
+    public PhysicalSwitchRemoveCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        Collection<PhysicalSwitch> deletedPSRows = TyperUtils.extractRowsRemoved(PhysicalSwitch.class, getUpdates(),getDbSchema()).values();
+        if(deletedPSRows != null && !deletedPSRows.isEmpty()) {
+            for (PhysicalSwitch pSwitch : deletedPSRows) {
+                InstanceIdentifier<Node> nodeIid = HwvtepSouthboundMapper.createInstanceIdentifier(
+                                getOvsdbConnectionInstance(), pSwitch);
+                InstanceIdentifier<Switches> switchIid = getOvsdbConnectionInstance().getInstanceIdentifier()
+                                .augmentation(HwvtepGlobalAugmentation.class)
+                                .child(Switches.class, new SwitchesKey(new HwvtepPhysicalSwitchRef(nodeIid)));
+                        // TODO handle removal of reference to managed switch from model
+                        transaction.delete(LogicalDatastoreType.OPERATIONAL, nodeIid);
+                        transaction.delete(LogicalDatastoreType.OPERATIONAL, switchIid);
+            }
+        }
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalSwitchUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/PhysicalSwitchUpdateCommand.java
new file mode 100644 (file)
index 0000000..aef9a97
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
+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.hardwarevtep.PhysicalSwitch;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.Switches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.SwitchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIpsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.PhysicalSwitchIdBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIpsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelsBuilder;
+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.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class PhysicalSwitchUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PhysicalSwitchUpdateCommand.class);
+    private Map<UUID, PhysicalSwitch> updatedPSRows;
+    private Map<UUID, PhysicalSwitch> oldPSRows;
+
+    public PhysicalSwitchUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedPSRows = TyperUtils.extractRowsUpdated(PhysicalSwitch.class, getUpdates(),getDbSchema());
+        oldPSRows = TyperUtils.extractRowsOld(PhysicalSwitch.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        if(updatedPSRows != null && !updatedPSRows.isEmpty()) {
+            for (Entry<UUID, PhysicalSwitch> entry : updatedPSRows.entrySet()) {
+                updatePhysicalSwitch(transaction, entry.getValue());
+            }
+        }
+    }
+
+    private void updatePhysicalSwitch(ReadWriteTransaction transaction, PhysicalSwitch pSwitch) {
+        final InstanceIdentifier<Node> connectionIId = getOvsdbConnectionInstance().getInstanceIdentifier();
+        Optional<Node> connection = HwvtepSouthboundUtil.readNode(transaction, connectionIId);
+        if (connection.isPresent()) {
+            LOG.debug("Connection {} is present",connection);
+            // Update the connection node to let it know it manages this Physical Switch
+            Node connectionNode = buildConnectionNode(pSwitch);
+            transaction.merge(LogicalDatastoreType.OPERATIONAL, connectionIId, connectionNode);
+
+            // Update the Physical Switch with whatever data we are getting
+            InstanceIdentifier<Node> psIid = getInstanceIdentifier(pSwitch);
+            Node psNode = buildPhysicalSwitchNode(pSwitch);
+            transaction.merge(LogicalDatastoreType.OPERATIONAL, psIid, psNode);
+//            TODO: Delete entries that are no longer needed
+        }
+    }
+
+    private Node buildPhysicalSwitchNode(PhysicalSwitch pSwitch) {
+        NodeBuilder psNodeBuilder = new NodeBuilder();
+        NodeId psNodeId = getNodeId(pSwitch);
+        psNodeBuilder.setNodeId(psNodeId);
+        PhysicalSwitchAugmentationBuilder psAugmentationBuilder = new PhysicalSwitchAugmentationBuilder();
+        setManagedBy(psAugmentationBuilder, pSwitch);
+        setPhysicalSwitchId(psAugmentationBuilder, pSwitch);
+        setManagementIps(psAugmentationBuilder, pSwitch);
+        setTunnelIps(psAugmentationBuilder, pSwitch);
+        setUcastMacsLocal(psAugmentationBuilder, pSwitch);
+        setUcastMacsRemote(psAugmentationBuilder, pSwitch);
+        setMcastMacsLocal(psAugmentationBuilder, pSwitch);
+        setMcastMacsRemote(psAugmentationBuilder, pSwitch);
+
+        psNodeBuilder.addAugmentation(PhysicalSwitchAugmentation.class, psAugmentationBuilder.build());
+
+        LOG.trace("Built with the intent to store bridge data {}",
+                psAugmentationBuilder.build());
+        return psNodeBuilder.build();
+    }
+
+    private void setManagedBy(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
+        InstanceIdentifier<Node> connectionNodePath = getOvsdbConnectionInstance().getInstanceIdentifier();
+        psAugmentationBuilder.setManagedBy(new HwvtepGlobalRef(connectionNodePath));
+    }
+
+    private void setPhysicalSwitchId(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
+        PhysicalSwitchIdBuilder psIdBuilder = new PhysicalSwitchIdBuilder();
+        if(pSwitch.getName() != null) {
+            psIdBuilder.setHwvtepNodeName(new HwvtepNodeName(pSwitch.getName()));
+        }
+
+        if(pSwitch.getDescription() != null) {
+            psIdBuilder.setHwvtepNodeDescription(pSwitch.getDescription());
+        }
+        psAugmentationBuilder.setPhysicalSwitchId(psIdBuilder.build());
+    }
+
+    private void setManagementIps(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
+        if(pSwitch.getManagementIpsColumn() != null 
+                && pSwitch.getManagementIpsColumn().getData() != null
+                && !pSwitch.getManagementIpsColumn().getData().isEmpty() ) {
+            List<ManagementIps> mgmtIps = new ArrayList<>();
+            for(String mgmtIp: pSwitch.getManagementIpsColumn().getData()) {
+                IpAddress ip = new IpAddress(mgmtIp.toCharArray());
+                mgmtIps.add(new ManagementIpsBuilder()
+                        .setKey(new ManagementIpsKey(ip))
+                        .setManagementIpsKey(ip)
+                        .build());
+            }
+            psAugmentationBuilder.setManagementIps(mgmtIps);
+        }
+    }
+
+    private void setTunnelIps(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
+        if(pSwitch.getTunnelIpsColumn() != null
+            && pSwitch.getTunnelIpsColumn().getData() != null
+            && !pSwitch.getTunnelIpsColumn().getData().isEmpty()) {
+            List<TunnelIps> tunnelIps = new ArrayList<>();
+            for(String tunnelIp: pSwitch.getTunnelIpsColumn().getData()) {
+                IpAddress ip = new IpAddress(tunnelIp.toCharArray());
+                tunnelIps.add(new TunnelIpsBuilder()
+                        .setKey(new TunnelIpsKey(ip))
+                        .setTunnelIpsKey(ip)
+                        .build());
+            }
+            psAugmentationBuilder.setTunnelIps(tunnelIps);
+        }
+    }
+
+    private void setUcastMacsLocal(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    private void setUcastMacsRemote(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    private void setMcastMacsLocal(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    private void setMcastMacsRemote(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    private Node buildConnectionNode(PhysicalSwitch pSwitch) {
+        //Update node with PhysicalSwitch reference
+        NodeBuilder connectionNode = new NodeBuilder();
+        connectionNode.setNodeId(getOvsdbConnectionInstance().getNodeId());
+
+        HwvtepGlobalAugmentationBuilder hgAugmentationBuilder = new HwvtepGlobalAugmentationBuilder();
+        List<Switches> switches = new ArrayList<>();
+        InstanceIdentifier<Node> switchIid = HwvtepSouthboundMapper.createInstanceIdentifier(getOvsdbConnectionInstance(),
+                        pSwitch);
+        hgAugmentationBuilder.setSwitches(switches);
+        Switches physicalSwitch = new SwitchesBuilder().setSwitchRef(
+                        new HwvtepPhysicalSwitchRef(switchIid)).build(); 
+        switches.add(physicalSwitch);
+
+        connectionNode.addAugmentation(HwvtepGlobalAugmentation.class, hgAugmentationBuilder.build());
+
+        LOG.debug("Update node with physicalswitch ref {}",
+                hgAugmentationBuilder.getSwitches().iterator().next());
+        return connectionNode.build();
+    }
+
+    private InstanceIdentifier<Node> getInstanceIdentifier(PhysicalSwitch pSwitch) {
+        return HwvtepSouthboundMapper.createInstanceIdentifier(getOvsdbConnectionInstance(),
+                pSwitch);
+    }
+
+    private NodeId getNodeId(PhysicalSwitch pSwitch) {
+        NodeKey nodeKey = getInstanceIdentifier(pSwitch).firstKeyOf(Node.class, NodeKey.class);
+        return nodeKey.getNodeId();
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/UcastMacsLocalUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/UcastMacsLocalUpdateCommand.java
new file mode 100644 (file)
index 0000000..3971ccc
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+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.hardwarevtep.UcastMacsLocal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UcastMacsLocalUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UcastMacsLocalUpdateCommand.class);
+    private Map<UUID, UcastMacsLocal> updatedUMacsLocalRows;
+    private Map<UUID, UcastMacsLocal> oldUMacsLocalRows;
+
+    public UcastMacsLocalUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedUMacsLocalRows = TyperUtils.extractRowsUpdated(UcastMacsLocal.class, getUpdates(),getDbSchema());
+        oldUMacsLocalRows = TyperUtils.extractRowsOld(UcastMacsLocal.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        // TODO Auto-generated method stub
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/UcastMacsRemoteUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/UcastMacsRemoteUpdateCommand.java
new file mode 100644 (file)
index 0000000..cac4a0a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.hwvtepsouthbound.transactions.md;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+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.hardwarevtep.UcastMacsRemote;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UcastMacsRemoteUpdateCommand extends AbstractTransactionCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UcastMacsRemoteUpdateCommand.class);
+    private Map<UUID, UcastMacsRemote> updatedUMacsRemoteRows;
+    private Map<UUID, UcastMacsRemote> oldUMacsRemoteRows;
+
+    public UcastMacsRemoteUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedUMacsRemoteRows = TyperUtils.extractRowsUpdated(UcastMacsRemote.class, getUpdates(),getDbSchema());
+        oldUMacsRemoteRows = TyperUtils.extractRowsOld(UcastMacsRemote.class, getUpdates(),getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        // TODO Auto-generated method stub
+    }
+
+}
index 55ec29e66c51539956f43a7e0d5943a6f50db94f..ecdbc05614ec4d210dda74a6b0d2bf653d10e7c0 100644 (file)
@@ -21,7 +21,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <maven>3.1.1</maven>
   </prerequisites>
   <properties>
-    <karaf.localFeature>odl-hwvtepsouthbound-ui</karaf.localFeature>
+    <karaf.localFeature>odl-ovsdb-hwvtepsouthbound-ui</karaf.localFeature>
   </properties>
   <dependencyManagement>
     <dependencies>
index a358245e037e934ed321ee8ef4e3143171a75f04..3f710d00f7edb6e706fb28e42b114e266f2bfe04 100644 (file)
@@ -24,19 +24,8 @@ public class SchemaVersionMismatchException extends RuntimeException {
         super(message, cause);
     }
 
-    public static String createMessage(Version currentVersion, Version requiredVersion) {
-        String message =
-                "The schema version used to access this Table/Column does not match the required version.\n"
-                + "Current Version: " + currentVersion.toString() + "\n";
-
-        if (currentVersion.compareTo(requiredVersion) > 1) {
-            message += "Removed in Version: " + requiredVersion.toString();
-
-        } else {
-            message += "Added in Version: " + requiredVersion.toString();
-
-        }
-
-        return message;
+    public SchemaVersionMismatchException(Version schemaVersion, Version fromVersion, Version untilVersion) {
+        this("The schema version used to access the table/column (" + schemaVersion + ") does not match the required " +
+                "version (from " + fromVersion + " to " + untilVersion + ")");
     }
 }
index 0932d95467db307652e577897e29edf4a482f8b6..8c9adceb13ac728e568129742912f6a9d4058b69 100644 (file)
@@ -196,13 +196,9 @@ public class TyperUtils {
     }
 
     private static void checkVersion(Version schemaVersion, Version fromVersion, Version untilVersion) {
-        if (!fromVersion.equals(Version.NULL) && schemaVersion.compareTo(fromVersion) < 0) {
-            String message = SchemaVersionMismatchException.createMessage(schemaVersion, fromVersion);
-            throw new SchemaVersionMismatchException(message);
-        }
-        if (!untilVersion.equals(Version.NULL) && schemaVersion.compareTo(untilVersion) > 0) {
-            String message = SchemaVersionMismatchException.createMessage(schemaVersion, untilVersion);
-            throw new SchemaVersionMismatchException(message);
+        if ((!fromVersion.equals(Version.NULL) && schemaVersion.compareTo(fromVersion) < 0) || (!untilVersion.equals(
+                Version.NULL) && schemaVersion.compareTo(untilVersion) > 0)) {
+            throw new SchemaVersionMismatchException(schemaVersion, fromVersion, untilVersion);
         }
     }
 
index 15785f62e3fcc4bca0009ad237dcb87bbd70a9b3..d7dfe6789537dfd29cd1cecce75aeb725498aede 100644 (file)
@@ -470,18 +470,12 @@ public class OpenVSwitchIT extends LibraryIntegrationTestBase {
         bridgeDelete(testBridgeUuid);
     }
 
-    @Test
+    @Test(expected = SchemaVersionMismatchException.class)
     public void testFlowSampleCollectorSetTableNotSupported () {
         // Don't run this test if the table is not supported
         assumeTrue(schemaVersion.compareTo(flowSampleCollectorSetFromVersion) < 0);
 
-        boolean isExceptionRaised = false;
-        try {
-            getClient().createTypedRowWrapper(FlowSampleCollectorSet.class);
-        } catch (SchemaVersionMismatchException e) {
-            isExceptionRaised = true;
-        }
-        assertTrue(isExceptionRaised);
+        getClient().createTypedRowWrapper(FlowSampleCollectorSet.class);
     }
 
     public void flowSampleCollectorSetInsert () throws ExecutionException, InterruptedException {
@@ -540,18 +534,12 @@ public class OpenVSwitchIT extends LibraryIntegrationTestBase {
         bridgeDelete(testBridgeUuid);
     }
 
-    @Test
+    @Test(expected = SchemaVersionMismatchException.class)
     public void testFlowTableTableNotSupported () {
         // Don't run this test if the table is not supported
         assumeTrue(schemaVersion.compareTo(flowTableFromVersion) < 0);
 
-        boolean isExceptionRaised = false;
-        try {
-            getClient().createTypedRowWrapper(FlowTable.class);
-        } catch (SchemaVersionMismatchException e) {
-            isExceptionRaised = true;
-        }
-        assertTrue(isExceptionRaised);
+        getClient().createTypedRowWrapper(FlowTable.class);
     }
 
     public void flowTableInsert () throws ExecutionException, InterruptedException {
@@ -632,18 +620,12 @@ public class OpenVSwitchIT extends LibraryIntegrationTestBase {
         bridgeDelete(testBridgeUuid);
     }
 
-    @Test
+    @Test(expected = SchemaVersionMismatchException.class)
     public void testIpfixTableNotSupported () {
         // Don't run this test if the table is not supported
         assumeTrue(schemaVersion.compareTo(ipfixFromVersion) < 0);
 
-        boolean isExceptionRaised = false;
-        try {
-            getClient().createTypedRowWrapper(IPFIX.class);
-        } catch (SchemaVersionMismatchException e) {
-            isExceptionRaised = true;
-        }
-        assertTrue(isExceptionRaised);
+        getClient().createTypedRowWrapper(IPFIX.class);
     }
 
     public void ipfixInsert () throws ExecutionException, InterruptedException {
index 5d29699642b10458b0e7754f1044735493faf472..c49173d9d6a6dc13a85089086641c1cb11ebae89 100644 (file)
@@ -7,11 +7,16 @@
  */
 package org.opendaylight.ovsdb.openstack.netvirt.it;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 import static org.ops4j.pax.exam.CoreOptions.composite;
 import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
 import static org.ops4j.pax.exam.CoreOptions.vmOption;
 import static org.ops4j.pax.exam.CoreOptions.when;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
@@ -26,6 +31,7 @@ import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
 import javax.inject.Inject;
@@ -37,10 +43,17 @@ import org.junit.runner.RunWith;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
+import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 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.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs;
@@ -124,6 +137,10 @@ public class NetvirtIT extends AbstractMdsalTestBase {
 
     private Option[] getOtherOptions() {
         return new Option[] {
+                wrappedBundle(
+                        mavenBundle("org.opendaylight.ovsdb", "utils.mdsal-openflow")
+                                .version(asInProject())
+                                .type("jar")),
                 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
                 keepRuntimeFolder()
         };
@@ -677,8 +694,34 @@ public class NetvirtIT extends AbstractMdsalTestBase {
     @Test
     public void testNetVirt() throws InterruptedException {
         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
-        connectOvsdbNode(connectionInfo);
+        Node ovsdbNode = connectOvsdbNode(connectionInfo);
+
         Thread.sleep(10000);
+        // Verify the pipeline flows were installed
+        PipelineOrchestrator pipelineOrchestrator =
+                (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
+        assertNotNull("Could not find PipelineOrchestrator Service", pipelineOrchestrator);
+        Node bridgeNode = southbound.getBridgeNode(ovsdbNode, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
+        assertNotNull("bridge " + NetvirtITConstants.INTEGRATION_BRIDGE_NAME + " was not found", bridgeNode);
+        long datapathId = southbound.getDataPathId(bridgeNode);
+        org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
+                FlowUtils.createNodeBuilder(datapathId);
+
+        List<Service> staticPipeline = pipelineOrchestrator.getStaticPipeline();
+        List<Service> staticPipelineFound = Lists.newArrayList();
+        for (Service service : pipelineOrchestrator.getServiceRegistry().keySet()) {
+            if (staticPipeline.contains(service)) {
+                staticPipelineFound.add(service);
+            }
+            FlowBuilder flowBuilder = FlowUtils.getPipelineFlow(service.getTable(), (short)0);
+            Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+            assertNotNull("Could not find flow in config", flow);
+            flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+            assertNotNull("Could not find flow in operational", flow);
+        }
+        assertEquals("did not find all expected flows in static pipeline",
+                staticPipeline.size(), staticPipelineFound.size());
+
         netVirtAddPort(connectionInfo);
         Thread.sleep(10000);
         Assert.assertTrue(deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
@@ -700,4 +743,22 @@ public class NetvirtIT extends AbstractMdsalTestBase {
             LOG.info(">>>>> node: {}", node);
         }
     }
+
+    private Flow getFlow (
+            FlowBuilder flowBuilder,
+            org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder,
+            LogicalDatastoreType store)
+            throws InterruptedException {
+
+        Flow flow = null;
+        for (int i = 0; i < 10; i++) {
+            flow = FlowUtils.getFlow(flowBuilder, nodeBuilder, dataBroker.newReadOnlyTransaction(), store);
+            if (flow != null) {
+                LOG.info("getFlow: flow({}): {}", store, flow);
+                break;
+            }
+            Thread.sleep(1000);
+        }
+        return flow;
+    }
 }
index 76ca876bdd34368c4b7c57b54e54730bf4038838..dfef38d55431f8a6c579369b2f1f57ce9b3381d7 100644 (file)
@@ -259,7 +259,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <Embed-Dependency>utils.config,utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
             <Embed-Transitive>true</Embed-Transitive>
             <Export-Package>
-              org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.*
+              org.opendaylight.ovsdb.openstack.netvirt.providers,
+              org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13
             </Export-Package>
           </instructions>
         </configuration>
index e6e0fd0396bf0a638685381f762206ec73d015ec..6f8a19728298cec71d23d9fdeb0e77af6ad60d2d 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
 
+import java.util.List;
+import java.util.Map;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.osgi.framework.ServiceReference;
 
@@ -21,6 +23,8 @@ import org.osgi.framework.ServiceReference;
 public interface PipelineOrchestrator {
     Service getNextServiceInPipeline(Service service);
     AbstractServiceInstance getServiceInstance(Service service);
+    Map<Service, AbstractServiceInstance> getServiceRegistry();
+    List<Service> getStaticPipeline();
     void enqueue(Node node);
     void registerService(final ServiceReference ref, AbstractServiceInstance serviceInstance);
     void unregisterService(final ServiceReference ref);
index edea48c26cdc122d5e2c6cbd29dd478f62e90075..299ab21a08b76f4261a5fceee18f5e49cf8c7046 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.BlockingQueue;
@@ -32,6 +33,11 @@ import com.google.common.collect.Maps;
 
 public class PipelineOrchestratorImpl implements ConfigInterface, NodeCacheListener, PipelineOrchestrator {
     private static final Logger LOG = LoggerFactory.getLogger(PipelineOrchestratorImpl.class);
+
+    public List<Service> getStaticPipeline() {
+        return staticPipeline;
+    }
+
     private List<Service> staticPipeline = Lists.newArrayList(
             Service.CLASSIFIER,
             Service.ARP_RESPONDER,
@@ -45,6 +51,11 @@ public class PipelineOrchestratorImpl implements ConfigInterface, NodeCacheListe
             Service.OUTBOUND_NAT,
             Service.L2_FORWARDING
     );
+
+    public Map<Service, AbstractServiceInstance> getServiceRegistry() {
+        return serviceRegistry;
+    }
+
     Map<Service, AbstractServiceInstance> serviceRegistry = Maps.newConcurrentMap();
     private volatile BlockingQueue<Node> queue;
     private ExecutorService eventHandler;
@@ -61,6 +72,23 @@ public class PipelineOrchestratorImpl implements ConfigInterface, NodeCacheListe
         Service service = (Service)ref.getProperty(AbstractServiceInstance.SERVICE_PROPERTY);
         LOG.info("registerService {} - {}", serviceInstance, service);
         serviceRegistry.put(service, serviceInstance);
+        // insert the service if not already there. The list is ordered based of table ID.
+        if (!staticPipeline.contains(service) && !isTableInPipeline(service.getTable())) {
+            staticPipeline.add(service);
+            Collections.sort(staticPipeline, Service.insertComparator);
+        }
+        LOG.info("registerService: {}", staticPipeline);
+    }
+
+    private boolean isTableInPipeline (short tableId) {
+        boolean found = false;
+        for (Service service : staticPipeline) {
+            if (service.getTable() == tableId) {
+                found = true;
+                break;
+            }
+        }
+        return found;
     }
 
     public void unregisterService(final ServiceReference ref) {
index badde08175e9c141537f22272ccfa90165642459..25177441218ed005b4c4788254738b7c1bb0608a 100644 (file)
@@ -8,11 +8,14 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
 
+import java.util.Comparator;
+
 public enum Service {
 
     CLASSIFIER ((short) 0, "Classifier"),
     GATEWAY_RESOLVER((short) 0, "External Network Gateway Resolver"),
     DIRECTOR ((short) 10, "Director"),
+    SFC_CLASSIFIER ((short) 10, "SFC Classifier"),
     ARP_RESPONDER ((short) 20, "Distributed ARP Responder"),
     INBOUND_NAT ((short) 30, "DNAT for inbound floating-ip traffic"),
     EGRESS_ACL ((short) 40, "Egress Acces-control"),
@@ -39,4 +42,12 @@ public enum Service {
     public String getDescription() {
         return description;
     }
+
+    public static Comparator<Service> insertComparator = new Comparator<Service>() {
+
+        @Override
+        public int compare(Service service1, Service service2) {
+            return service1.getTable() - service2.getTable();
+        }
+    };
 }
index 5de7118017f750fe19df1da89a6eef515998ca86..350f9cf478e18d8c3543449ca71d3adf8cffbbc4 100644 (file)
@@ -83,6 +83,13 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
              * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
              *
              */
+
+            if (portSecurityRule == null ||
+                    portSecurityRule.getSecurityRuleEthertype() == null ||
+                    portSecurityRule.getSecurityRuleDirection() == null) {
+                continue;
+            }
+
             if ("IPv4".equals(portSecurityRule.getSecurityRuleEthertype())
                     && portSecurityRule.getSecurityRuleDirection().equals("egress")) {
                 LOG.debug("programPortSecurityGroup: Acl Rule matching IPv4 and ingress is: {} ", portSecurityRule);
@@ -149,13 +156,51 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                                 Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
                   break;
               default:
-                  LOG.error("programPortSecurityRule: Protocol not supported", portSecurityRule);
+                  LOG.info("programPortSecurityAcl: Protocol is not TCP/UDP/ICMP but other " +
+                          "protocol = ", portSecurityRule.getSecurityRuleProtocol());
+                  egressOtherProtocolAclHandler(dpid, segmentationId, attachedMac,
+                                      portSecurityRule, ipaddress, write,
+                                      Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
                   break;
             }
         }
 
     }
 
+    private void egressOtherProtocolAclHandler(Long dpidLong, String segmentationId, String srcMac,
+         NeutronSecurityRule portSecurityRule, String dstAddress,
+         boolean write, Integer protoPortMatchPriority) {
+
+         MatchBuilder matchBuilder = new MatchBuilder();
+         String flowId = "Egress_Other_" + segmentationId + "_" + srcMac + "_";
+         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
+
+         short proto = 0;
+         try {
+             Integer protocol = new Integer(portSecurityRule.getSecurityRuleProtocol());
+             proto = protocol.shortValue();
+             flowId = flowId + proto;
+         } catch (NumberFormatException e) {
+             LOG.error("Protocol vlaue conversion failure", e);
+         }
+         matchBuilder = MatchUtils.createIpProtocolMatch(matchBuilder, proto);
+
+         if (null != dstAddress) {
+             flowId = flowId + dstAddress;
+             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
+                                                         MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
+
+         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,new Ipv4Prefix(portSecurityRule
+                                                                        .getSecurityRuleRemoteIpPrefix()));
+         }
+         flowId = flowId + "_Permit";
+         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+ }
+
     @Override
     public void programFixedSecurityGroup(Long dpid, String segmentationId, String attachedMac,
                                         long localPort, List<Neutron_IPs> srcAddressList,
@@ -224,7 +269,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
             if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
                     && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
-                    + portSecurityRule.getSecurityRulePortMax() + "_";
+                            + portSecurityRule.getSecurityRulePortMax() + "_";
                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
             }
             /*TODO TCP PortRange Match*/
@@ -234,13 +279,12 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
         if (null != dstAddress) {
             flowId = flowId + dstAddress;
             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
-                                                        MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
+                                      MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
 
         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
-                                                        new Ipv4Prefix(portSecurityRule
-                                                                       .getSecurityRuleRemoteIpPrefix()));
+                                      new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
         }
         flowId = flowId + "_Permit";
         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
@@ -264,14 +308,23 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
     private void egressAclIcmp(Long dpidLong, String segmentationId, String srcMac,
                                NeutronSecurityRule portSecurityRule, String dstAddress,
                                boolean write, Integer protoPortMatchPriority) {
+
         MatchBuilder matchBuilder = new MatchBuilder();
-        String flowId = "Egress_ICMP_" + segmentationId + "_" + srcMac + "_"
-                    + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
-                    + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
+        String flowId = "Egress_ICMP_" + segmentationId + "_" + srcMac + "_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
-        matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
-                                                    portSecurityRule.getSecurityRulePortMin().shortValue(),
-                                                    portSecurityRule.getSecurityRulePortMax().shortValue());
+        /*Custom ICMP Match */
+        if (portSecurityRule.getSecurityRulePortMin() != null &&
+                             portSecurityRule.getSecurityRulePortMax() != null) {
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
+                    + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
+            matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
+                    portSecurityRule.getSecurityRulePortMin().shortValue(),
+                    portSecurityRule.getSecurityRulePortMax().shortValue());
+        } else {
+            /* All ICMP Match */ // We are getting from neutron NULL for both min and max
+            flowId = flowId + "all" + "_" ;
+            matchBuilder = MatchUtils.createICMPv4Match(matchBuilder, MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
+        }
         if (null != dstAddress) {
             flowId = flowId + dstAddress;
             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
index 581eb9d69ba91b3e987f145bfe6a0040689cff79..d100f4e6daf96205aeae722195e0f07623a382e6 100644 (file)
@@ -85,6 +85,12 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
              *
              */
 
+            if (portSecurityRule == null ||
+                    portSecurityRule.getSecurityRuleEthertype() == null ||
+                    portSecurityRule.getSecurityRuleDirection() == null) {
+                continue;
+            }
+
             if ("IPv4".equals(portSecurityRule.getSecurityRuleEthertype())
                     && "ingress".equals(portSecurityRule.getSecurityRuleDirection())) {
                 LOG.debug("programPortSecurityGroup: Rule matching IPv4 and ingress is: {} ", portSecurityRule);
@@ -114,9 +120,6 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                     securityGroupCacheManger.portRemoved(securityGroup.getSecurityGroupUUID(), portUuid);
                 }
             }
-
-
-
         }
     }
 
@@ -149,12 +152,46 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                                  write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
                   break;
               default:
-                  LOG.error("programPortSecurityRule: Protocol not supported", portSecurityRule);
+                  LOG.info("programPortSecurityAcl: Protocol is not TCP/UDP/ICMP but other " +
+                          "protocol = ", portSecurityRule.getSecurityRuleProtocol());
+                  ingressOtherProtocolAclHandler(dpid, segmentationId, attachedMac, portSecurityRule,
+                              null, write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
                   break;
             }
         }
     }
 
+    private void ingressOtherProtocolAclHandler(Long dpidLong, String segmentationId, String dstMac,
+          NeutronSecurityRule portSecurityRule, String srcAddress,
+          boolean write, Integer protoPortMatchPriority) {
+
+          MatchBuilder matchBuilder = new MatchBuilder();
+          String flowId = "Ingress_Other_" + segmentationId + "_" + dstMac + "_";
+          matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
+          short proto = 0;
+          try {
+              Integer protocol = new Integer(portSecurityRule.getSecurityRuleProtocol());
+              proto = protocol.shortValue();
+              flowId = flowId + proto;
+          } catch (NumberFormatException e) {
+              LOG.error("Protocol vlaue conversion failure", e);
+          }
+          matchBuilder = MatchUtils.createIpProtocolMatch(matchBuilder, proto);
+          if (null != srcAddress) {
+              flowId = flowId + srcAddress;
+              matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                                        MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
+          } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
+              flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
+              matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                                        new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
+          }
+          String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+          NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+          flowId = flowId + "_Permit";
+          syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+    }
+
     @Override
     public void programFixedSecurityGroup(Long dpid, String segmentationId, String dhcpMacAddress,
                                         long localPort, boolean isLastPortinSubnet,
@@ -311,14 +348,22 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                                 boolean write, Integer protoPortMatchPriority) {
 
         MatchBuilder matchBuilder = new MatchBuilder();
-        FlowBuilder flowBuilder = new FlowBuilder();
-        String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_"
-                + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
-                + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
+        String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
-        matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
-                                                    portSecurityRule.getSecurityRulePortMin().shortValue(),
-                                                    portSecurityRule.getSecurityRulePortMax().shortValue());
+
+        /* Custom ICMP Match */
+        if (portSecurityRule.getSecurityRulePortMin() != null &&
+                portSecurityRule.getSecurityRulePortMax() != null) {
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
+                    + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
+            matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
+                    portSecurityRule.getSecurityRulePortMin().shortValue(),
+                    portSecurityRule.getSecurityRulePortMax().shortValue());
+        } else {
+            /* All ICMP Match */
+            flowId = flowId + "all" + "_";
+            matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
+        }
         if (null != srcAddress) {
             flowId = flowId + srcAddress;
             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
index f1654266de348eb4871d83069cd761787adf0617..c21b60fa0bbde363e34bdfde92fe71e68db7dfed 100644 (file)
@@ -266,6 +266,43 @@ public class EgressAclServiceTest {
         verify(commitFuture, times(1)).get();
     }
 */
+    /**
+     * Test method {@link EgressAclService#programPortSecurityGroup(java.lang.Long, java.lang.String,
+     * java.lang.String, long, org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup,
+     * java.lang.String, boolean)} when portSecurityRule is incomplete
+     */
+    @Test
+    public void testProgramPortSecurityGroupWithIncompleteRule() throws Exception {
+        NeutronSecurityRule portSecurityRule1 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule1.getSecurityRuleEthertype()).thenReturn("IPv4");
+        when(portSecurityRule1.getSecurityRuleDirection()).thenReturn("not_egress");  // other direction
+
+        NeutronSecurityRule portSecurityRule2 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule2.getSecurityRuleEthertype()).thenReturn(null);
+        when(portSecurityRule2.getSecurityRuleDirection()).thenReturn("egress");
+
+        NeutronSecurityRule portSecurityRule3 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule3.getSecurityRuleEthertype()).thenReturn("IPv4");
+        when(portSecurityRule3.getSecurityRuleDirection()).thenReturn(null);
+
+        NeutronSecurityRule portSecurityRule4 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule4.getSecurityRuleEthertype()).thenReturn(null);
+        when(portSecurityRule4.getSecurityRuleDirection()).thenReturn(null);
+
+        List<NeutronSecurityRule> portSecurityList = new ArrayList<>();
+        portSecurityList.add(null);
+        portSecurityList.add(portSecurityRule1);
+        portSecurityList.add(portSecurityRule2);
+        portSecurityList.add(portSecurityRule3);
+        portSecurityList.add(portSecurityRule4);
+
+        NeutronSecurityGroup localSecurityGroup = mock(NeutronSecurityGroup.class);
+        when(localSecurityGroup.getSecurityRules()).thenReturn(portSecurityList);
+
+        egressAclServiceSpy.programPortSecurityGroup(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT,
+                localSecurityGroup, PORT_UUID, true);
+    }
+
     /**
      * Test method {@link EgressAclService#egressACLDefaultTcpDrop(Long, String, String, int, boolean)}
      */
index f617990b578ac755d0f23340f66071723ad9d5d6..e2b41f68bcdb995d3d02cb121a023a36e94802af 100644 (file)
@@ -269,6 +269,43 @@ public class IngressAclServiceTest {
         verify(commitFuture, times(1)).get();
     }
 */
+    /**
+     * Test method {@link EgressAclService#programPortSecurityGroup(java.lang.Long, java.lang.String,
+     * java.lang.String, long, org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup,
+     * java.lang.String, boolean)} when portSecurityRule is incomplete
+     */
+    @Test
+    public void testProgramPortSecurityGroupWithIncompleteRule() throws Exception {
+        NeutronSecurityRule portSecurityRule1 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule1.getSecurityRuleEthertype()).thenReturn("IPv4");
+        when(portSecurityRule1.getSecurityRuleDirection()).thenReturn("not_ingress");  // other direction
+
+        NeutronSecurityRule portSecurityRule2 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule2.getSecurityRuleEthertype()).thenReturn(null);
+        when(portSecurityRule2.getSecurityRuleDirection()).thenReturn("ingress");
+
+        NeutronSecurityRule portSecurityRule3 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule3.getSecurityRuleEthertype()).thenReturn("IPv4");
+        when(portSecurityRule3.getSecurityRuleDirection()).thenReturn(null);
+
+        NeutronSecurityRule portSecurityRule4 = mock(NeutronSecurityRule.class);
+        when(portSecurityRule4.getSecurityRuleEthertype()).thenReturn(null);
+        when(portSecurityRule4.getSecurityRuleDirection()).thenReturn(null);
+
+        List<NeutronSecurityRule> portSecurityList = new ArrayList<>();
+        portSecurityList.add(null);
+        portSecurityList.add(portSecurityRule1);
+        portSecurityList.add(portSecurityRule2);
+        portSecurityList.add(portSecurityRule3);
+        portSecurityList.add(portSecurityRule4);
+
+        NeutronSecurityGroup localSecurityGroup = mock(NeutronSecurityGroup.class);
+        when(localSecurityGroup.getSecurityRules()).thenReturn(portSecurityList);
+
+        ingressAclServiceSpy.programPortSecurityGroup(
+                Long.valueOf(1554), "2", MAC_ADDRESS, 124, localSecurityGroup, PORT_UUID, false);
+    }
+
     /**
      *  Test IPv4 add test case.
      */
index c01db2bc0c15d7b4ddbef284e30952252a5cc1c6..75049d0d0e309d3f466bae15a6b5206749848ece 100644 (file)
@@ -57,11 +57,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <Export-Package>
               org.opendaylight.yang.gen.v1.*,
               org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105,
-              org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.*,
               org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105,
-              org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.*,
               org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105,
-              org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.*
             </Export-Package>
           </instructions>
         </configuration>
index 31d1e1d867e9b727f259cb1daab7ae3e9269056e..44fa5a1847ce303d084f01e108f6af4c3ee190fb 100644 (file)
@@ -10,7 +10,6 @@ module netvirt-sfc-acl {
         description "Initial revision of netvirt extensions to ietf-acl model";
     }
 
-    // TODO: Add choice for Neutron and add fields there instead of at the root of matches
   //augment "/ietf-acl:access-lists/ietf-acl:access-list/ietf-acl:access-list-entries/ietf-acl:access-list-entry/ietf-acl:matches" {
     augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:matches" {
         description "Neutron network uuid";
@@ -20,11 +19,16 @@ module netvirt-sfc-acl {
         }
     }
 
-    // TODO: Add choice for Neutron and add fields there instead of at the root of matches
     augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:actions" {
-        description "Redirect traffic to SFC identified by SFC Path ID";
+        description "Redirect traffic to SFC identified by either SFC, SFP or RSP";
         ext:augment-identifier "redirect-to-sfc";
-        leaf redirect-sfc {
+        leaf sfc-name {
+            type string;
+        }
+        leaf sfp-name {
+            type string;
+        }
+        leaf rsp-name {
             type string;
         }
     }
index df4dd39e8d6351807116f2baf8a56bd54702960b..5e01309128afde1990aa54d2e891ba0da8875c7a 100644 (file)
@@ -38,6 +38,12 @@ module netvirt-sfc-classifier {
                     leaf name {
                         type string;
                     }
+                    leaf direction {
+                        type enumeration {
+                            enum ingress;
+                            enum egress;
+                        }
+                    }
                 }
             }
         }
index ba405df726bf5fa56275456d900688f4c5268b6d..684d59a55fb868a9aad0b34cb11d748f57a384a3 100644 (file)
@@ -130,22 +130,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.sfc</groupId>
-      <artifactId>features-sfc-ovs</artifactId>
-      <version>${sfc.version}</version>
-      <classifier>features</classifier>
-      <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.sfc</groupId>
-      <artifactId>features-sfcofl2</artifactId>
-      <version>${sfc.version}</version>
-      <classifier>features</classifier>
-      <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>openstack.net-virt-sfc-impl</artifactId>
index dc73264661f7aed2efd1d5d082424ad56bfe96fb..cf65c97d01e51c7b60c99f6b5455f1021a1be0cc 100644 (file)
@@ -19,8 +19,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <repository>mvn:org.opendaylight.ovsdb/features-ovsdb/${project.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.ovsdb/southbound-features/${project.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.sfc/features-sfc/${sfc.version}/xml/features</repository>
-  <!--<repository>mvn:org.opendaylight.sfc/features-sfc-ovs/${sfc.version}/xml/features</repository>-->
-  <repository>mvn:org.opendaylight.sfc/features-sfcofl2/${sfc.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
   <feature name='odl-ovsdb-sfc-api' version='${project.version}' description='OpenDaylight :: ovsdb-sfc :: api'>
     <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
index 690626c9b060fb9350f9e07a8474b08e0f79b320..27c3ab73097acb581025a68ff1aa9b0227f6262c 100644 (file)
@@ -27,6 +27,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <properties>
     <networkconfig.neutron.version>0.6.0-SNAPSHOT</networkconfig.neutron.version>
     <openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
+    <powermock.version>1.5.2</powermock.version>
     <sonar.jacoco.itReportPath>../it/target/jacoco-it.exec</sonar.jacoco.itReportPath>
     <sfc.project.version>0.2.0-SNAPSHOT</sfc.project.version>
   </properties>
@@ -47,11 +48,16 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>openstack.net-virt-providers</artifactId>
       <version>${project.version}</version>
     </dependency>
-       <dependency>
+    <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>southbound-api</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>southbound-impl</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>utils.mdsal-utils</artifactId>
@@ -91,6 +97,20 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-common-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-inventory</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowplugin-extension-nicira</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowjava-extension-nicira</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.openflowplugin.model</groupId>
       <artifactId>model-flow-base</artifactId>
@@ -110,11 +130,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>sfc-model</artifactId>
       <version>${sfc.project.version}</version>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.sfc</groupId>
-      <artifactId>sfc-ovs</artifactId>
-      <version>${sfc.project.version}</version>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.sfc</groupId>
       <artifactId>sfc-provider</artifactId>
@@ -139,12 +154,35 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>mockito-all</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-core</artifactId>
+      <version>${powermock.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <version>${powermock.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <version>${powermock.version}</version>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.codehaus.sonar-plugins.java</groupId>
       <artifactId>sonar-jacoco-listeners</artifactId>
       <version>${sonar-jacoco-listeners.version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>iana-if-type-2014-05-08</artifactId>
+      <version>2014.05.08.8-SNAPSHOT</version>
+    </dependency>
   </dependencies>
 
   <build>
@@ -160,13 +198,13 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
+      <!--<plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
-        <!--<configuration>
+        <configuration>
           <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
-        </configuration>-->
-      </plugin>
+        </configuration>
+      </plugin>-->
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
index 1aa106ae18a911d76b08b871f2e182aa6f9ba65a..a794e579218c8e05d2352cad7e5c369af812b445 100644 (file)
@@ -21,6 +21,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <module>
           <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:netvirt:sfc">prefix:netvirt-sfc</type>
           <name>netvirt-sfc-default</name>
+          <of13provider>workaround</of13provider>
           <broker>
             <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
             <name>binding-osgi-broker</name>
index dfbe6f0eb790506b9b3e487ca20dc4ae31dba555..87a9db615cdd7ffb3e9cd672e73ed574ce7f414d 100644 (file)
@@ -14,7 +14,6 @@ import com.google.common.base.Preconditions;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.INetvirtSfcOF13Provider;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -6,11 +6,14 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13;
+package org.opendaylight.ovsdb.openstack.netvirt.sfc;
 
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services.SfcClassifierService;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.Bridges;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
+import org.osgi.framework.ServiceReference;
 
 /**
  * Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
@@ -26,6 +29,7 @@ public interface INetvirtSfcOF13Provider {
      * @param acl - Access list includes rules that need to be installed in a SFF.
      */
     void addClassifierRules(Bridge bridge, Acl acl);
+    void addClassifierRules(Bridges bridges, Acl acl);
 
     /**
      * Method removes the OF rules corresponding to rules within ACL
@@ -35,4 +39,10 @@ public interface INetvirtSfcOF13Provider {
      * @param acl - Access list includes rules that need to be installed in a SFF.
      */
     void removeClassifierRules(Sff sff, Acl acl);
+
+    void addClassifierRules(Acl acl);
+    void removeClassifierRules(Acl acl);
+
+    void setSfcClassifierService(ISfcClassifierService sfcClassifierService);
+    public void setDependencies(ServiceReference serviceReference);
 }
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/ISfcClassifierService.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/ISfcClassifierService.java
new file mode 100644 (file)
index 0000000..008339e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright Â© 2015 Red Hat, 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.openstack.netvirt.sfc;
+
+import java.net.InetAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+
+public interface ISfcClassifierService {
+    void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
+                                  NshUtils nshHeader, long vxGpeOfPort, boolean write);
+
+    void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write);
+
+    void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                  int tunnelOfPort, int tunnelId, short gotoTableId, boolean write);
+
+    void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                 long sfOfPort, int tunnelId, boolean write);
+
+    void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                       long sfOfPort, int tunnelId, boolean write);
+
+    void program_sfEgress(long dataPathId, int dstPort, boolean write);
+
+    void program_sfIngress(long dataPathId, int dstPort, long sfOfPort,
+                           String ipAddress, String sfDplName, boolean write);
+
+    void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
+                               String ipAddress, boolean write);
+}
index 139add1676b2e62d3d7496464a41816f50691aaf..74776698cb219d469a354acd76910172fd8556a4 100644 (file)
@@ -12,18 +12,9 @@ import com.google.common.base.Preconditions;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.INetvirtSfcOF13Provider;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclKey;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntries;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -35,7 +26,6 @@ import org.slf4j.LoggerFactory;
 public class NetvirtSfcAclListener extends AbstractDataTreeListener<Acl> {
     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcAclListener.class);
     private ListenerRegistration<NetvirtSfcAclListener> listenerRegistration;
-    private MdsalUtils dbutils;
 
     /**
      * {@link NetvirtSfcAclListener} constructor.
@@ -46,7 +36,6 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener<Acl> {
         super(provider, Acl.class);
         Preconditions.checkNotNull(db, "DataBroker can not be null!");
 
-        dbutils = new MdsalUtils(db);
         registrationListener(db);
     }
 
@@ -54,12 +43,11 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener<Acl> {
         final DataTreeIdentifier<Acl> treeId =
                 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, getIetfAclIid());
         try {
-            LOG.info("Registering Data Change Listener for NetvirtSfc AccesList configuration.");
+            LOG.info("Registering Data Change Listener for NetvirtSfc AccessList configuration.");
             listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
         } catch (final Exception e) {
             LOG.warn("Netvirt AccesList DataChange listener registration fail!");
-            LOG.debug("Netvirt AccesList DataChange listener registration fail!", e);
-            throw new IllegalStateException("NetvirtSfcAccesListListener startup fail! System needs restart.", e);
+            throw new IllegalStateException("NetvirtSfcAccessListListener startup fail! System needs restart.", e);
         }
     }
 
@@ -80,20 +68,7 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener<Acl> {
     public void remove(final InstanceIdentifier<Acl> identifier,
                        final Acl removeDataObj) {
         Preconditions.checkNotNull(removeDataObj, "Removed object can not be null!");
-        String aclName = removeDataObj.getAclName();
-
-        Classifiers classifiers = dbutils.read(LogicalDatastoreType.CONFIGURATION, getClassifierIid());
-        if (classifiers != null) {
-            for (Classifier classifier : classifiers.getClassifier()) {
-                if (classifier.getAcl().equalsIgnoreCase(aclName)) {
-                    if (classifier.getSffs() != null) {
-                        for (Sff sff : classifier.getSffs().getSff()) {
-                            provider.removeClassifierRules(sff, removeDataObj);
-                        }
-                    }
-                }
-            }
-        }
+        provider.removeClassifierRules(removeDataObj);
     }
 
     @Override
@@ -105,43 +80,11 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener<Acl> {
     public void add(final InstanceIdentifier<Acl> identifier,
                     final Acl addDataObj) {
         Preconditions.checkNotNull(addDataObj, "Added object can not be null!");
-        String aclName = addDataObj.getAclName();
         LOG.debug("Adding accesslist iid = {}, dataObj = {}", identifier, addDataObj);
-        Classifiers classifiers = dbutils.read(LogicalDatastoreType.CONFIGURATION, getClassifierIid());
-        if (classifiers == null) {
-            LOG.debug("add: No Classifiers found");
-            return;
-        }
-
-        LOG.debug("add: Classifiers: {}", classifiers);
-        for (Classifier classifier : classifiers.getClassifier()) {
-            if (classifier.getAcl().equals(aclName)) {
-                if (classifier.getBridges() != null) {
-                    for (Bridge bridge : classifier.getBridges().getBridge()) {
-                        provider.addClassifierRules(bridge, addDataObj);
-                    }
-                }
-            }
-        }
-    }
-
-    private InstanceIdentifier<Classifiers> getClassifierIid() {
-        return InstanceIdentifier.create(Classifiers.class);
+        provider.addClassifierRules(addDataObj);
     }
 
     public InstanceIdentifier<Acl> getIetfAclIid() {
         return InstanceIdentifier.create(AccessLists.class).child(Acl.class);
     }
-
-    /**
-     * Create an {@link Ace} {@link InstanceIdentifier}.
-     * @param aclName is the name of the ACL
-     * @param ruleName is the name of the rule
-     * @return the {@link Ace} {@link InstanceIdentifier}
-     */
-    public InstanceIdentifier<Ace> getIetfAclEntryIid(String aclName, String ruleName) {
-        return InstanceIdentifier.create(AccessLists.class).child(Acl.class,
-                new AclKey(aclName)).child(AccessListEntries.class).child(Ace.class,
-                new AceKey(ruleName));
-    }
 }
index 078b64b5e49447b623a498404ebf731fcca9cc89..1562a41f0fd461505fc4366bd949982255c93c50 100644 (file)
@@ -12,14 +12,12 @@ import com.google.common.base.Preconditions;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.INetvirtSfcOF13Provider;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -33,7 +31,7 @@ import org.slf4j.LoggerFactory;
  */
 public class NetvirtSfcClassifierListener extends AbstractDataTreeListener<Classifier> {
     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcClassifierListener.class);
-    private MdsalUtils dbutils;
+    private MdsalUtils mdsalUtils;
     private ListenerRegistration<NetvirtSfcClassifierListener> listenerRegistration;
 
     /**
@@ -44,7 +42,7 @@ public class NetvirtSfcClassifierListener extends AbstractDataTreeListener<Class
     public NetvirtSfcClassifierListener(final INetvirtSfcOF13Provider provider, final DataBroker db) {
         super(provider, Classifier.class);
         Preconditions.checkNotNull(db, "DataBroker can not be null!");
-        dbutils = new MdsalUtils(db);
+        mdsalUtils = new MdsalUtils(db);
         registrationListener(db);
     }
 
@@ -56,7 +54,6 @@ public class NetvirtSfcClassifierListener extends AbstractDataTreeListener<Class
             listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
         } catch (final Exception e) {
             LOG.warn("Netvirt Classifier DataChange listener registration fail!");
-            LOG.debug("Netvirt Classifier DataChange listener registration fail!", e);
             throw new IllegalStateException("NetvirtSfcClassifierListener startup fail! System needs restart.", e);
         }
     }
@@ -68,7 +65,6 @@ public class NetvirtSfcClassifierListener extends AbstractDataTreeListener<Class
                 listenerRegistration.close();
             } catch (final Exception e) {
                 LOG.warn("Error to stop Netvirt Classifier DataChange listener: {}", e.getMessage());
-                LOG.debug("Error to stop Netvirt Classifier DataChange listener..", e);
             }
             listenerRegistration = null;
         }
@@ -80,20 +76,13 @@ public class NetvirtSfcClassifierListener extends AbstractDataTreeListener<Class
         Preconditions.checkNotNull(removeDataObj, "Added object can not be null!");
         String aclName = removeDataObj.getAcl();
         // Read the ACL information from data store and make sure it exists.
-        Acl acl = dbutils.read(LogicalDatastoreType.CONFIGURATION, getIetfAclIid(aclName));
+        Acl acl = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, getIetfAclIid(aclName));
         if (acl == null) {
             LOG.debug("IETF ACL with name ={} is not yet configured. skip this operation", aclName);
             return;
         }
 
-        if (removeDataObj.getSffs() != null) {
-            for (Sff sff : removeDataObj.getSffs().getSff()) {
-                // Netvirt classifier binds an ACL with service function forwarder that is identified by SFF name.
-                // SFF validation can be done with SFC Provider APIs, as SFF is configured within SFC project.  
-                // Netvirt SFC provider will validate the SFF using SFC provider APIs.
-                provider.removeClassifierRules(sff, acl);
-            }
-        }
+        provider.removeClassifierRules(acl);
     }
 
     @Override
@@ -110,17 +99,13 @@ public class NetvirtSfcClassifierListener extends AbstractDataTreeListener<Class
         String aclName = addDataObj.getAcl();
         LOG.debug("Adding classifier iid = {}, dataObj = {}", identifier, addDataObj);
         // Read the ACL information from data store and make sure it exists.
-        Acl acl = dbutils.read(LogicalDatastoreType.CONFIGURATION, getIetfAclIid(aclName));
+        Acl acl = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, getIetfAclIid(aclName));
         if (acl == null) {
             LOG.debug("IETF ACL with name ={} is not yet configured. skip this operation", aclName);
             return;
         }
 
-        if (addDataObj.getBridges() != null) {
-            for (Bridge bridge : addDataObj.getBridges().getBridge()) {
-                provider.addClassifierRules(bridge, acl);
-            }
-        }
+        provider.addClassifierRules(acl);
     }
 
     public InstanceIdentifier<Classifier> getClassifierIid() {
index 57dece3e31e912f2409786ee35c88a33c12192c7..a77b8cf560f795bb44a5567279ec320160569cee 100644 (file)
 
 package org.opendaylight.ovsdb.openstack.netvirt.sfc;
 
+import java.util.Dictionary;
+import java.util.Hashtable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.INetvirtSfcOF13Provider;
-import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.NetvirtSfcOF13Provider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.OF13Provider;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.standalone.openflow13.NetvirtSfcStandaloneOF13Provider;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.standalone.openflow13.services.SfcClassifierService;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.NetvirtSfcWorkaroundOF13Provider;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class NetvirtSfcProvider implements BindingAwareProvider, AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcProvider.class);
     private NetvirtSfcAclListener aclListener;
-    private NetvirtSfcClassifierListener classfierListener;
+    private NetvirtSfcClassifierListener classifierListener;
+
+    public void setOf13Provider(String of13Provider) {
+        LOG.info("of13Provider is: {}", of13Provider);
+        this.of13Provider = of13Provider;
+    }
+
+    private String of13Provider;
+
+    public void setBundleContext(BundleContext bundleContext) {
+        LOG.info("bundleContext is: {}", bundleContext);
+        this.bundleContext = bundleContext;
+    }
+
+    private BundleContext bundleContext;
+
+    public NetvirtSfcProvider(BundleContext bundleContext) {
+        LOG.info("NetvirtSfcProvider: bundleContext: {}", bundleContext);
+        this.bundleContext = bundleContext;
+    }
 
     @Override
     public void onSessionInitiated(ProviderContext session) {
         LOG.info("NetvirtSfcProvider Session Initiated");
         DataBroker dataBroker = session.getSALService(DataBroker.class);
 
-        INetvirtSfcOF13Provider provider = new NetvirtSfcOF13Provider(dataBroker);
+        MdsalUtils mdsalUtils = new MdsalUtils(dataBroker);
+        SfcUtils sfcUtils = new SfcUtils(mdsalUtils);
+
+        // Allocate provider based on config
+        INetvirtSfcOF13Provider provider;
+        if (of13Provider.equals("standalone")) {
+            provider = new NetvirtSfcStandaloneOF13Provider(dataBroker);
+        } else {
+            provider = new NetvirtSfcWorkaroundOF13Provider(dataBroker, mdsalUtils, sfcUtils);
+        }
         aclListener = new NetvirtSfcAclListener(provider, dataBroker);
-        classfierListener = new NetvirtSfcClassifierListener(provider, dataBroker);
+        classifierListener = new NetvirtSfcClassifierListener(provider, dataBroker);
+
+        addToPipeline(provider);
+        provider.setDependencies(null);
     }
 
     @Override
     public void close() throws Exception {
         LOG.info("NetvirtSfcProvider Closed");
         aclListener.close();
-        classfierListener.close();
+        classifierListener.close();
+    }
+
+    private void addToPipeline(INetvirtSfcOF13Provider provider) {
+        if (provider instanceof NetvirtSfcStandaloneOF13Provider) {
+            SfcClassifierService sfcClassifierService =
+                    new org.opendaylight.ovsdb.openstack.netvirt.sfc.standalone.openflow13.services.SfcClassifierService();
+            registerService(bundleContext, ISfcClassifierService.class.getName(),
+                    sfcClassifierService, Service.SFC_CLASSIFIER);
+            sfcClassifierService.setDependencies(bundleContext, null);
+        } else {
+            org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services.SfcClassifierService sfcClassifierService =
+                    new org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services.SfcClassifierService();
+            registerService(bundleContext, ISfcClassifierService.class.getName(),
+                    sfcClassifierService, Service.SFC_CLASSIFIER);
+            sfcClassifierService.setDependencies(bundleContext, null);
+        }
+
+        //provider.setSfcClassifierService(sfcClassifierService);
+    }
+
+    private ServiceRegistration<?> registerService(BundleContext bundleContext, String[] interfaces,
+                                                   Dictionary<String, Object> properties, Object impl) {
+        ServiceRegistration<?> serviceRegistration = bundleContext.registerService(interfaces, impl, properties);
+        return serviceRegistration;
+    }
+
+    private ServiceRegistration<?> registerService(BundleContext bundleContext, String interfaceClassName,
+                                                       Object impl, Object serviceProperty) {
+        Dictionary<String, Object> properties = new Hashtable<>();
+        properties.put(AbstractServiceInstance.SERVICE_PROPERTY, serviceProperty);
+        properties.put(Constants.PROVIDER_NAME_PROPERTY, OF13Provider.NAME);
+        return registerService(bundleContext,
+                new String[] {AbstractServiceInstance.class.getName(),interfaceClassName},
+                properties, impl);
     }
 }
similarity index 98%
rename from openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/NshUtils.java
rename to openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NshUtils.java
index d8aca3bd930094bfe97abef367b86ce351574348..f28f030741577ab1add58386c7460e6ee951c332 100644 (file)
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13;
+package org.opendaylight.ovsdb.openstack.netvirt.sfc;
 
 import com.google.common.net.InetAddresses;
 
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/SfcUtils.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/SfcUtils.java
new file mode 100644 (file)
index 0000000..40b8172
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright Â© 2015 Red Hat, 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.openstack.netvirt.sfc;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePaths;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathKey;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctions;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionKey;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.Ip;
+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.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SfcUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(SfcUtils.class);
+    private MdsalUtils mdsalUtils;
+
+    public SfcUtils(MdsalUtils mdsalUtils) {
+        this.mdsalUtils = mdsalUtils;
+    }
+
+    public InstanceIdentifier<Classifiers> getClassifierIid() {
+        return InstanceIdentifier.create(Classifiers.class);
+    }
+
+    public InstanceIdentifier<RenderedServicePaths> getRspsId() {
+        return InstanceIdentifier.builder(RenderedServicePaths.class).build();
+    }
+
+    public InstanceIdentifier<RenderedServicePath> getRspId(String rspName) {
+        return InstanceIdentifier.builder(RenderedServicePaths.class)
+                .child(RenderedServicePath.class, new RenderedServicePathKey(new RspName(rspName))).build();
+    }
+
+    public InstanceIdentifier<ServiceFunction> getSfId(String sfName) {
+        return InstanceIdentifier.builder(ServiceFunctions.class)
+                .child(ServiceFunction.class, new ServiceFunctionKey(SfName.getDefaultInstance(sfName))).build();
+    }
+
+    public RenderedServicePath getRsp(String rspName) {
+        return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, getRspId(rspName));
+    }
+
+    public RenderedServicePath getRspforSfp(String sfpName) {
+        RenderedServicePath rspFound = null;
+        RenderedServicePaths rsps = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, this.getRspsId());
+        if (rsps != null) {
+            for (RenderedServicePath rsp : rsps.getRenderedServicePath()) {
+                if (rsp.getParentServiceFunctionPath() != null) {
+                    if (rsp.getParentServiceFunctionPath().getValue().equals(sfpName)) {
+                        rspFound = rsp;
+                    }
+                }
+            }
+        }
+        return rspFound;
+    }
+
+    public ServiceFunctionPath getSfp(String redirectSfc) {
+        ServiceFunctionPath sfpFound = null;
+        ServiceFunctionPaths sfps = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
+        if (sfps != null) {
+            for (ServiceFunctionPath sfp: sfps.getServiceFunctionPath()) {
+                if (sfp.getServiceChainName().getValue().equalsIgnoreCase(redirectSfc)) {
+                    sfpFound = sfp;
+                }
+            }
+        }
+        return sfpFound;
+    }
+
+    public IpAddress getSfIpAddress(String sfname) {
+        ServiceFunction serviceFunction =
+                SfcProviderServiceFunctionAPI.readServiceFunction(SfName.getDefaultInstance(sfname));
+
+        if (serviceFunction == null) {
+            LOG.info("Failed to read ServiceFunction: {}", sfname);
+            return null;
+        }
+
+        return getSfIpAddress(serviceFunction);
+    }
+
+    public IpAddress getSfIpAddress(ServiceFunction serviceFunction) {
+        if (serviceFunction == null) {
+            LOG.info("getSfIp: Servicefunction is null");
+            return null;
+        }
+
+        Ip ipLocator = (Ip) serviceFunction.getSfDataPlaneLocator().get(0).getLocatorType();
+        return ipLocator.getIp();
+    }
+
+    public PortNumber getSfPort(ServiceFunction serviceFunction) {
+        if (serviceFunction == null) {
+            LOG.info("getSfIp: Servicefunction is null");
+            return null;
+        }
+
+        Ip ipLocator = (Ip) serviceFunction.getSfDataPlaneLocator().get(0).getLocatorType();
+        return ipLocator.getPort();
+    }
+
+    public Ip getSfIp(ServiceFunction serviceFunction) {
+        if (serviceFunction == null) {
+            LOG.info("getSfIp: Servicefunction is null");
+            return null;
+        }
+
+        return (Ip)serviceFunction.getSfDataPlaneLocator().get(0).getLocatorType();
+    }
+
+    public String getSfDplName(ServiceFunction serviceFunction) {
+        String sfDplName = null;
+        if (serviceFunction == null) {
+            LOG.warn("getSfDplName: Servicefunction is null");
+            return null;
+        }
+
+        sfDplName = serviceFunction.getSfDataPlaneLocator().get(0).getName().getValue();
+        return sfDplName;
+    }
+
+    public Ip getSffIp(ServiceFunctionForwarder serviceFunctionForwarder) {
+        if (serviceFunctionForwarder == null) {
+            LOG.info("getSfIp: ServicefunctionForwarder is null");
+            return null;
+        }
+
+        return (Ip)serviceFunctionForwarder.getSffDataPlaneLocator().get(0).getDataPlaneLocator().getLocatorType();
+    }
+}
@@ -6,10 +6,11 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13;
+package org.opendaylight.ovsdb.openstack.netvirt.sfc.standalone.openflow13;
 
 import com.google.common.base.Preconditions;
 
+import com.google.common.collect.Iterables;
 import java.util.List;
 import java.util.StringTokenizer;
 
@@ -17,6 +18,9 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.INetvirtSfcOF13Provider;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
@@ -37,9 +41,10 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.cont
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.Bridges;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
@@ -52,20 +57,14 @@ import org.slf4j.LoggerFactory;
  * Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
  * @author Arun Yerra
  */
-public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
-    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcOF13Provider.class);
+public class NetvirtSfcStandaloneOF13Provider implements INetvirtSfcOF13Provider {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcStandaloneOF13Provider.class);
     private static final short TABLE_0_CLASSIFIER = 0;
-    //private static final short TABLE_1_L2FORWARD = 30;
-    //private static final short TABLE_2_L3FORWARD = 40;
     private static final short TABLE_3_INGR_ACL = 50;
 
-    public static final long REG_VALUE_FROM_LOCAL = 0x1L;
-    public static final long REG_VALUE_FROM_REMOTE = 0x2L;
-    public static final Class<? extends NxmNxReg> REG_FIELD = NxmNxReg0.class;
     private volatile NodeCacheManager nodeCacheManager;
     private volatile Southbound southbound;
     private MdsalUtils mdsalUtils;
-    private DataBroker dataBroker;
     private SfcClassifier sfcClassifier;
 
     // TBD:: Remove these constants after integrating with openstack.
@@ -78,14 +77,13 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
     private static final String INTERFACE_TYPE_VXLAN_GPE = "vxlangpe";
 
     /**
-     * {@link NetvirtSfcOF13Provider} constructor.
+     * {@link NetvirtSfcStandaloneOF13Provider} constructor.
      * @param dataBroker MdSal {@link DataBroker}
      */
-    public NetvirtSfcOF13Provider(final DataBroker dataBroker) {
+    public NetvirtSfcStandaloneOF13Provider(final DataBroker dataBroker) {
         Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
-        this.dataBroker = dataBroker;
         mdsalUtils = new MdsalUtils(dataBroker);
-        this.setDependencies(null);
+        //this.setDependencies(null);
         sfcClassifier = new SfcClassifier(dataBroker, southbound, mdsalUtils);
     }
 
@@ -94,46 +92,210 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
     }
 
     @Override
-    public void addClassifierRules(Bridge bridge, Acl acl) {
-        Preconditions.checkNotNull(bridge, "Input bridge cannot be NULL!");
-        Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!");
-
-        Node bridgeNode = getBridgeNode(bridge.getName());
-        if (bridgeNode == null) {
-            LOG.debug("bridge {} not yet configured. Skip processing !!", bridge.getName());
+    public void addClassifierRules(Acl acl) {
+        String aclName = acl.getAclName();
+        Classifiers classifiers = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, getClassifierIid());
+        if (classifiers == null) {
+            LOG.debug("add: No Classifiers found");
             return;
         }
 
-        // TODO: Find all nodes needing the classifier and add classifier to them
+        LOG.debug("add: Classifiers: {}", classifiers);
+        for (Classifier classifier : classifiers.getClassifier()) {
+            if (classifier.getAcl().equals(aclName)) {
+                if (classifier.getBridges() != null) {
+                    addClassifierRules(classifier.getBridges(), acl);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void removeClassifierRules(Acl acl) {
+        String aclName = acl.getAclName();
+        Classifiers classifiers = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, getClassifierIid());
+        if (classifiers != null) {
+            for (Classifier classifier : classifiers.getClassifier()) {
+                if (classifier.getAcl().equalsIgnoreCase(aclName)) {
+                    if (classifier.getSffs() != null) {
+                        for (Sff sff : classifier.getSffs().getSff()) {
+                            removeClassifierRules(sff, acl);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setSfcClassifierService(ISfcClassifierService sfcClassifierService) {
+
+    }
+
+    @Override
+    public void addClassifierRules(Bridge bridge, Acl acl) {
+
+    }
+
+    @Override
+    public void addClassifierRules(Bridges bridges, Acl acl) {
+        Preconditions.checkNotNull(bridges, "Input bridges cannot be NULL!");
+        Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!");
+
         for (Ace ace : acl.getAccessListEntries().getAce()) {
-            processAclEntry(ace, bridgeNode, true);
+            processAclEntry(ace, bridges, true);
         }
     }
 
-    private void processAclEntry(Ace entry, Node srcNode, boolean write) {
+    private void processAclEntry(Ace entry, Bridges bridges, boolean write) {
         Matches matches = entry.getMatches();
         if (matches == null) {
             LOG.warn("processAclEntry: matches not found");
             return;
         }
 
+        RenderedServicePath rsp = getRenderedServicePath(entry);
+        if (rsp == null) {
+            LOG.warn("Failed to get renderedServicePatch for entry: {}", entry);
+            return;
+        }
+
+        LOG.info("processAclEntry: RSP: {}", rsp);
+        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+        if (pathHopList.isEmpty()) {
+            LOG.warn("Service Path = {} has empty hops!!", rsp.getName());
+            return;
+        }
+
+        for (Bridge bridge : bridges.getBridge()) {
+            if (bridge.getDirection().getIntValue() == 0) {
+                Node bridgeNode = getBridgeNode(bridge.getName());
+                if (bridgeNode == null) {
+                    LOG.debug("processAclEntry: bridge {} not yet configured. Skip processing !!", bridge.getName());
+                    continue;
+                }
+
+                long tunnelOfPort = southbound.getOFPort(bridgeNode, CLIENT_GPE_PORT_NAME);
+                if (tunnelOfPort == 0L) {
+                    LOG.error("programAclEntry: Could not identify tunnel port {} -> OF ({}) on {}",
+                            CLIENT_GPE_PORT_NAME, tunnelOfPort, bridgeNode);
+                    return;
+                }
+
+                long localOfPort = southbound.getOFPort(bridgeNode, CLIENT_PORT_NAME);
+                if (localOfPort == 0L) {
+                    LOG.error("programAclEntry: Could not identify local port {} -> OF ({}) on {}",
+                            CLIENT_GPE_PORT_NAME, localOfPort, bridgeNode);
+                    return;
+                }
+
+                // Find the first Hop within an RSP.
+                // The classifier flow needs to send all matched traffic to this first hop SFF.
+                RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
+                        .readRenderedServicePathFirstHop(new RspName(rsp.getName()));
+
+                LOG.debug("First Hop IPAddress = {}, Port = {}", firstRspHop.getIp().getIpv4Address().getValue(),
+                        firstRspHop.getPort().getValue());
+
+                NshUtils nshHeader = new NshUtils();
+                // C1 is the normal overlay dest ip and c2 is the vnid
+                // Hardcoded for now, netvirt integration will have those values
+                nshHeader.setNshMetaC1(NshUtils.convertIpAddressToLong(new Ipv4Address(TUNNEL_DST)));
+                nshHeader.setNshMetaC2(Long.parseLong(TUNNEL_VNID));
+                nshHeader.setNshNsp(rsp.getPathId());
+
+                RenderedServicePathHop firstHop = pathHopList.get(0);
+                nshHeader.setNshNsi(firstHop.getServiceIndex());
+                nshHeader.setNshTunIpDst(firstRspHop.getIp().getIpv4Address());
+                nshHeader.setNshTunUdpPort(firstRspHop.getPort());
+                LOG.debug("The Nsh Header = {}", nshHeader);
+
+                handleLocalInPort(southbound.getDataPathId(bridgeNode), rsp.getPathId().toString(), localOfPort,
+                        TABLE_0_CLASSIFIER, TABLE_3_INGR_ACL, matches, true);
+
+                handleSfcClassiferFlows(southbound.getDataPathId(bridgeNode), TABLE_3_INGR_ACL, entry.getRuleName(),
+                        matches, nshHeader, tunnelOfPort, true);
+            } else {
+                Node bridgeNode = getBridgeNode(bridge.getName());
+                if (bridgeNode == null) {
+                    LOG.debug("processAclEntry: bridge {} not yet configured. Skip processing !!", bridge.getName());
+                    continue;
+                }
+
+                long tunnelOfPort = southbound.getOFPort(bridgeNode, SERVER_GPE_PORT_NAME);
+                if (tunnelOfPort == 0L) {
+                    LOG.error("programAclEntry: Could not identify tunnel port {} -> OF ({}) on {}",
+                            CLIENT_GPE_PORT_NAME, tunnelOfPort, bridgeNode);
+                    return;
+                }
+
+                long localOfPort = southbound.getOFPort(bridgeNode, SERVER_PORT_NAME);
+                if (localOfPort == 0L) {
+                    LOG.error("programAclEntry: Could not identify local port {} -> OF ({}) on {}",
+                            CLIENT_GPE_PORT_NAME, localOfPort, bridgeNode);
+                    return;
+                }
+
+                RenderedServicePathHop lastRspHop = Iterables.getLast(rsp.getRenderedServicePathHop());
+
+                LOG.debug("programAclEntry: Last Hop #: {}, nsi: {}", lastRspHop.getHopNumber().intValue(),
+                        lastRspHop.getServiceIndex().intValue() - 1);
+
+                NshUtils nshHeader = new NshUtils();
+                nshHeader.setNshNsp(rsp.getPathId());
+                nshHeader.setNshNsi((short)(lastRspHop.getServiceIndex().intValue() - 1));
+                nshHeader.setNshMetaC2(Long.parseLong(TUNNEL_VNID));
+                LOG.debug("programAclEntry: The Nsh Header = {}", nshHeader);
+
+                //handleLocalEgressPort(southbound.getDataPathId(bridgeNode), rsp.getPathId().toString(), localOfPort,
+                //        TABLE_0_CLASSIFIER, TABLE_3_INGR_ACL, true);
+
+                handleEgressSfcClassiferFlows(southbound.getDataPathId(bridgeNode),
+                        TABLE_0_CLASSIFIER, entry.getRuleName(), matches, nshHeader, tunnelOfPort, localOfPort, true);
+            }
+        }
+    }
+
+    private RenderedServicePath getRenderedServicePath (Ace entry) {
+        RenderedServicePath rsp = null;
         RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
-        LOG.debug("Processing ACL entry = {} on Node = {} sfcRedirect = {}", entry.getRuleName(),
-                srcNode.getNodeId(), sfcRedirect);
+        LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
         if (sfcRedirect == null) {
             LOG.warn("processAClEntry: sfcRedirect is null");
-            return;
+            return null;
+        }
+
+        if (sfcRedirect.getRspName() != null) {
+            rsp = getRenderedServicePathFromRsp(sfcRedirect.getRspName());
+        } else if (sfcRedirect.getSfpName() != null) {
+            LOG.warn("getRenderedServicePath: sfp not handled yet");
+        } else {
+            rsp = getRenderedServicePathFromSfc(entry);
+        }
+        LOG.info("getRenderedServicePath: rsp: {}", rsp);
+        return rsp;
+    }
+
+    private RenderedServicePath getRenderedServicePathFromRsp(String rspName) {
+        return null;//getRsp(rspName);
+    }
+
+    private RenderedServicePath getRenderedServicePathFromSfc (Ace entry) {
+        RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
+        LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
+        if (sfcRedirect == null) {
+            LOG.warn("processAClEntry: sfcRedirect is null");
+            return null;
         }
 
-        String sfcName = sfcRedirect.getRedirectSfc();
-        LOG.debug("Processing Redirect to SFC = {}", sfcRedirect.getRedirectSfc());
+        String sfcName = sfcRedirect.getSfcName();
         ServiceFunctionPath sfp = getSfp(sfcName);
         if (sfp == null || sfp.getName() == null) {
             LOG.warn("There is no configured SFP with sfcName = {}; so skip installing the ACL entry!!", sfcName);
-            return;
+            return null;
         }
 
-        LOG.debug("Processing Redirect to SFC = {}, SFP = {}", sfcRedirect.getRedirectSfc(), sfp);
+        LOG.debug("Processing Redirect to SFC = {}, SFP = {}", sfcName, sfp);
         // If RSP doesn't exist, create an RSP.
         String sfpName = sfp.getName().getValue();
         RenderedServicePath rsp = getRspforSfp(sfpName);
@@ -148,7 +310,7 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
             rsp = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, rspInput);
             if (rsp == null) {
                 LOG.warn("failed to add RSP");
-                return;
+                return null;
             }
 
             // If SFP is symmetric, create RSP in the reverse direction.
@@ -156,64 +318,29 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
                 LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName);
                 String rspNameRev = rspName + "-Reverse";
                 RenderedServicePath rspReverse = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
-                                                             this.getRspId(rspNameRev));
+                        getRspId(rspNameRev));
                 if (rspReverse == null) {
                     rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
                     if (rspReverse == null) {
                         LOG.warn("failed to add reverse RSP");
-                        return;
+                        return null;
                     }
                 }
             }
         }
+        return rsp;
+    }
 
-        LOG.info("processAclEntry: RSP: {}", rsp);
-
-        // Find the first Hop within an RSP.
-        // The classifier flow needs to send all matched traffic to this first hop SFF.
-        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
-        if (pathHopList.isEmpty()) {
-            LOG.warn("Service Path = {} has empty hops!!", sfpName);
-            return;
-        }
-
-        RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
-                .readRenderedServicePathFirstHop(new RspName(rspName));
-
-        LOG.debug("First Hop IPAddress = {}, Port = {}", firstRspHop.getIp().getIpv4Address().getValue(),
-                firstRspHop.getPort().getValue().intValue());
-        long tunnelOfPort = southbound.getOFPort(srcNode, CLIENT_GPE_PORT_NAME);
-        if (tunnelOfPort == 0L) {
-            LOG.error("programAclEntry: Could not identify tunnel port {} -> OF ({}) on {}",
-                    CLIENT_GPE_PORT_NAME, tunnelOfPort, srcNode);
-            return;
-        }
-
-        long localOfPort = southbound.getOFPort(srcNode, CLIENT_PORT_NAME);
-        if (localOfPort == 0L) {
-            LOG.error("programAclEntry: Could not identify local port {} -> OF ({}) on {}",
-                    CLIENT_GPE_PORT_NAME, localOfPort, srcNode);
-            return;
-        }
-
-        NshUtils nshHeader = new NshUtils();
-        // C1 is the normal overlay dest ip and c2 is the vnid
-        // Hardcoded for now, netvirt integration will have those values
-        nshHeader.setNshMetaC1(NshUtils.convertIpAddressToLong(new Ipv4Address(TUNNEL_DST)));
-        nshHeader.setNshMetaC2(Long.parseLong(TUNNEL_VNID));
-        nshHeader.setNshNsp(rsp.getPathId());
-
-        RenderedServicePathHop firstHop = pathHopList.get(0);
-        nshHeader.setNshNsi(firstHop.getServiceIndex());
-        nshHeader.setNshTunIpDst(firstRspHop.getIp().getIpv4Address());
-        nshHeader.setNshTunUdpPort(firstRspHop.getPort());
-        LOG.debug("The Nsh Header = {}", nshHeader);
+    private void handleLocalEgressPort(long dataPathId, String s, long localOfPort, short writeTable,
+                                       short gotoTable, boolean write) {
 
-        handleLocalInPort(southbound.getDataPathId(srcNode), rsp.getPathId().toString(), localOfPort,
-                TABLE_0_CLASSIFIER, TABLE_3_INGR_ACL, true);
+    }
 
-        handleSfcClassiferFlows(southbound.getDataPathId(srcNode), TABLE_3_INGR_ACL, entry.getRuleName(),
-                matches, nshHeader, tunnelOfPort, true);
+    private void handleEgressSfcClassiferFlows(long dataPathId, short writeTable, String ruleName,
+                                               Matches matches, NshUtils nshHeader, long tunnelOfPort,
+                                               long outOfPort, boolean write) {
+        sfcClassifier.programEgressSfcClassiferFlows(dataPathId, writeTable, ruleName, matches, nshHeader,
+                tunnelOfPort, outOfPort, write);
     }
 
     private void handleSfcClassiferFlows(long dataPathId, short writeTable, String ruleName,
@@ -309,12 +436,17 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
         return null;
     }
 
+    private InstanceIdentifier<Classifiers> getClassifierIid() {
+        return InstanceIdentifier.create(Classifiers.class);
+    }
+
     public void handleLocalInPort(long dpidLong, String segmentationId, Long inPort,
-                                  short writeTable, short goToTableId, boolean write) {
-        sfcClassifier.programLocalInPort(dpidLong, segmentationId, inPort, writeTable, goToTableId, write);
+                                  short writeTable, short goToTableId, Matches matches, boolean write) {
+        sfcClassifier.programLocalInPort(dpidLong, segmentationId, inPort, writeTable, goToTableId, matches, write);
     }
 
-    private void setDependencies(ServiceReference serviceReference) {
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
         nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
     }
@@ -6,15 +6,18 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13;
+package org.opendaylight.ovsdb.openstack.netvirt.sfc.standalone.openflow13;
 
 import com.google.common.collect.Lists;
 import java.math.BigInteger;
+import java.util.ArrayList;
 import java.util.List;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
 import org.opendaylight.ovsdb.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
 import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
@@ -26,11 +29,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
@@ -41,15 +40,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -79,7 +73,7 @@ public class SfcClassifier {
     public void programSfcClassiferFlows(Long dpidLong, short writeTable, String ruleName, Matches match,
                                          NshUtils nshHeader, long tunnelOfPort, boolean write) {
         String nodeName = OPENFLOW + dpidLong;
-        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
         FlowBuilder flowBuilder = new FlowBuilder();
 
         MatchBuilder matchBuilder = buildMatch(match);
@@ -99,7 +93,7 @@ public class SfcClassifier {
             List<Action> actionList = getNshAction(nshHeader);
             ActionBuilder ab = new ActionBuilder();
 
-            ab.setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + tunnelOfPort)));
+            ab.setAction(ActionUtils.outputAction(FlowUtils.getNodeConnectorId(tunnelOfPort, nodeName)));
             ab.setOrder(actionList.size());
             ab.setKey(new ActionKey(actionList.size()));
             actionList.add(ab.build());
@@ -123,6 +117,65 @@ public class SfcClassifier {
         }
     }
 
+    public void programEgressSfcClassiferFlows(Long dpidLong, short writeTable, String ruleName,
+                                               Matches match, NshUtils nshHeader,
+                                               long tunnelOfPort, long outOfPort, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, tunnelOfPort).build());
+        flowBuilder.setMatch(
+                MatchUtils.createTunnelIDMatch(matchBuilder, BigInteger.valueOf(nshHeader.getNshMetaC2())).build());
+        flowBuilder.setMatch(MatchUtils.addNxNspMatch(matchBuilder, nshHeader.getNshNsp()).build());
+        flowBuilder.setMatch(MatchUtils.addNxNsiMatch(matchBuilder, nshHeader.getNshNsi()).build());
+
+        String flowId = "egressSfcClass_" + ruleName + "_" + nshHeader.getNshNsp() + "_" + nshHeader.getNshNsi();
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(writeTable);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            List<Action> actionList = new ArrayList<>();
+            ActionBuilder ab = new ActionBuilder();
+
+            ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(REG_FIELD).build(),
+                    BigInteger.valueOf(REG_VALUE_FROM_REMOTE)));
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            ab.setAction(ActionUtils.outputAction(FlowUtils.getNodeConnectorId(dpidLong, outOfPort)));
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+
+            InstructionBuilder ib = new InstructionBuilder();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            List<Instruction> instructions = new ArrayList<>();
+            instructions.add(ib.build());
+
+            InstructionsBuilder isb = new InstructionsBuilder();
+            isb.setInstruction(instructions);
+
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
     private List<Action> getNshAction(NshUtils header) {
         // Build the Actions to Add the NSH Header
         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC1Load =
@@ -150,13 +203,14 @@ public class SfcClassifier {
     }
 
     public void programLocalInPort(Long dpidLong, String segmentationId, Long inPort,
-                                   short writeTable, short goToTableId, boolean write) {
+                                   short writeTable, short goToTableId, Matches match, boolean write) {
         String nodeName = OPENFLOW + dpidLong;
 
-        MatchBuilder matchBuilder = new MatchBuilder();
-        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
         FlowBuilder flowBuilder = new FlowBuilder();
 
+        MatchBuilder matchBuilder = buildMatch(match);
+        flowBuilder.setMatch(matchBuilder.build());
         flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort).build());
         String flowId = "sfcIngress_" + segmentationId + "_" + inPort;
         flowBuilder.setId(new FlowId(flowId));
@@ -205,36 +259,6 @@ public class SfcClassifier {
         }
     }
 
-/*
-    public InstructionsBuilder buildActions(String ruleName, Actions actions, String datapathId) {
-        InstructionBuilder ib = new InstructionBuilder();
-
-        if (actions.getPacketHandling() instanceof Deny) {
-            InstructionUtils.createDropInstructions(ib);
-        } else if (actions.getPacketHandling() instanceof Permit) {
-            //Permit actPermit = (Permit) actions.getPacketHandling();
-        } else {
-            InstructionUtils.createDropInstructions(ib);
-        }
-
-        ib.setOrder(0);
-        ib.setKey(new InstructionKey(0));
-        // Instructions List Stores Individual Instructions
-        List<Instruction> instructions = Lists.newArrayList();
-        instructions.add(ib.build());
-
-        // Call the InstructionBuilder Methods Containing Actions
-        ib = this.getMutablePipelineInstructionBuilder();
-        ib.setOrder(1);
-        ib.setKey(new InstructionKey(1));
-        instructions.add(ib.build());
-
-        // Add InstructionBuilder to the Instruction(s)Builder List
-        InstructionsBuilder isb = new InstructionsBuilder();
-        isb.setInstruction(instructions);
-        return isb;
-    }*/
-
     public MatchBuilder buildMatch(Matches matches) {
         MatchBuilder matchBuilder = new MatchBuilder();
 
@@ -244,7 +268,7 @@ public class SfcClassifier {
                 //AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
                 //MatchUtils.createSrcL3IPv4Match(matchBuilder, aceIpv4.getSourceIpv4Network());
                 //MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Network());
-                //MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
+                MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
                 MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(), 0,
                         aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
             }
@@ -255,59 +279,19 @@ public class SfcClassifier {
                     new MacAddress(aceEth.getDestinationMacAddressMask().getValue()));
         }
 
+        LOG.info("buildMatch: {}", matchBuilder.build());
         return matchBuilder;
     }
 
     protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
         LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}", flowBuilder.build(), nodeBuilder.build());
-        mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder), nodeBuilder.build());
-        mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder),
+        mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, FlowUtils.createNodePath(nodeBuilder),
+                nodeBuilder.build());
+        mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, FlowUtils.createFlowPath(flowBuilder, nodeBuilder),
                 flowBuilder.build());
     }
 
-    /*private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
-        LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
-                flowBuilder.build(), nodeBuilder.build());
-        WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
-        modification.put(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder),
-                nodeBuilder.build(), true);
-        modification.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder),
-                flowBuilder.build(), true);
-
-        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
-        try {
-            commitFuture.get();  // TODO: Make it async (See bug 1362)
-            LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
-        } catch (Exception e) {
-            LOG.error(e.getMessage(), e);
-            modification.cancel();
-        }
-    }*/
-
     protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
-        mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
-    }
-
-    private NodeBuilder createNodeBuilder(String nodeId) {
-        NodeBuilder builder = new NodeBuilder();
-        builder.setId(new NodeId(nodeId));
-        builder.setKey(new NodeKey(builder.getId()));
-        return builder;
-    }
-
-    private static InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
-        return InstanceIdentifier.builder(Nodes.class)
-                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
-                        nodeBuilder.getKey())
-                .augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(flowBuilder.getTableId()))
-                .child(Flow.class, flowBuilder.getKey()).build();
-    }
-
-    private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
-    createNodePath(NodeBuilder nodeBuilder) {
-        return InstanceIdentifier.builder(Nodes.class)
-                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
-                        nodeBuilder.getKey()).build();
+        mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, FlowUtils.createFlowPath(flowBuilder, nodeBuilder));
     }
 }
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/standalone/openflow13/services/SfcClassifierService.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/standalone/openflow13/services/SfcClassifierService.java
new file mode 100644 (file)
index 0000000..f725c24
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright Â© 2015 Red Hat, 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.openstack.netvirt.sfc.standalone.openflow13.services;
+
+import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface, ISfcClassifierService {
+    private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
+
+    public SfcClassifierService(Service service) {
+        super(service);
+    }
+
+    public SfcClassifierService() {
+        super(Service.SFC_CLASSIFIER);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(SfcClassifierService.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+
+    @Override
+    public void programIngressClassifier(long dataPathId, String ruleName, Matches matches, NshUtils nshHeader, long vxGpeOfPort, boolean write) {
+
+    }
+
+    @Override
+    public void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write) {
+
+    }
+
+    @Override
+    public void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi, int tunnelOfPort, int tunnelId, short gotoTableId, boolean write) {
+
+    }
+
+    @Override
+    public void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi, long sfOfPort, int tunnelId, boolean write) {
+
+    }
+
+    @Override
+    public void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi, long sfOfPort, int tunnelId, boolean write) {
+
+    }
+
+    @Override
+    public void program_sfEgress(long dataPathId, int dstPort, boolean write) {
+
+    }
+
+    @Override
+    public void program_sfIngress(long dataPathId, int dstPort, long sfOfPort, String ipAddress, String sfDplName, boolean write) {
+
+    }
+
+    @Override
+    public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr, String ipAddress, boolean write) {
+
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/NetvirtSfcWorkaroundOF13Provider.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/NetvirtSfcWorkaroundOF13Provider.java
new file mode 100644 (file)
index 0000000..a69e801
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Copyright Â© 2015 Red Hat, 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.openstack.netvirt.sfc.workaround;
+
+import com.google.common.base.Preconditions;
+import java.util.List;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbTables;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.INetvirtSfcOF13Provider;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.SfcUtils;
+import org.opendaylight.ovsdb.southbound.SouthboundConstants;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
+import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.Ip;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+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.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.Bridges;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
+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.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.port._interface.attributes.Options;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcWorkaroundOF13Provider.class);
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile Southbound southbound;
+    private volatile ISfcClassifierService sfcClassifierService;
+    private static final short SFC_TABLE = 150;
+    private static final int GPE_PORT = 6633;
+    private static final String NETWORK_TYPE_VXLAN = "vxlan";
+    private MdsalUtils mdsalUtils;
+    private SfcUtils sfcUtils;
+    private static final String VXGPE = "vxgpe";
+    private static final String TUNNEL_DST = "192.168.120.31";
+    private static final String TUNNEL_VNID = "10";
+    public static final String TUNNEL_ENDPOINT_KEY = "local_ip";
+
+    public NetvirtSfcWorkaroundOF13Provider(final DataBroker dataBroker, MdsalUtils mdsalUtils, SfcUtils sfcUtils) {
+        Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
+        Preconditions.checkNotNull(mdsalUtils, "Input mdsalUtils cannot be NULL!");
+        Preconditions.checkNotNull(sfcUtils, "Input sfcUtils cannot be NULL!");
+
+        this.mdsalUtils = mdsalUtils;
+        this.sfcUtils = sfcUtils;
+        //this.setDependencies(null);
+    }
+
+    public void setSfcClassifierService(ISfcClassifierService sfcClassifierService) {
+        this.sfcClassifierService = sfcClassifierService;
+    }
+
+    @Override
+    public void addClassifierRules(Bridge bridge, Acl acl) {
+
+    }
+
+    @Override
+    public void addClassifierRules(Bridges bridges, Acl acl) {
+        Preconditions.checkNotNull(bridges, "Input bridges cannot be NULL!");
+        Preconditions.checkNotNull(acl, "Input acl cannot be NULL!");
+    }
+
+    @Override
+    public void removeClassifierRules(Sff sff, Acl acl) {
+
+    }
+
+    @Override
+    public void addClassifierRules(Acl acl) {
+        String aclName = acl.getAclName();
+        Classifiers classifiers = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, sfcUtils.getClassifierIid());
+        if (classifiers == null) {
+            LOG.debug("addClassifierRules: No Classifiers found");
+            return;
+        }
+
+        LOG.debug("addClassifierRules: Classifiers: {}", classifiers);
+        for (Classifier classifier : classifiers.getClassifier()) {
+            if (classifier.getAcl().equals(aclName)) {
+                for (Ace ace : acl.getAccessListEntries().getAce()) {
+                    processAclEntry(ace);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void removeClassifierRules(Acl acl) {
+
+    }
+
+    private void processAclEntry(Ace entry) {
+        Matches matches = entry.getMatches();
+        Preconditions.checkNotNull(matches, "Input bridges cannot be NULL!");
+
+        RenderedServicePath rsp = getRenderedServicePath(entry);
+        if (rsp == null) {
+            LOG.warn("Failed to get renderedServicePatch for entry: {}", entry);
+            return;
+        }
+
+        handleRenderedServicePath(rsp, entry);
+    }
+
+    private void handleRenderedServicePathOld(RenderedServicePath rsp, Ace entry) {
+        LOG.info("handleRenderedServicePath: RSP: {}", rsp);
+
+        Matches matches = entry.getMatches();
+        if (matches == null) {
+            LOG.warn("processAclEntry: matches not found");
+            return;
+        }
+
+        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+        if (pathHopList.isEmpty()) {
+            LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
+            return;
+        }
+        LOG.info("handleRenderedServicePath: pathHopList: {}", pathHopList);
+
+        final List<Node> bridgeNodes = nodeCacheManager.getBridgeNodes();
+        if (bridgeNodes == null || bridgeNodes.isEmpty()) {
+            LOG.warn("handleRenderedServicePath: There are no bridges to process");
+            return;
+        }
+        for (Node bridgeNode : bridgeNodes) {
+            OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(bridgeNode, "br-int");
+            if (ovsdbBridgeAugmentation == null) {
+                continue;
+            }
+            long vxGpeOfPort = getOFPort(bridgeNode, VXGPE);
+            if (vxGpeOfPort == 0L) {
+                LOG.warn("programAclEntry: Could not identify tunnel port {} -> OF ({}) on {}",
+                        VXGPE, vxGpeOfPort, bridgeNode);
+                continue;
+            }
+            long dataPathId = southbound.getDataPathId(bridgeNode);
+            if (dataPathId == 0L) {
+                LOG.warn("programAclEntry: Could not identify datapathId on {}", bridgeNode);
+                continue;
+            }
+
+            // Find the first Hop within an RSP.
+            // The classifier flow needs to send all matched traffic to this first hop SFF.
+            RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
+                    .readRenderedServicePathFirstHop(rsp.getName());
+
+            LOG.info("handleRenderedServicePath: firstRspHop: {}", firstRspHop);
+            LOG.debug("handleRenderedServicePath: First Hop IPAddress = {}, Port = {}",
+                    firstRspHop.getIp().getIpv4Address().getValue(),
+                    firstRspHop.getPort().getValue());
+
+            NshUtils nshHeader = new NshUtils();
+            nshHeader.setNshMetaC1(NshUtils.convertIpAddressToLong(new Ipv4Address(TUNNEL_DST)));
+            nshHeader.setNshMetaC2(Long.parseLong(TUNNEL_VNID)); // get from register //get from
+            nshHeader.setNshNsp(rsp.getPathId());
+
+            RenderedServicePathHop firstHop = pathHopList.get(0);
+            RenderedServicePathHop lastHop = pathHopList.get(pathHopList.size()-1);
+            ServiceFunction serviceFunction =
+                    SfcProviderServiceFunctionAPI.readServiceFunction(
+                            SfName.getDefaultInstance(firstHop.getServiceFunctionName().getValue()));
+            if (serviceFunction == null) {
+                LOG.warn("programAclEntry: Could not identify ServiceFunction {} on {}",
+                        firstHop.getServiceFunctionName().getValue(), bridgeNode);
+                continue;
+            }
+
+            nshHeader.setNshNsi(firstHop.getServiceIndex());
+            // workaround: bypass sff and got directly to sf
+            //nshHeader.setNshTunIpDst(firstRspHop.getIp().getIpv4Address());
+            IpAddress sfIpAddress = sfcUtils.getSfIpAddress(serviceFunction);
+            String sfDplName = sfcUtils.getSfDplName(serviceFunction);
+            //sfcUtils.getSfIp(firstHop.getServiceFunctionName().getValue());
+            nshHeader.setNshTunIpDst(sfIpAddress.getIpv4Address());
+            nshHeader.setNshTunUdpPort(firstRspHop.getPort());
+            LOG.debug("handleRenderedServicePath: NSH Header = {}", nshHeader);
+
+            sfcClassifierService.programIngressClassifier(dataPathId, entry.getRuleName(), matches,
+                    nshHeader, vxGpeOfPort, true);
+
+            sfcClassifierService.program_sfEgress(dataPathId, GPE_PORT, true);
+            long sfOfPort = getSfPort(bridgeNode, sfDplName);
+
+            String sfMac = getMacFromExternalIds(bridgeNode, sfDplName);
+            String sfIpString = new String(sfIpAddress.getValue());
+            LOG.info("handleRenderedServicePath: sfDplName: {}, sfMac: {}, sfOfPort: {}, sfIpAddress: {}",
+                    sfDplName, sfMac, sfOfPort, sfIpString);
+            if (sfMac != null) { // install if the sf is on this bridge, expand when using multiple bridges
+                sfcClassifierService.program_sfIngress(dataPathId, GPE_PORT, sfOfPort, sfIpString, sfDplName, true);
+                sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpString, true);
+            }
+
+            short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
+            sfcClassifierService.programEgressClassifier(dataPathId, vxGpeOfPort, rsp.getPathId(),
+                    lastServiceindex, sfOfPort, 0, true);
+            sfcClassifierService.programEgressClassifierBypass(dataPathId, vxGpeOfPort, rsp.getPathId(),
+                    lastServiceindex, sfOfPort, 0, true);
+
+            sfcClassifierService.programSfcTable(dataPathId, vxGpeOfPort, SFC_TABLE, true);
+        }
+    }
+
+    private void handleRenderedServicePath(RenderedServicePath rsp, Ace entry) {
+        LOG.info("handleRenderedServicePath: RSP: {}", rsp);
+
+        Matches matches = entry.getMatches();
+        if (matches == null) {
+            LOG.warn("processAclEntry: matches not found");
+            return;
+        }
+
+        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+        if (pathHopList.isEmpty()) {
+            LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
+            return;
+        }
+        LOG.info("handleRenderedServicePath: pathHopList: {}", pathHopList);
+
+        RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
+                .readRenderedServicePathFirstHop(rsp.getName());
+        LOG.info("handleRenderedServicePath: firstRspHop: {}", firstRspHop);
+
+        RenderedServicePathHop firstHop = pathHopList.get(0);
+        RenderedServicePathHop lastHop = pathHopList.get(pathHopList.size()-1);
+
+        final List<Node> bridgeNodes = nodeCacheManager.getBridgeNodes();
+        if (bridgeNodes == null || bridgeNodes.isEmpty()) {
+            LOG.warn("handleRenderedServicePath: There are no bridges to process");
+            return;
+        }
+        for (RenderedServicePathHop hop : pathHopList) {
+            for (Node bridgeNode : bridgeNodes) {
+                // ignore bridges other than br-int
+                OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(bridgeNode, "br-int");
+                if (ovsdbBridgeAugmentation == null) {
+                    continue;
+                }
+                long vxGpeOfPort = getOFPort(bridgeNode, VXGPE);
+                if (vxGpeOfPort == 0L) {
+                    LOG.warn("programAclEntry: Could not identify gpe vtep {} -> OF ({}) on {}",
+                            VXGPE, vxGpeOfPort, bridgeNode);
+                    continue;
+                }
+                long dataPathId = southbound.getDataPathId(bridgeNode);
+                if (dataPathId == 0L) {
+                    LOG.warn("programAclEntry: Could not identify datapathId on {}", bridgeNode);
+                    continue;
+                }
+
+                ServiceFunction serviceFunction =
+                        SfcProviderServiceFunctionAPI.readServiceFunction(firstHop.getServiceFunctionName());
+                if (serviceFunction == null) {
+                    LOG.warn("programAclEntry: Could not identify ServiceFunction {} on {}",
+                            firstHop.getServiceFunctionName().getValue(), bridgeNode);
+                    continue;
+                }
+                ServiceFunctionForwarder serviceFunctionForwarder =
+                        SfcProviderServiceForwarderAPI
+                                .readServiceFunctionForwarder(hop.getServiceFunctionForwarder());
+                if (serviceFunctionForwarder == null) {
+                    LOG.warn("programAclEntry: Could not identify ServiceFunctionForwarder {} on {}",
+                            firstHop.getServiceFunctionName().getValue(), bridgeNode);
+                    continue;
+                }
+
+                handleSf(bridgeNode, serviceFunction);
+                handleSff(bridgeNode, serviceFunctionForwarder, serviceFunction, hop, firstHop, lastHop,
+                        entry.getRuleName(), matches, vxGpeOfPort, rsp);
+                if (firstHop == lastHop) {
+                    handleSff(bridgeNode, serviceFunctionForwarder, serviceFunction, hop, null, lastHop,
+                            entry.getRuleName(), matches, vxGpeOfPort, rsp);
+                }
+            }
+        }
+    }
+
+    private void handleSff(Node bridgeNode, ServiceFunctionForwarder serviceFunctionForwarder,
+                           ServiceFunction serviceFunction,
+                           RenderedServicePathHop hop,
+                           RenderedServicePathHop firstHop,
+                           RenderedServicePathHop lastHop,
+                           String ruleName, Matches matches,
+                           long vxGpeOfPort, RenderedServicePath rsp) {
+        long dataPathId = southbound.getDataPathId(bridgeNode);
+
+        if (hop == firstHop) {
+            LOG.info("handleSff: first hop processing {} - {}",
+                    bridgeNode.getNodeId(), serviceFunctionForwarder.getName());
+            NshUtils nshHeader = new NshUtils();
+            nshHeader.setNshNsp(rsp.getPathId());
+            nshHeader.setNshNsi(firstHop.getServiceIndex());
+            if (isSffOnBridge(bridgeNode, serviceFunctionForwarder)) {
+                LOG.info("handleSff: sff and bridge are the same: {} - {}, skipping first sff",
+                        bridgeNode.getNodeId(), serviceFunctionForwarder.getName());
+                Ip ip = sfcUtils.getSfIp(serviceFunction);
+                nshHeader.setNshTunIpDst(ip.getIp().getIpv4Address());
+                nshHeader.setNshTunUdpPort(ip.getPort());
+            } else {
+                LOG.info("handleSff: sff and bridge are not the same: {} - {}, sending to first sff",
+                        bridgeNode.getNodeId(), serviceFunctionForwarder.getName());
+                Ip ip = sfcUtils.getSffIp(serviceFunctionForwarder);
+                nshHeader.setNshTunIpDst(ip.getIp().getIpv4Address());
+                nshHeader.setNshTunUdpPort(ip.getPort());
+            }
+            sfcClassifierService.programIngressClassifier(dataPathId, ruleName, matches,
+                    nshHeader, vxGpeOfPort, true);
+        } else if (hop == lastHop) {
+            LOG.info("handleSff: last hop processing {} - {}",
+                    bridgeNode.getNodeId(), serviceFunctionForwarder.getName());
+            short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
+            String sfDplName = sfcUtils.getSfDplName(serviceFunction);
+            long sfOfPort = getSfPort(bridgeNode, sfDplName);
+            sfcClassifierService.programEgressClassifier(dataPathId, vxGpeOfPort, rsp.getPathId(),
+                    lastServiceindex, sfOfPort, 0, true);
+            sfcClassifierService.programEgressClassifierBypass(dataPathId, vxGpeOfPort, rsp.getPathId(),
+                    lastServiceindex, sfOfPort, 0, true);
+        } else {
+            // add typical sff flows
+        }
+
+        sfcClassifierService.programSfcTable(dataPathId, vxGpeOfPort, SFC_TABLE, true);
+    }
+
+    void handleSf(Node bridgeNode, ServiceFunction serviceFunction) {
+        if (isSfOnBridge(bridgeNode, serviceFunction)) {
+            LOG.info("handleSf: sf and bridge are on the same node: {} - {}, adding workaround and arp",
+                    bridgeNode.getNodeId(), serviceFunction.getName());
+            long dataPathId = southbound.getDataPathId(bridgeNode);
+            Ip ip = sfcUtils.getSfIp(serviceFunction);
+            String sfIpAddr = String.valueOf(ip.getIp().getValue());
+            int sfIpPort = ip.getPort().getValue(); //GPE_PORT
+            String sfDplName = sfcUtils.getSfDplName(serviceFunction);
+            long sfOfPort = getSfPort(bridgeNode, sfDplName);
+            String sfMac = getMacFromExternalIds(bridgeNode, sfDplName);
+            if (sfMac == null) {
+                LOG.warn("handleSff: could not find mac for {} on {}", sfDplName, bridgeNode);
+                return;
+            }
+            //should be sffdplport, but they should all be the same 6633/4790
+            sfcClassifierService.program_sfEgress(dataPathId, sfIpPort, true);
+            sfcClassifierService.program_sfIngress(dataPathId, sfIpPort, sfOfPort, sfIpAddr, sfDplName, true);
+            sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpAddr, true);
+        }
+    }
+
+    private boolean isSffOnBridge(Node bridgeNode, ServiceFunctionForwarder serviceFunctionForwarder) {
+        String local_ip = "";
+        Ip ip = sfcUtils.getSffIp(serviceFunctionForwarder);
+        Node ovsdbNode = southbound.readOvsdbNode(bridgeNode);
+        if (ovsdbNode != null) {
+            OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
+            if (ovsdbNodeAugmentation != null && ovsdbNodeAugmentation.getOpenvswitchOtherConfigs() != null) {
+                southbound.getOtherConfig(ovsdbNode, OvsdbTables.OPENVSWITCH, TUNNEL_ENDPOINT_KEY);
+            }
+
+        }
+        return local_ip.equals(String.valueOf(ip.getIp().getValue()));
+    }
+
+    private boolean isSfOnBridge(Node bridgeNode, ServiceFunction serviceFunction) {
+        String sfDplName = sfcUtils.getSfDplName(serviceFunction);
+        long sfOfPort = getSfPort(bridgeNode, sfDplName);
+        return sfOfPort != 0L;
+    }
+
+    private RenderedServicePath getRenderedServicePath (Ace entry) {
+        RenderedServicePath rsp = null;
+        RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
+        LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
+        if (sfcRedirect == null) {
+            LOG.warn("processAClEntry: sfcRedirect is null");
+            return null;
+        }
+
+        if (sfcRedirect.getRspName() != null) {
+            rsp = getRenderedServicePathFromRsp(sfcRedirect.getRspName());
+        } else if (sfcRedirect.getSfpName() != null) {
+            LOG.warn("getRenderedServicePath: sfp not handled yet");
+        } else {
+            rsp = getRenderedServicePathFromSfc(entry);
+        }
+        LOG.info("getRenderedServicePath: rsp: {}", rsp);
+        return rsp;
+    }
+
+    private RenderedServicePath getRenderedServicePathFromRsp(String rspName) {
+        return sfcUtils.getRsp(rspName);
+    }
+
+    private RenderedServicePath getRenderedServicePathFromSfc (Ace entry) {
+        RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
+        LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
+        if (sfcRedirect == null) {
+            LOG.warn("processAClEntry: sfcRedirect is null");
+            return null;
+        }
+
+        String sfcName = sfcRedirect.getSfcName();
+        ServiceFunctionPath sfp = sfcUtils.getSfp(sfcName);
+        if (sfp == null || sfp.getName() == null) {
+            LOG.warn("There is no configured SFP with sfcName = {}; so skip installing the ACL entry!!", sfcName);
+            return null;
+        }
+
+        LOG.debug("Processing Redirect to SFC = {}, SFP = {}", sfcName, sfp);
+        // If RSP doesn't exist, create an RSP.
+        String sfpName = sfp.getName().getValue();
+        RenderedServicePath rsp = sfcUtils.getRspforSfp(sfpName);
+        String rspName = sfp.getName().getValue() + "_rsp";
+        if (rsp == null) {
+            LOG.info("No configured RSP corresponding to SFP = {}, Creating new RSP = {}", sfpName, rspName);
+            CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder()
+                    .setParentServiceFunctionPath(sfpName)
+                    .setName(rspName)
+                    .setSymmetric(sfp.isSymmetric())
+                    .build();
+            rsp = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, rspInput);
+            if (rsp == null) {
+                LOG.warn("failed to add RSP");
+                return null;
+            }
+
+            // If SFP is symmetric, create RSP in the reverse direction.
+            if (sfp.isSymmetric()) {
+                LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName);
+                String rspNameRev = rspName + "-Reverse";
+                RenderedServicePath rspReverse = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
+                        sfcUtils.getRspId(rspNameRev));
+                if (rspReverse == null) {
+                    rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
+                    if (rspReverse == null) {
+                        LOG.warn("failed to add reverse RSP");
+                        return null;
+                    }
+                }
+            }
+        }
+        return rsp;
+    }
+
+    // loop through all ports looking for vxlan types, skip vxgpe, keep the rest
+    // first pass we only have two tunnels: one for normal vxlan and the other for gpe
+    // so just return the first non-gpe vxlan port
+    private long getTunnelOfPort(Node bridgeNode, String vxGpePortName) {
+        long port = 0L;
+        List<OvsdbTerminationPointAugmentation> ovsdbTerminationPointAugmentations =
+                southbound.getTerminationPointsOfBridge(bridgeNode);
+        if (!ovsdbTerminationPointAugmentations.isEmpty()) {
+            for (OvsdbTerminationPointAugmentation terminationPointAugmentation :
+                    ovsdbTerminationPointAugmentations) {
+                if (terminationPointAugmentation.getInterfaceType() ==
+                        SouthboundConstants.OVSDB_INTERFACE_TYPE_MAP.get(NETWORK_TYPE_VXLAN)) {
+                    if (!terminationPointAugmentation.getName().equals(vxGpePortName)) {
+                        port = terminationPointAugmentation.getOfport();
+                        break;
+                    }
+                }
+            }
+        }
+        return port;
+    }
+
+    private long getSfPort(Node bridgeNode, String sfPortName) {
+        long port = 0L;
+        port = getOFPort(bridgeNode, sfPortName);
+        return port;
+    }
+
+    private long getOFPort(Node bridgeNode, String portName) {
+        long ofPort = 0L;
+        OvsdbTerminationPointAugmentation port =
+                southbound.extractTerminationPointAugmentation(bridgeNode, portName);
+        if (port != null) {
+            ofPort = southbound.getOFPort(port);
+        }
+        if (ofPort == 0L) {
+            for (int i = 0; i < 5; i++) {
+                LOG.info("Looking for ofPort {}, try: {}", portName, i);
+                if (ofPort == 0L) {
+                    TerminationPoint tp = southbound.readTerminationPoint(bridgeNode, null, portName);
+                    if (tp != null) {
+                        port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                        if (port != null) {
+                            ofPort = southbound.getOFPort(port);
+                            break;
+                        }
+                    }
+                }
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return ofPort;
+    }
+
+    private String getMacFromOptions(Node bridgeNode, String portName) {
+        String mac = null;
+        OvsdbTerminationPointAugmentation port = southbound.extractTerminationPointAugmentation(bridgeNode, portName);
+        LOG.info("getMac: portName: {}, bridgeNode: {},,, port: {}", portName, bridgeNode, port);
+        if (port != null && port.getOptions() != null) {
+            //mac = southbound.getOptionsValue(port.getOptions(), EXTERNAL_ID_VM_MAC);
+            for (Options option : port.getOptions()) {
+                LOG.info("getMac: option: {}", option);
+                if (option.getOption().equals(Constants.EXTERNAL_ID_VM_MAC)) {
+                    mac = option.getValue();
+                    break;
+                }
+            }
+        }
+        return mac;
+    }
+
+    private String getMacFromExternalIds(Node bridgeNode, String portName) {
+        String mac = null;
+        OvsdbTerminationPointAugmentation port = southbound.getTerminationPointOfBridge(bridgeNode, portName);
+        LOG.info("getMac: portName: {}, bridgeNode: {},,, port: {}", portName, bridgeNode, port);
+        if (port != null && port.getInterfaceExternalIds() != null) {
+            mac = southbound.getInterfaceExternalIdsValue(port, Constants.EXTERNAL_ID_VM_MAC);
+        }
+        return mac;
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        sfcClassifierService =
+                (ISfcClassifierService) ServiceHelper.getGlobalInstance(ISfcClassifierService.class, this);
+        LOG.info("sfcClassifierService= {}", sfcClassifierService);
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/SfcClassifierService.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/SfcClassifierService.java
new file mode 100644 (file)
index 0000000..947dcec
--- /dev/null
@@ -0,0 +1,604 @@
+/*
+ * Copyright Â© 2015 Red Hat, 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.openstack.netvirt.sfc.workaround.services;
+
+import com.google.common.collect.Lists;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface, ISfcClassifierService {
+    private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
+    private static final short TABLE_0 = 0;
+    private static final short UDP_SHORT = 17;
+    static int cookieIndex = 0;
+
+    private enum FlowID {
+        FLOW_INGRESSCLASS(1), FLOW_SFINGRESS(2), FLOW_SFEGRESS(3), FLOW_SFARP(4),
+        FLOW_EGRESSCLASSUNUSED(5), FLOW_EGRESSCLASS(6), FLOW_EGRESSCLASSBYPASS(7), FLOW_SFCTABLE(8);
+
+        private int value;
+        FlowID(int value) {
+            this.value = value;
+        }
+
+    }
+
+    //private AtomicLong flowCookieInc = new AtomicLong(0x1L);
+    private BigInteger getCookie(FlowID flowID) {
+        String cookieString = new String().format("1110%02d%010d", flowID.value, cookieIndex++);
+                //new String().format("1100%02d00%04d", flowID.value, flowCookieInc.getAndIncrement());
+                // "1100%02000000d%04d"
+        return new BigInteger(cookieString, 16);
+    }
+
+    public SfcClassifierService(Service service) {
+        super(service);
+    }
+
+    public SfcClassifierService() {
+        super(Service.SFC_CLASSIFIER);
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(ISfcClassifierService.class.getName()), this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+
+    @Override
+    public void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
+                                         NshUtils nshHeader, long vxGpeOfPort, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = buildMatch(matches);
+        MatchUtils.addNxRegMatch(matchBuilder,
+                MatchUtils.RegMatch.of(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL));
+        MatchUtils.addNxRegMatch(matchBuilder,
+                MatchUtils.RegMatch.of(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        String flowId = "sfcIngressClass_" + ruleName;// + "_" + nshHeader.getNshNsp();
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        flowBuilder.setCookie(new FlowCookie(getCookie(FlowID.FLOW_INGRESSCLASS)));
+
+        if (write) {
+            ActionBuilder ab = new ActionBuilder();
+            List<Action> actionList = new ArrayList<>();
+
+            ab.setAction(ActionUtils.nxMoveTunIdtoNshc2());
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            getNshAction(nshHeader, actionList);
+
+            ab.setAction(ActionUtils.outputAction(FlowUtils.getNodeConnectorId(dataPathId, vxGpeOfPort)));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+
+            InstructionBuilder ib = new InstructionBuilder();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            List<Instruction> instructions = Lists.newArrayList();
+            instructions.add(ib.build());
+
+            InstructionsBuilder isb = new InstructionsBuilder();
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        String flowId = "sfcTable_" + vxGpeOfPort;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        flowBuilder.setPriority(1000);
+        flowBuilder.setCookie(new FlowCookie(getCookie(FlowID.FLOW_SFCTABLE)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(FlowID.FLOW_SFCTABLE)));
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib =
+                    InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), goToTableId);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                         int tunnelOfPort, int tunnelId, short gotoTableId, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
+        MatchUtils.addNxNspMatch(matchBuilder, nsp);
+        MatchUtils.addNxNsiMatch(matchBuilder, nsi);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        String flowId = "sfcEgressClass1_" + vxGpeOfPort;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        flowBuilder.setCookie(new FlowCookie(getCookie(FlowID.FLOW_EGRESSCLASSUNUSED)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(FlowID.FLOW_EGRESSCLASSUNUSED)));
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib = new InstructionBuilder();
+
+            /*List<Action> actionList = Lists.newArrayList();
+
+            ActionBuilder ab = new ActionBuilder();
+            ab.setAction(ActionUtils.nxMoveNshc2ToTunId());
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+            ib.setOrder(instructions.size());
+            ib.setKey(new InstructionKey(instructions.size()));
+            instructions.add(ib.build());*/
+
+            ib = InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), getTable());
+            ib.setOrder(instructions.size());
+            ib.setKey(new InstructionKey(instructions.size()));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                        long sfOfPort, int tunnelId, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
+        MatchUtils.addNxNspMatch(matchBuilder, nsp);
+        MatchUtils.addNxNsiMatch(matchBuilder, nsi);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        String flowId = "sfcEgressClass_" + nsp + "_" + + nsi + "_"  + vxGpeOfPort;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        flowBuilder.setCookie(new FlowCookie(getCookie(FlowID.FLOW_EGRESSCLASS)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(FlowID.FLOW_EGRESSCLASS)));
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            List<Action> actionList = Lists.newArrayList();
+
+            ActionBuilder ab = new ActionBuilder();
+
+            ab.setAction(
+                    ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(FlowUtils.REG_FIELD).build(),
+                    BigInteger.valueOf(FlowUtils.REG_VALUE_FROM_LOCAL)));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            ab.setAction(ActionUtils.nxMoveNshc2ToTunId());
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            ab.setAction(ActionUtils.nxResubmitAction((int)sfOfPort, TABLE_0));
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+            InstructionBuilder ib = new InstructionBuilder();
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                              long sfOfPort, int tunnelId, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, sfOfPort);
+        MatchUtils.addNxRegMatch(matchBuilder,
+                MatchUtils.RegMatch.of(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL));
+        MatchUtils.addNxNspMatch(matchBuilder, nsp);
+        MatchUtils.addNxNsiMatch(matchBuilder, nsi);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        String flowId = "sfcEgressClassBypass_" + nsp + "_" + + nsi + "_"  + sfOfPort;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        flowBuilder.setCookie(new FlowCookie(getCookie(FlowID.FLOW_EGRESSCLASSBYPASS)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(FlowID.FLOW_EGRESSCLASSBYPASS)));
+        flowBuilder.setPriority(40000); //Needs to be above default priority of 32768
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+
+            InstructionBuilder ib;
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    // packet from sf to sff that need to go out local
+    @Override
+    public void program_sfEgress(long dataPathId, int dstPort, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createIpProtocolMatch(matchBuilder, UDP_SHORT);
+        MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort);
+        MatchUtils.addNxRegMatch(matchBuilder,
+                MatchUtils.RegMatch.of(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        String flowId = "sfEgress_" + dstPort;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        flowBuilder.setCookie(new FlowCookie(getCookie(FlowID.FLOW_SFEGRESS)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(FlowID.FLOW_SFEGRESS)));
+
+        if (write) {
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionUtils.createLocalInstructions(ib, dataPathId);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    // looped back sff to sf packets
+    @Override
+    public void program_sfIngress(long dataPathId, int dstPort, long sfOfPort,
+                                  String ipAddress, String sfDplName, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createIpProtocolMatch(matchBuilder, UDP_SHORT);
+        Ipv4Prefix ipCidr = MatchUtils.iPv4PrefixFromIPv4Address(ipAddress);
+        MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(ipCidr));
+        MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        String flowId = "sfIngress_" + dstPort + "_" + ipAddress;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        flowBuilder.setCookie(new FlowCookie(getCookie(FlowID.FLOW_SFINGRESS)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(FlowID.FLOW_SFINGRESS)));
+
+        if (write) {
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionUtils.createOutputPortInstructions(ib, dataPathId, sfOfPort);
+
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
+                                      String ipAddress, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MacAddress macAddress = new MacAddress(macAddressStr);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortReservedMatch(matchBuilder, dataPathId, OutputPortValues.LOCAL.toString());
+        MatchUtils.createEtherTypeMatch(matchBuilder, new EtherType(Constants.ARP_ETHERTYPE));
+        MatchUtils.createArpDstIpv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(ipAddress));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        String flowId = "ArpResponder_" + ipAddress;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setKey(key);
+        flowBuilder.setPriority(1024);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        flowBuilder.setCookie(new FlowCookie(getCookie(FlowID.FLOW_SFARP)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(FlowID.FLOW_SFARP)));
+
+        if (write == true) {
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            List<Action> actionList = Lists.newArrayList();
+
+            // Move Eth Src to Eth Dst
+            ab.setAction(ActionUtils.nxMoveEthSrcToEthDstAction());
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            // Set Eth Src
+            ab.setAction(ActionUtils.setDlSrcAction(new MacAddress(macAddress)));
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            // Set ARP OP
+            ab.setAction(ActionUtils.nxLoadArpOpAction(BigInteger.valueOf(FlowUtils.ARP_OP_REPLY)));
+            ab.setOrder(2);
+            ab.setKey(new ActionKey(2));
+            actionList.add(ab.build());
+
+            // Move ARP SHA to ARP THA
+            ab.setAction(ActionUtils.nxMoveArpShaToArpThaAction());
+            ab.setOrder(3);
+            ab.setKey(new ActionKey(3));
+            actionList.add(ab.build());
+
+            // Move ARP SPA to ARP TPA
+            ab.setAction(ActionUtils.nxMoveArpSpaToArpTpaAction());
+            ab.setOrder(4);
+            ab.setKey(new ActionKey(4));
+            actionList.add(ab.build());
+
+            // Load Mac to ARP SHA
+            ab.setAction(ActionUtils.nxLoadArpShaAction(macAddress));
+            ab.setOrder(5);
+            ab.setKey(new ActionKey(5));
+            actionList.add(ab.build());
+
+            // Load IP to ARP SPA
+            ab.setAction(ActionUtils.nxLoadArpSpaAction(ipAddress));
+            ab.setOrder(6);
+            ab.setKey(new ActionKey(6));
+            actionList.add(ab.build());
+
+            // Output of InPort
+            ab.setAction(ActionUtils.outputAction(
+                    FlowUtils.getSpecialNodeConnectorId(dataPathId, OutputPortValues.INPORT.toString())));
+            ab.setOrder(7);
+            ab.setKey(new ActionKey(7));
+            actionList.add(ab.build());
+
+            // Create Apply Actions Instruction
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    private List<Action> getNshAction(NshUtils header, List<Action> actionList) {
+        // Build the Actions to Add the NSH Header
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC1Load =
+                ActionUtils.nxLoadNshc1RegAction(header.getNshMetaC1());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC2Load =
+                ActionUtils.nxLoadNshc2RegAction(header.getNshMetaC2());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nspLoad =
+                ActionUtils.nxSetNspAction(header.getNshNsp());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nsiLoad =
+                ActionUtils.nxSetNsiAction(header.getNshNsi());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunVnid =
+                ActionUtils.nxLoadTunIdAction(BigInteger.valueOf(header.getNshNsp()), false);
+        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunDest =
+                ActionUtils.nxLoadTunIPv4Action(header.getNshTunIpDst().getValue(), false);
+
+        int count = actionList.size();
+        actionList.add(new ActionBuilder()
+                .setKey(new ActionKey(count)).setOrder(count++).setAction(nshC1Load).build());
+        //actionList.add(new ActionBuilder()
+        // .setKey(new ActionKey(count)).setOrder(count++).setAction(nshC2Load).build());
+        actionList.add(new ActionBuilder()
+                .setKey(new ActionKey(count)).setOrder(count++).setAction(nspLoad).build());
+        actionList.add(new ActionBuilder()
+                .setKey(new ActionKey(count)).setOrder(count++).setAction(nsiLoad).build());
+        actionList.add(new ActionBuilder()
+                .setKey(new ActionKey(count)).setOrder(count++).setAction(loadChainTunDest).build());
+        actionList.add(new ActionBuilder()
+                .setKey(new ActionKey(count)).setOrder(count).setAction(loadChainTunVnid).build());
+        return actionList;
+    }
+
+    public MatchBuilder buildMatch(Matches matches) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+
+        if (matches.getAceType() instanceof AceIp) {
+            AceIp aceIp = (AceIp)matches.getAceType();
+            if (aceIp.getAceIpVersion() instanceof AceIpv4) {
+                //AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
+                //MatchUtils.createSrcL3IPv4Match(matchBuilder, aceIpv4.getSourceIpv4Network());
+                //MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Network());
+                MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
+                MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(), 0,
+                        aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
+            } else {
+                MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
+                MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(), 0,
+                        aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
+            }
+        } else if (matches.getAceType() instanceof AceEth) {
+            AceEth aceEth = (AceEth) matches.getAceType();
+            MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(aceEth.getSourceMacAddress().getValue()));
+            MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(aceEth.getDestinationMacAddress().getValue()),
+                    new MacAddress(aceEth.getDestinationMacAddressMask().getValue()));
+        }
+
+        LOG.info("buildMatch: {}", matchBuilder.build());
+        return matchBuilder;
+    }
+}
index 4709be3238d78a71c6d3ed8b5b5d4a52e905c76d..34dfd96c547b3cbc0cd9c91212b70b39500754a9 100644 (file)
@@ -1,18 +1,30 @@
+/*
+ * Copyright Â© 2015 Red Hat, 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev141210;
 
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.NetvirtSfcProvider;
+import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class NetvirtSfcModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev141210.AbstractNetvirtSfcModule {
-
+public class NetvirtSfcModule extends AbstractNetvirtSfcModule {
     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcModule.class);
+    private BundleContext bundleContext;
 
-    public NetvirtSfcModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+    public NetvirtSfcModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
     }
 
-    public NetvirtSfcModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev141210.NetvirtSfcModule oldModule, java.lang.AutoCloseable oldInstance) {
+    public NetvirtSfcModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver,
+                            NetvirtSfcModule oldModule, java.lang.AutoCloseable oldInstance) {
         super(identifier, dependencyResolver, oldModule, oldInstance);
     }
 
@@ -24,8 +36,13 @@ public class NetvirtSfcModule extends org.opendaylight.yang.gen.v1.urn.opendayli
     @Override
     public java.lang.AutoCloseable createInstance() {
         LOG.info("Netvirt SFC module initialization.");
-        NetvirtSfcProvider sfcProvider = new NetvirtSfcProvider();
+        NetvirtSfcProvider sfcProvider = new NetvirtSfcProvider(bundleContext);
+        sfcProvider.setOf13Provider(getOf13provider());
         getBrokerDependency().registerProvider(sfcProvider);
         return sfcProvider;
     }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
 }
index 60b6cddc04b7505de015da0b32008d1d1cd35a29..276a14aa20b5561f3a20ab37114fdf3c03a1b4c3 100644 (file)
@@ -1,13 +1,32 @@
 /*
-* Generated file
-*
-* Generated from: yang module name: netvirt-sfc yang module local name: netvirt-sfc
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Wed Sep 23 15:18:24 EDT 2015
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+ * Copyright Â© 2015 Red Hat, 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev141210;
 
-public class NetvirtSfcModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev141210.AbstractNetvirtSfcModuleFactory {
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+public class NetvirtSfcModuleFactory extends AbstractNetvirtSfcModuleFactory {
+    @Override
+    public NetvirtSfcModule instantiateModule(String instanceName, DependencyResolver dependencyResolver,
+                                              BundleContext bundleContext) {
+        NetvirtSfcModule module = super.instantiateModule(instanceName, dependencyResolver, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+
+    @Override
+    public NetvirtSfcModule instantiateModule(String instanceName, DependencyResolver dependencyResolver,
+                                              NetvirtSfcModule oldModule, AutoCloseable oldInstance,
+                                              BundleContext bundleContext) {
+        NetvirtSfcModule module = super.instantiateModule(instanceName, dependencyResolver,
+                oldModule, oldInstance, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
 }
index 46b6a5f8379e912ce68fb8aa9b1ca6351f8c5610..2f5d016da2cb08e2412da489d337465083113c1a 100644 (file)
@@ -30,6 +30,10 @@ module netvirt-sfc {
                     }
                 }
             }
+
+            leaf of13provider {
+                type string;
+            }
         }
     }
 }
index 7b6f065a38badcb0119e3372e5ca12e27d287b90..ecc9c11f116fe42a1906e6762f2e8811fadcedac 100644 (file)
@@ -5,25 +5,42 @@
  * 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev141210;
 
+import java.util.Dictionary;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.NetvirtSfcProvider;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 
 import javax.management.ObjectName;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.standalone.openflow13.services.SfcClassifierService;
+import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+@PrepareForTest(ServiceHelper.class)
+@RunWith(PowerMockRunner.class)
 public class NetvirtSfcModuleTest {
     @Test
     public void testCustomValidation() {
@@ -33,6 +50,7 @@ public class NetvirtSfcModuleTest {
         module.customValidation();
     }
 
+    @SuppressWarnings("unchecked")
     @Test
     public void testCreateInstance() throws Exception {
         // configure mocks
@@ -40,13 +58,33 @@ public class NetvirtSfcModuleTest {
         BindingAwareBroker broker = mock(BindingAwareBroker.class);
         ProviderContext session = mock(ProviderContext.class);
         DataBroker dataBroker = mock(DataBroker.class);
-        when(dependencyResolver.resolveInstance(eq(BindingAwareBroker.class), any(ObjectName.class), any(JmxAttribute.class))).thenReturn(broker);
+        when(dependencyResolver.resolveInstance(eq(BindingAwareBroker.class),
+                any(ObjectName.class), any(JmxAttribute.class))).thenReturn(broker);
         when(session.getSALService(eq(DataBroker.class))).thenReturn(dataBroker);
 
         // create instance of module with injected mocks
         NetvirtSfcModule module = new NetvirtSfcModule(mock(ModuleIdentifier.class), dependencyResolver);
         // getInstance calls resolveInstance to get the broker dependency and then calls createInstance
+        BundleContext bundleContext = mock(BundleContext.class);
+        PowerMockito.mockStatic(ServiceHelper.class);
+        PipelineOrchestrator pipelineOrchestrator = mock(PipelineOrchestrator.class);
+        PowerMockito.when(ServiceHelper.getGlobalInstance(eq(PipelineOrchestrator.class), any(AbstractServiceInstance.class)))
+                .thenReturn(pipelineOrchestrator);
+        PowerMockito.when(ServiceHelper.getGlobalInstance(eq(Southbound.class), any(AbstractServiceInstance.class)))
+                .thenReturn(mock(Southbound.class));
+
+        doNothing().when(pipelineOrchestrator).registerService(any(ServiceReference.class),
+                any(AbstractServiceInstance.class));
+        when(bundleContext.registerService(
+                eq(new String[]{AbstractServiceInstance.class.getName(), SfcClassifierService.class.getName()}),
+                any(),
+                any(Dictionary.class)))
+                .thenReturn(mock(ServiceRegistration.class));
+        when(bundleContext.getServiceReference(SfcClassifierService.class.getName()))
+                .thenReturn(mock(ServiceReference.class));
         AutoCloseable closeable = module.getInstance();
+        ((NetvirtSfcProvider)closeable).setBundleContext(bundleContext);
+        ((NetvirtSfcProvider)closeable).setOf13Provider("standalone");
         ((NetvirtSfcProvider)closeable).onSessionInitiated(session);
         // verify that the module registered the returned provider with the broker
         verify(broker).registerProvider((NetvirtSfcProvider)closeable);
index 9075b486ecd3a937bfcc631f9cf43355ed1adbea..67b04335ea4996eb339b72c38423e5b922297b12 100644 (file)
@@ -49,6 +49,12 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>openstack.net-virt-sfc-features-test</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-openflow</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>utils.mdsal-utils</artifactId>
index 49e8c6958ca47e02e2ad6854d884b3038ba8b2a0..08a1f0069560fc98dc0c3f1d555de973ea8876bb 100644 (file)
@@ -15,18 +15,27 @@ import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.ops4j.pax.exam.CoreOptions.composite;
 import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
 import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
 import static org.ops4j.pax.exam.CoreOptions.vmOption;
+import static org.ops4j.pax.exam.CoreOptions.when;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
 
+import com.google.common.collect.Maps;
 import java.io.IOException;
+import java.math.BigInteger;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
@@ -34,26 +43,58 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
-import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.NshUtils;
-import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.SfcClassifier;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.standalone.openflow13.SfcClassifier;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.AclUtils;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ClassifierUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionChainUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionPathUtils;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionForwarderUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionUtils;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.southbound.SouthboundUtil;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctions;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.ServiceFunctionChains;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.ServiceFunctionChainsBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChainBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunction;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunctionBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwarders;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwardersBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPathsBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sft.rev140701.Firewall;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
 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.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.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.ClassifiersBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.ClassifierBuilder;
@@ -76,6 +117,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.karaf.options.LogLevelOption;
 import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
 import org.ops4j.pax.exam.options.MavenUrlReference;
 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
@@ -90,6 +132,10 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     private static AclUtils aclUtils = new AclUtils();
     private static ClassifierUtils classifierUtils = new ClassifierUtils();
     private static SfcUtils sfcUtils = new SfcUtils();
+    private static ServiceFunctionUtils serviceFunctionUtils = new ServiceFunctionUtils();
+    private static ServiceFunctionForwarderUtils serviceFunctionForwarderUtils = new ServiceFunctionForwarderUtils();
+    private static ServiceFunctionChainUtils serviceFunctionChainUtils = new ServiceFunctionChainUtils();
+    private static ServiceFunctionPathUtils serviceFunctionPathUtils = new ServiceFunctionPathUtils();
     private static MdsalUtils mdsalUtils;
     private static AtomicBoolean setup = new AtomicBoolean(false);
     private static SouthboundUtils southboundUtils;
@@ -107,6 +153,26 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     public static final String DEFAULT_SERVER_PORT = "6640";
     public static final String INTEGRATION_BRIDGE_NAME = "br-int";
     private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
+    private static final String OVSDB_TRACE = "ovsdb.trace";
+    private static final String SF1NAME = "firewall-72";
+    private static final String SF2NAME = "dpi-72";
+    private static final String SF1IP = "10.2.1.1";//"192.168.50.70";//"192.168.120.31";
+    private static final String SF2IP = "10.2.1.2";
+    private static final String SF1DPLNAME = "sf1";
+    private static final String SF2DPLNAME = "sf2";
+    private static final String SFF1IP = "127.0.0.1"; //"192.168.1.129"
+    private static final String SFF2IP = "192.168.1.129";//"127.0.0.1";
+    private static final String SFF1NAME = "SFF1";
+    private static final String SFF2NAME = "SFF2";
+    private static final String SFFDPL1NAME = "vxgpe";
+    private static final String SFFDPL2NAME = "vxgpe";
+    private static final String SN1NAME = "OVSDB1";
+    private static final String SN2NAME = "OVSDB2";
+    private static final String BRIDGE1NAME= "br-int";
+    private static final String BRIDGE2NAME= "br-int";
+    private static final String ACLNAME= "httpAcl";
+    private static final String SFCNAME = "SFC";
+    private static final int GPEPORT = 6633;
 
     @Override
     public String getModuleName() {
@@ -149,30 +215,45 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
 
     private Option[] getOtherOptions() {
         return new Option[] {
+                wrappedBundle(
+                        mavenBundle("org.opendaylight.ovsdb", "utils.mdsal-openflow")
+                                .version(asInProject())
+                                .type("jar")),
                 configureConsole().startLocalConsole(),
                 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
-                keepRuntimeFolder()
+                        keepRuntimeFolder()
         };
     }
 
     public Option[] getPropertiesOptions() {
         return new Option[] {
-                propagateSystemProperties(SERVER_IPADDRESS, SERVER_PORT, CONNECTION_TYPE, CONTROLLER_IPADDRESS),
+                propagateSystemProperties(SERVER_IPADDRESS, SERVER_PORT, CONNECTION_TYPE,
+                        CONTROLLER_IPADDRESS, OVSDB_TRACE),
         };
     }
 
     @Override
     public Option getLoggingOption() {
         return composite(
+                when(Boolean.getBoolean(OVSDB_TRACE)).useOptions(
+                        editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                                "log4j.logger.org.opendaylight.ovsdb",
+                                LogLevelOption.LogLevel.TRACE.name())),
+                //editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                //        "log4j.logger.org.opendaylight.ovsdb",
+                //        LogLevelOption.LogLevel.TRACE.name()),
                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
                         logConfiguration(NetvirtSfcIT.class),
                         LogLevel.INFO.name()),
                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
                         "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc",
                         LogLevel.TRACE.name()),
-                /*editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
-                        "log4j.logger.org.opendaylight.ovsdb",
-                        LogLevelOption.LogLevel.TRACE.name()),*/
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13",
+                        LogLevel.TRACE.name()),
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.sfc",
+                        LogLevel.TRACE.name()),
                 super.getLoggingOption());
     }
 
@@ -194,6 +275,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
                 fail(usage());
             }
         }
+        LOG.info("getProperties {}: {}", OVSDB_TRACE, props.getProperty(OVSDB_TRACE));
     }
 
     @Before
@@ -282,68 +364,256 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         assertTrue(true);
     }
 
-    private AccessListsBuilder setAccessLists () {
-        MatchesBuilder matchesBuilder = aclUtils.createMatches(new MatchesBuilder(), 80);
-        ActionsBuilder actionsBuilder = aclUtils.createActions(new ActionsBuilder(), Boolean.TRUE);
-        AceBuilder accessListEntryBuilder = aclUtils.createAccessListEntryBuilder(
-                new AceBuilder(), "http", matchesBuilder, actionsBuilder);
-        AccessListEntriesBuilder accessListEntriesBuilder = aclUtils.createAccessListEntries(
-                new AccessListEntriesBuilder(), accessListEntryBuilder);
-        AclBuilder accessListBuilder = aclUtils.createAccessList(new AclBuilder(),
-                "http", accessListEntriesBuilder);
-        AccessListsBuilder accessListsBuilder = aclUtils.createAccessLists(new AccessListsBuilder(),
-                accessListBuilder);
+    private AccessListsBuilder accessListsBuilder() {
+        MatchesBuilder matchesBuilder = aclUtils.matchesBuilder(new MatchesBuilder(), 80);
+        LOG.info("Matches: {}", matchesBuilder.build());
+        //ActionsBuilder actionsBuilder = aclUtils.actionsBuilder(new ActionsBuilder(), Boolean.TRUE);
+        ActionsBuilder actionsBuilder = aclUtils.actionsBuilder(new ActionsBuilder(), SFCNAME);
+        AceBuilder accessListEntryBuilder =
+                aclUtils.aceBuilder(new AceBuilder(), "httpRule", matchesBuilder, actionsBuilder);
+        AccessListEntriesBuilder accessListEntriesBuilder =
+                aclUtils.accessListEntriesBuidler(new AccessListEntriesBuilder(), accessListEntryBuilder);
+        AclBuilder accessListBuilder =
+                aclUtils.aclBuilder(new AclBuilder(), ACLNAME, accessListEntriesBuilder);
+        AccessListsBuilder accessListsBuilder =
+                aclUtils.accesslistsbuilder(new AccessListsBuilder(), accessListBuilder);
         LOG.info("AccessLists: {}", accessListsBuilder.build());
         return accessListsBuilder;
     }
 
     @Test
-    public void testAccessLists() {
-        testModel(setAccessLists(), AccessLists.class);
+    public void testAccessLists() throws InterruptedException {
+        testModel(accessListsBuilder(), AccessLists.class, 0);
     }
 
-    private ClassifiersBuilder setClassifiers() {
-        SffBuilder sffBuilder = classifierUtils.createSff(new SffBuilder(), "sffname");
-        SffsBuilder sffsBuilder = classifierUtils.createSffs(new SffsBuilder(), sffBuilder);
-        ClassifierBuilder classifierBuilder = classifierUtils.createClassifier(new ClassifierBuilder(),
-                "classifierName", "aclName", sffsBuilder);
-        ClassifiersBuilder classifiersBuilder = classifierUtils.createClassifiers(new ClassifiersBuilder(),
+    private ClassifiersBuilder classifiersBuilder() {
+        SffBuilder sffBuilder = classifierUtils.sffBuilder(new SffBuilder(), SFF1NAME);
+        SffsBuilder sffsBuilder = classifierUtils.sffsBuilder(new SffsBuilder(), sffBuilder);
+        ClassifierBuilder classifierBuilder = classifierUtils.classifierBuilder(new ClassifierBuilder(),
+                "classifierName", ACLNAME, sffsBuilder);
+        ClassifiersBuilder classifiersBuilder = classifierUtils.ClassifiersBuilder(new ClassifiersBuilder(),
                 classifierBuilder);
         LOG.info("Classifiers: {}", classifiersBuilder.build());
         return classifiersBuilder;
     }
 
     @Test
-    public void testClassifiers() {
-        testModel(setClassifiers(), Classifiers.class);
+    public void testClassifiers() throws InterruptedException {
+        testModel(classifiersBuilder(), Classifiers.class, 0);
     }
 
-    private SfcBuilder setSfc() {
-        return sfcUtils.createSfc(new SfcBuilder(), "sfc");
+    private SfcBuilder netvirtSfcBuilder() {
+        return sfcUtils.sfcBuilder(new SfcBuilder(), "sfc");
     }
 
     @Test
-    public void testSfc() {
-        testModel(setSfc(), Sfc.class);
+    public void testNetvirtSfcModel() throws InterruptedException {
+        testModel(netvirtSfcBuilder(), Sfc.class, 0);
     }
 
-    private <T extends DataObject> void testModel(Builder<T> builder, Class<T> clazz) {
+    private <T extends DataObject> void testModelPut(Builder<T> builder, Class<T> clazz) {
         InstanceIdentifier<T> path = InstanceIdentifier.create(clazz);
         assertTrue(mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, path, builder.build()));
         T result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
         assertNotNull(clazz.getSimpleName() + " should not be null", result);
+    }
+
+    private <T extends DataObject> void testModelDelete(Builder<T> builder, Class<T> clazz)
+            throws InterruptedException {
+        InstanceIdentifier<T> path = InstanceIdentifier.create(clazz);
         assertTrue("Failed to remove " + clazz.getSimpleName(),
                 mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, path));
-        result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
+        result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
         assertNull(clazz.getSimpleName() + " should be null", result);
     }
 
+    private <T extends DataObject> void testModel(Builder<T> builder, Class<T> clazz, long wait)
+            throws InterruptedException {
+        testModelPut(builder, clazz);
+        Thread.sleep(wait);
+        testModelDelete(builder, clazz);
+    }
+
+    private ServiceFunctionsBuilder serviceFunctionsBuilder() {
+        String sf1Name = SF1NAME;
+        String sf1Ip = SF1IP;
+        String sff1Ip = SF1IP;
+        String sff1Name = SFF1NAME;
+        String sf1DplName = SF1DPLNAME;
+        String sn1Name = SN1NAME;
+        String bridge1Name= BRIDGE1NAME;
+        String sf2Name = SF2NAME;
+        String sf2Ip = SF2IP;
+        String sff2Ip = SF2IP;
+        String sff2Name = SFF2NAME;
+        String sf2DplName = SF2DPLNAME;
+        String sn2Name = SN2NAME;
+        String bridge2Name= BRIDGE2NAME;
+        int port = GPEPORT;
+
+        ServiceFunctionBuilder serviceFunctionBuilder =
+                serviceFunctionUtils.serviceFunctionBuilder(sf1Ip, port, sf1DplName, sff1Name, sf1Name);
+        List<ServiceFunction> serviceFunctionList = serviceFunctionUtils.list(
+                new ArrayList<ServiceFunction>(), serviceFunctionBuilder);
+
+        //serviceFunctionBuilder =
+        //        serviceFunctionUtils.serviceFunctionBuilder(sf2Ip, port, sffDpl2Name, sff2Name, sf2Name);
+        //serviceFunctionList = serviceFunctionUtils.list(
+        //        serviceFunctionList, serviceFunctionBuilder);
+
+        ServiceFunctionsBuilder serviceFunctionsBuilder =
+                serviceFunctionUtils.serviceFunctionsBuilder(new ServiceFunctionsBuilder(),
+                        serviceFunctionList);
+        LOG.info("ServiceFunctions: {}", serviceFunctionsBuilder.build());
+        return serviceFunctionsBuilder;
+    }
+
+    private ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder() {
+        String sf1Name = SF1NAME;
+        String sf1Ip = SF1IP;
+        String sff1Ip = SFF1IP;
+        String sff1Name = SFF1NAME;
+        String sffDpl1Name = SFFDPL1NAME;
+        String sn1Name = SN1NAME;
+        String bridge1Name= BRIDGE1NAME;
+        String sf2Name = SF2NAME;
+        String sf2Ip = SF2IP;
+        String sff2Ip = SFF2IP;
+        String sff2Name = SFF2NAME;
+        String sffDpl2Name = SFFDPL2NAME;
+        String sn2Name = SN2NAME;
+        String bridge2Name= BRIDGE2NAME;
+        String aclName = ACLNAME;
+        int port = GPEPORT;
+
+        ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder =
+                serviceFunctionForwarderUtils.serviceFunctionForwarderBuilder(
+                        sff1Name, sff1Ip, port, sffDpl1Name, sf1Name, sf1Ip, sn1Name, bridge1Name, Firewall.class);
+        List<ServiceFunctionForwarder>  serviceFunctionForwarderList = serviceFunctionForwarderUtils.list(
+                new ArrayList<ServiceFunctionForwarder>(), serviceFunctionForwarderBuilder);
+
+        //serviceFunctionForwarderBuilder =
+        //        serviceFunctionForwarderUtils.serviceFunctionForwarderBuilder(
+        //                sff2Name, sff2Ip, port, sffDpl2Name, sf2Name, sff2Ip, sn2Name, bridge2Name, Dpi.class);
+        //serviceFunctionForwarderList = serviceFunctionForwarderUtils.list(
+        //        serviceFunctionForwarderList, serviceFunctionForwarderBuilder);
+
+        ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder =
+                serviceFunctionForwarderUtils.serviceFunctionForwardersBuilder(
+                        new ServiceFunctionForwardersBuilder(), serviceFunctionForwarderList);
+        LOG.info("ServiceFunctionForwarders: {}", serviceFunctionForwardersBuilder.build());
+        return serviceFunctionForwardersBuilder;
+    }
+
+    private ServiceFunctionChainsBuilder serviceFunctionChainsBuilder() {
+        String sf1Name = "firewall-abstract1";
+        String sf2Name = "dpi-abstract1";
+        String sfcName = SFCNAME;
+
+        SfcServiceFunctionBuilder sfcServiceFunctionBuilder = serviceFunctionChainUtils.sfcServiceFunctionBuilder(
+                new SfcServiceFunctionBuilder(), sf1Name, Firewall.class);
+        List<SfcServiceFunction> sfcServiceFunctionList =
+                serviceFunctionChainUtils.list(new ArrayList<SfcServiceFunction>(), sfcServiceFunctionBuilder);
+
+        //sfcServiceFunctionBuilder = serviceFunctionChainUtils.sfcServiceFunctionBuilder(
+        //        sfcServiceFunctionBuilder, sf2Name, Dpi.class);
+        //sfcServiceFunctionList = serviceFunctionChainUtils.list(sfcServiceFunctionList, sfcServiceFunctionBuilder);
+
+        ServiceFunctionChainBuilder serviceFunctionChainBuilder =
+                serviceFunctionChainUtils.serviceFunctionChainBuilder(
+                        new ServiceFunctionChainBuilder(), sfcName, false, sfcServiceFunctionList);
+        ServiceFunctionChainsBuilder serviceFunctionChainsBuilder =
+                serviceFunctionChainUtils.serviceFunctionChainsBuilder(
+                        new ServiceFunctionChainsBuilder(),
+                        serviceFunctionChainUtils.list(new ArrayList<ServiceFunctionChain>(),
+                                serviceFunctionChainBuilder));
+        LOG.info("ServiceFunctionChains: {}", serviceFunctionChainBuilder.build());
+        return serviceFunctionChainsBuilder;
+    }
+
+    private ServiceFunctionPathsBuilder serviceFunctionPathsBuilder() {
+        String sfpName = "SFC-Path";
+        String sfcName = "SFC";
+        short startingIndex = 255;
+
+        ServiceFunctionPathBuilder serviceFunctionPathBuilder =
+                serviceFunctionPathUtils.serviceFunctionPathBuilder(
+                        new ServiceFunctionPathBuilder(), sfpName, sfcName, startingIndex, false);
+        ServiceFunctionPathsBuilder serviceFunctionPathsBuilder =
+                serviceFunctionPathUtils.serviceFunctionPathsBuilder(
+                        serviceFunctionPathUtils.list(new ArrayList<ServiceFunctionPath>(),
+                                serviceFunctionPathBuilder));
+        LOG.info("ServiceFunctionPaths: {}", serviceFunctionPathsBuilder.build());
+        return serviceFunctionPathsBuilder;
+    }
+
+    @Test
+    public void testSfcModel() throws InterruptedException {
+        testModel(serviceFunctionsBuilder(), ServiceFunctions.class, 3000);
+        testModel(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class, 3000);
+        testModel(serviceFunctionChainsBuilder(), ServiceFunctionChains.class, 3000);
+        testModel(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class, 3000);
+    }
+
+    @Test
+    public void testSfcModels() throws InterruptedException {
+        String bridgeName = INTEGRATION_BRIDGE_NAME;
+        ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(addressStr, portStr);
+        assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
+        Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
+        assertNotNull("node is not connected", ovsdbNode);
+
+        Thread.sleep(5000);
+        Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
+        assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
+        long datapathId = southbound.getDataPathId(bridgeNode);
+
+        Map<String, String> externalIds = Maps.newHashMap();
+        externalIds.put("attached-mac", "f6:00:00:0f:00:01");
+        southboundUtils.addTerminationPoint(bridgeNode, null, SF1DPLNAME, "internal", null, externalIds);
+        southboundUtils.addTerminationPoint(bridgeNode, null, "vm1", "internal");
+        southboundUtils.addTerminationPoint(bridgeNode, null, "vm2", "internal");
+        Map<String, String> options = Maps.newHashMap();
+        options.put("key", "flow");
+        options.put("remote_ip", "192.168.120.32");
+        southboundUtils.addTerminationPoint(bridgeNode, null, "vx", "vxlan", options, null);
+        Thread.sleep(1000);
+
+        testModelPut(serviceFunctionsBuilder(), ServiceFunctions.class);
+        testModelPut(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class);
+        testModelPut(serviceFunctionChainsBuilder(), ServiceFunctionChains.class);
+        testModelPut(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class);
+
+        Thread.sleep(5000);
+
+        testModelPut(accessListsBuilder(), AccessLists.class);
+        testModelPut(classifiersBuilder(), Classifiers.class);
+
+        Thread.sleep(10000);
+
+        ISfcClassifierService sfcClassifierService = (ISfcClassifierService) ServiceHelper.getGlobalInstance(ISfcClassifierService.class, this);
+        LOG.info("SfcClassifierService: {}", sfcClassifierService);
+        readwait();
+        //sfcClassifierService.programIngressClassifier(datapathId);
+
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
+        FlowBuilder flowBuilder = getSfcIngressClassifierFlowBuilder();
+        Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+        assertNotNull("Could not find flow in config", flow);
+        flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+        assertNotNull("Could not find flow in operational", flow);
+
+        assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
+        Thread.sleep(1000);
+        assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
+    }
+
     /*
      * Connect to an ovsdb node. Netvirt should add br-int, add the controller address
      * and program the pipeline flows.
      */
     @Test
-    public void testDoIt() throws InterruptedException {
+    public void testNetvirtSfc() throws InterruptedException {
         String bridgeName = INTEGRATION_BRIDGE_NAME;
         ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(addressStr, portStr);
         assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
@@ -354,86 +624,43 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         for (int i = 0; i < 10; i++) {
             ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
             assertNotNull("ovsdb node not found", ovsdbNode);
-            String controllerTarget = "tcp:192.168.50.1:6653";//SouthboundUtil.getControllerTarget(ovsdbNode);
+            String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
             assertNotNull("Failed to get controller target", controllerTarget);
             OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, bridgeName);
-            assertNotNull(bridge);
-            assertNotNull(bridge.getControllerEntry());
-            controllerEntry = bridge.getControllerEntry().iterator().next();
-            assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
-            if (controllerEntry.isIsConnected()) {
-                Assert.assertTrue(controllerEntry.isIsConnected());
-                break;
+            if (bridge != null) {
+                assertNotNull("Failed to read bridge", bridge);
+                assertNotNull("Failed to extract controllerEntry", bridge.getControllerEntry());
+                controllerEntry = bridge.getControllerEntry().iterator().next();
+                assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
+                if (controllerEntry.isIsConnected()) {
+                    Assert.assertTrue("switch is not connected to the controller", controllerEntry.isIsConnected());
+                    break;
+                }
             }
             Thread.sleep(1000);
         }
 
-        /* TODO: add code to write to mdsal to exercise the sfc dataChangeListener */
-        /* allow some time to let the impl code do it's work to push flows */
-        /* or just comment out below lines and just manually verify on the bridges and reset them */
+        Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
+        assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
+        long datapathId = southbound.getDataPathId(bridgeNode);
+
         //Thread.sleep(10000);
 
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
+        FlowBuilder flowBuilder = FlowUtils.getPipelineFlow(Service.SFC_CLASSIFIER.getTable(), (short)0);
+        Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+        assertNotNull("Could not find flow in config", flow);
+        flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+        assertNotNull("Could not find flow in operational", flow);
+
         assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
         Thread.sleep(1000);
         assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
     }
 
+    @Ignore
     @Test
-    public void testDemo() throws InterruptedException {
-        for (DemoVm vm : demoVms){
-            ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(vm.ipAddr, vm.ipPort);
-            assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
-            Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
-            assertNotNull("node is not connected", ovsdbNode);
-            String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
-            assertNotNull("Failed to get controller target", controllerTarget);
-            List<ControllerEntry> setControllerEntry = southboundUtils.createControllerEntry(controllerTarget);
-            Uri setUri = new Uri(controllerTarget);
-            assertTrue(southboundUtils.addBridge(connectionInfo, null, vm.name, null, true,
-                    SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
-                    setControllerEntry, null));
-
-            for (int i = 0; i < 10; i++) {
-                OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, vm.name);
-                assertNotNull("bridge was not found: " + vm.name, bridge);
-                assertNotNull("ControllerEntry was not found: "
-                                + southboundUtils.createControllerEntry(controllerTarget),
-                        bridge.getControllerEntry());
-                List<ControllerEntry> getControllerEntries = bridge.getControllerEntry();
-                for (ControllerEntry entry : getControllerEntries) {
-                    if (entry.isIsConnected()) {
-                        assertTrue(entry.isIsConnected());
-                        break;
-                    }
-                }
-                Thread.sleep(1000);
-            }
-
-            assertTrue(southboundUtils.deleteBridge(connectionInfo, vm.name));
-            Thread.sleep(1000);
-            assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
-        }
-    }
-
-    private class DemoVm {
-        String name;
-        String ipAddr;
-        String ipPort;
-
-        DemoVm(String name, String ipAddr, String ipPort) {
-            this.name = name;
-            this.ipAddr = ipAddr;
-            this.ipPort = ipPort;
-        }
-    }
-
-    private DemoVm[] demoVms = {
-            new DemoVm("sw1", "192.168.50.70", "6640"),
-            //new DemoVm("sw2", "192.168.50.71", "6640"),
-    };
-
-    @Test
-    public void testDoIt2() throws InterruptedException {
+    public void testStandalone() throws InterruptedException {
         String bridgeName = "sw1";
         ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(addressStr, portStr);
         assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
@@ -461,30 +688,152 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
             Thread.sleep(1000);
         }
 
-        SfcClassifier sfcClassifier = new SfcClassifier(dataBroker, southbound, mdsalUtils);
         Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
         assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
         long datapathId = southbound.getDataPathId(bridgeNode);
-        //sfcClassifier.programSfcClassiferFlows();
-        sfcClassifier.programLocalInPort(datapathId, "4096", (long)1, (short)0, (short)50, true);
+
+        SfcClassifier sfcClassifier = new SfcClassifier(dataBroker, southbound, mdsalUtils);
+        //sfcClassifier.programLocalInPort(datapathId, "4096", (long)1, (short)0, (short)50, true);
 
         NshUtils nshUtils = new NshUtils(new Ipv4Address("192.168.50.71"), new PortNumber(6633),
                 (long)10, (short)255, (long)4096, (long)4096);
-        MatchesBuilder matchesBuilder = aclUtils.createMatches(new MatchesBuilder(), 80);
-        sfcClassifier.programSfcClassiferFlows(datapathId, (short)50, "test", matchesBuilder.build(),
+        MatchesBuilder matchesBuilder = aclUtils.matchesBuilder(new MatchesBuilder(), 80);
+        sfcClassifier.programSfcClassiferFlows(datapathId, (short)0, "test", matchesBuilder.build(),
                 nshUtils, (long)2, true);
 
+        nshUtils = new NshUtils(null, null, (long)10, (short)253, 0, 0);
+        //sfcClassifier.programEgressSfcClassiferFlows(datapathId, (short)0, "test", null,
+        //        nshUtils, (long)2, (long)3, true);
+
         //try {
         //    System.in.read();
         //} catch (IOException e) {
         //    e.printStackTrace();
         //}
 
-        Thread.sleep(15000);
+        //NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
+        //FlowBuilder flowBuilder = getLocalInPortFlow(datapathId, "4096", (long) 1, (short) 0);
+        //Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+        //assertNotNull("Could not find flow in config", flow);
+        //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+        //assertNotNull("Could not find flow in operational", flow);
+
+        MatchBuilder matchBuilder = sfcClassifier.buildMatch(matchesBuilder.build());
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
+        FlowBuilder flowBuilder = getSfcClassifierFlow(datapathId, (short) 0, "test", null,
+                nshUtils, (long) 2, matchBuilder);
+        Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+        assertNotNull("Could not find flow in config", flow);
+        flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+        assertNotNull("Could not find flow in operational", flow);
+
+        //nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
+        //flowBuilder = getEgressSfcClassifierFlow(datapathId, (short) 0, "test", nshUtils, (long) 2);
+        //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+        //assertNotNull("Could not find flow in config", flow);
+        //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+        //assertNotNull("Could not find flow in operational", flow);
+
+        LOG.info("***** Go look for flows *****");
+        Thread.sleep(30000);
         assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
         Thread.sleep(1000);
         assertTrue(southboundUtils.deleteBridge(connectionInfo, INTEGRATION_BRIDGE_NAME));
         Thread.sleep(1000);
         assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
     }
+
+    private FlowBuilder getLocalInPortFlow(long dpidLong, String segmentationId, long inPort, short writeTable) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort).build());
+        String flowId = "sfcIngress_" + segmentationId + "_" + inPort;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(true);
+        flowBuilder.setBarrier(false);
+        flowBuilder.setTableId(writeTable);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        return flowBuilder;
+    }
+
+    public FlowBuilder getSfcClassifierFlow(long dpidLong, short writeTable, String ruleName, Matches match,
+                                             NshUtils nshHeader, long tunnelOfPort, MatchBuilder matchBuilder) {
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(matchBuilder.build());
+
+        String flowId = "sfcClass_" + ruleName + "_" + nshHeader.getNshNsp();
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(writeTable);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        return flowBuilder;
+    }
+
+    private FlowBuilder getEgressSfcClassifierFlow(long dpidLong, short writeTable, String ruleName,
+                                                   NshUtils nshHeader, long tunnelOfPort) {
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, tunnelOfPort).build());
+        flowBuilder.setMatch(
+                MatchUtils.createTunnelIDMatch(matchBuilder, BigInteger.valueOf(nshHeader.getNshNsp())).build());
+        flowBuilder.setMatch(MatchUtils.addNxNspMatch(matchBuilder, nshHeader.getNshNsp()).build());
+        flowBuilder.setMatch(MatchUtils.addNxNsiMatch(matchBuilder, nshHeader.getNshNsi()).build());
+
+        String flowId = "egressSfcClass_" + ruleName + "_" + nshHeader.getNshNsp() + "_" + nshHeader.getNshNsi();
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(true);
+        flowBuilder.setBarrier(false);
+        flowBuilder.setTableId(writeTable);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        return flowBuilder;
+    }
+
+    private FlowBuilder getSfcIngressClassifierFlowBuilder() {
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowId = "sfcClass_" + "httpRule";
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setTableId((short)10);
+        return flowBuilder;
+    }
+
+    private Flow getFlow (FlowBuilder flowBuilder, NodeBuilder nodeBuilder, LogicalDatastoreType store)
+            throws InterruptedException {
+        Flow flow = null;
+        for (int i = 0; i < 10; i++) {
+            flow = FlowUtils.getFlow(flowBuilder, nodeBuilder, dataBroker.newReadOnlyTransaction(), store);
+            if (flow != null) {
+                LOG.info("getFlow: flow: {}: {}", store, flow);
+                break;
+            }
+            Thread.sleep(1000);
+        }
+        return flow;
+    }
+
+    private void readwait() {
+        try {
+            System.in.read();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
 }
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/AbstractUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/AbstractUtils.java
new file mode 100644 (file)
index 0000000..5258547
--- /dev/null
@@ -0,0 +1,29 @@
+package org.opendaylight.ovsdb.openstack.netvirt.sfc.utils;
+
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.sff.data.plane.locator.DataPlaneLocatorBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.IpBuilder;
+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.PortNumber;
+import org.opendaylight.yangtools.concepts.Builder;
+
+public abstract class AbstractUtils {
+    public <T> List<T> list(List<T> list, Builder<T> builder) {
+        list.add(builder.build());
+        return list;
+    }
+
+    public IpBuilder ipBuilder(String ip, int port) {
+        return new IpBuilder()
+                .setIp(new IpAddress(ip.toCharArray()))
+                .setPort(new PortNumber(port));
+    }
+
+    public DataPlaneLocatorBuilder dataPlaneLocatorBuilder(DataPlaneLocatorBuilder dataPlaneLocatorBuilder,
+                                                           String ip, int port) {
+        return dataPlaneLocatorBuilder
+                .setLocatorType(ipBuilder(ip, port).build())
+                .setTransport(VxlanGpe.class);
+    }
+}
index dd6cce50dce3072505e21e58898bb567e934cdf6..7657f2eee31f6ee07089e16679a761ba7d4d3544 100644 (file)
@@ -20,65 +20,68 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.cont
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.PermitBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder;
 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.packet.fields.rev150611.acl.transport.header.fields.DestinationPortRangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfcBuilder;
 
-public class AclUtils {
-    public MatchesBuilder createMatches (MatchesBuilder matchesBuilder, int destPort) {
+public class AclUtils extends AbstractUtils {
+    public MatchesBuilder matchesBuilder(MatchesBuilder matchesBuilder, int destPort) {
         PortNumber portNumber = new PortNumber(destPort);
-        DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder();
-        destinationPortRangeBuilder.setLowerPort(portNumber);
-        destinationPortRangeBuilder.setUpperPort(portNumber);
+        DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder()
+                .setLowerPort(portNumber)
+                .setUpperPort(portNumber);
 
-        AceIpBuilder aceIpBuilder = new AceIpBuilder();
-        aceIpBuilder.setDestinationPortRange(destinationPortRangeBuilder.build());
-        matchesBuilder.setAceType(aceIpBuilder.build());
+        AceIpBuilder aceIpBuilder = new AceIpBuilder()
+                .setDestinationPortRange(destinationPortRangeBuilder.build())
+                .setProtocol((short)6)
+                .setAceIpVersion(new AceIpv4Builder().build());
 
-        return matchesBuilder;
+        return matchesBuilder.setAceType(aceIpBuilder.build());
     }
 
-    public ActionsBuilder createActions (ActionsBuilder actionsBuilder, Boolean permit) {
-        PermitBuilder permitBuilder = new PermitBuilder();
-        permitBuilder.setPermit(Boolean.TRUE);
-        actionsBuilder.setPacketHandling(permitBuilder.build());
-
-        return actionsBuilder;
+    public ActionsBuilder actionsBuilder(ActionsBuilder actionsBuilder, Boolean permit) {
+        return actionsBuilder.setPacketHandling(new PermitBuilder().setPermit(permit).build());
     }
 
-    public AceBuilder createAccessListEntryBuilder(AceBuilder accessListEntryBuilder,
-                                                   String ruleName,
-                                                   MatchesBuilder matchesBuilder,
-                                                   ActionsBuilder actionsBuilder) {
-        accessListEntryBuilder.setRuleName(ruleName);
-        accessListEntryBuilder.setMatches(matchesBuilder.build());
-        accessListEntryBuilder.setActions(actionsBuilder.build());
+    public ActionsBuilder actionsBuilder(ActionsBuilder actionsBuilder, String sfcName) {
+        RedirectToSfcBuilder redirectToSfcBuilder = new RedirectToSfcBuilder().setSfcName(sfcName);
 
-        return accessListEntryBuilder;
+        return actionsBuilder.addAugmentation(RedirectToSfc.class, redirectToSfcBuilder.build());
     }
 
-    public AccessListEntriesBuilder createAccessListEntries(AccessListEntriesBuilder accessListEntriesBuilder,
-                                                            AceBuilder accessListEntryBuilder) {
-        List<Ace> accessListEntriesList = new ArrayList<>();
-        accessListEntriesList.add(accessListEntryBuilder.build());
-
-        return accessListEntriesBuilder;
+    public AceBuilder aceBuilder(AceBuilder accessListEntryBuilder,
+                                 String ruleName,
+                                 MatchesBuilder matchesBuilder,
+                                 ActionsBuilder actionsBuilder) {
+        return accessListEntryBuilder
+                .setRuleName(ruleName)
+                .setMatches(matchesBuilder.build())
+                .setActions(actionsBuilder.build());
     }
 
-    public AclBuilder createAccessList(AclBuilder accessListBuilder,
-                                       String aclName,
-                                       AccessListEntriesBuilder accessListEntriesBuilder) {
-        accessListBuilder.setAclName(aclName);
-        accessListBuilder.setAccessListEntries(accessListEntriesBuilder.build());
+    public AccessListEntriesBuilder accessListEntriesBuidler(AccessListEntriesBuilder accessListEntriesBuilder,
+                                                             AceBuilder aceBuilder) {
+        List<Ace> aceList = new ArrayList<>();
+        aceList.add(aceBuilder.build());
+
+        return accessListEntriesBuilder.setAce(aceList);
+    }
 
-        return accessListBuilder;
+    public AclBuilder aclBuilder(AclBuilder aclBuilder,
+                                 String aclName,
+                                 AccessListEntriesBuilder accessListEntriesBuilder) {
+        return aclBuilder
+                .setAclName(aclName)
+                .setAccessListEntries(accessListEntriesBuilder.build());
     }
 
-    public AccessListsBuilder createAccessLists(AccessListsBuilder accessListsBuilder,
-                                                AclBuilder accessListBuilder) {
-        List<Acl> accessListList = new ArrayList<>();
-        accessListList.add(accessListBuilder.build());
-        accessListsBuilder.setAcl(accessListList);
+    public AccessListsBuilder accesslistsbuilder(AccessListsBuilder accessListsBuilder,
+                                                 AclBuilder aclBuilder) {
+        List<Acl> aclList = new ArrayList<>();
+        aclList.add(aclBuilder.build());
 
-        return accessListsBuilder;
+        return accessListsBuilder.setAcl(aclList);
     }
 }
index f99ca664cf46acb49839cdd7a84bdf8360c17349..54d31dbab720b96ac853517e539cead1c817bed1 100644 (file)
@@ -17,14 +17,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.SffBuilder;
 
-public class ClassifierUtils {
-    public SffBuilder createSff(SffBuilder sffBuilder, String sffName) {
-        sffBuilder.setName(sffName);
-
-        return sffBuilder;
+public class ClassifierUtils extends AbstractUtils {
+    public SffBuilder sffBuilder(SffBuilder sffBuilder, String sffName) {
+        return sffBuilder.setName(sffName);
     }
 
-    public SffsBuilder createSffs(SffsBuilder sffsBuilder, SffBuilder sffBuilder) {
+    public SffsBuilder sffsBuilder(SffsBuilder sffsBuilder, SffBuilder sffBuilder) {
         List<Sff> sffList = new ArrayList<>();
         sffList.add(sffBuilder.build());
         sffsBuilder.setSff(sffList);
@@ -32,17 +30,16 @@ public class ClassifierUtils {
         return sffsBuilder;
     }
 
-    public ClassifierBuilder createClassifier(ClassifierBuilder classifierBuilder,
-                                       String classifierName, String aclName,
-                                       SffsBuilder sffsBuilder) {
-        classifierBuilder.setName(classifierName);
-        classifierBuilder.setAcl(aclName);
-
-        return classifierBuilder;
+    public ClassifierBuilder classifierBuilder(ClassifierBuilder classifierBuilder,
+                                               String classifierName, String aclName,
+                                               SffsBuilder sffsBuilder) {
+        return classifierBuilder
+                .setName(classifierName)
+                .setAcl(aclName);
     }
 
-    public ClassifiersBuilder createClassifiers(ClassifiersBuilder classifiersBuilder,
-                                                ClassifierBuilder classifierBuilder) {
+    public ClassifiersBuilder ClassifiersBuilder(ClassifiersBuilder classifiersBuilder,
+                                                 ClassifierBuilder classifierBuilder) {
         List<Classifier> classifierList = new ArrayList<>();
         classifierList.add(classifierBuilder.build());
         classifiersBuilder.setClassifier(classifierList);
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionChainUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionChainUtils.java
new file mode 100644 (file)
index 0000000..3ad69c4
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright Â© 2015 Red Hat, 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.openstack.netvirt.sfc.utils;
+
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName;
+
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.ServiceFunctionChainsBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChainBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunction;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunctionBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sft.rev140701.ServiceFunctionTypeIdentity;
+
+public class ServiceFunctionChainUtils extends AbstractUtils {
+    public SfcServiceFunctionBuilder sfcServiceFunctionBuilder(SfcServiceFunctionBuilder sfcServiceFunctionBuilder,
+                                                               String name,
+                                                               Class<? extends ServiceFunctionTypeIdentity> type) {
+        return sfcServiceFunctionBuilder
+                .setName(name)
+                .setType(type);
+    }
+
+    public ServiceFunctionChainBuilder serviceFunctionChainBuilder(
+            ServiceFunctionChainBuilder serviceFunctionChainBuilder, String name, Boolean symmetric,
+            List<SfcServiceFunction> sfcServiceFunctionList) {
+
+        return serviceFunctionChainBuilder
+                .setName(SfcName.getDefaultInstance(name))
+                .setSymmetric(symmetric)
+                .setSfcServiceFunction(sfcServiceFunctionList);
+    }
+
+    public ServiceFunctionChainsBuilder serviceFunctionChainsBuilder(
+            ServiceFunctionChainsBuilder serviceFunctionChainsBuilder,
+            List<ServiceFunctionChain> serviceFunctionChainBuilderList) {
+
+        return serviceFunctionChainsBuilder.setServiceFunctionChain(serviceFunctionChainBuilderList);
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionForwarderUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionForwarderUtils.java
new file mode 100644 (file)
index 0000000..79f3a69
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright Â© 2015 Red Hat, 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.openstack.netvirt.sfc.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffDataPlaneLocatorName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SnName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsBridgeAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsLocatorOptionsAugmentation;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsLocatorOptionsAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.bridge.OvsBridgeBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.options.OvsOptionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwardersBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.ServiceFunctionDictionary;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.ServiceFunctionDictionaryBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.SffDataPlaneLocator;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.SffDataPlaneLocatorBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.service.function.dictionary.SffSfDataPlaneLocatorBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.sff.data.plane.locator.DataPlaneLocatorBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sft.rev140701.ServiceFunctionTypeIdentity;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeName;
+
+public class ServiceFunctionForwarderUtils extends AbstractUtils {
+    public OvsOptionsBuilder ovsOptionsBuilder(OvsOptionsBuilder ovsOptionsBuilder, int port) {
+        String flow = "flow";
+        return ovsOptionsBuilder
+                .setDstPort(String.valueOf(port))
+                .setRemoteIp(flow)
+                .setKey(flow)
+                .setNsi(flow)
+                .setNsp(flow)
+                .setNshc1(flow)
+                .setNshc2(flow)
+                .setNshc3(flow)
+                .setNshc4(flow);
+    }
+
+    public SffDataPlaneLocatorBuilder sffDataPlaneLocatorBuilder(SffDataPlaneLocatorBuilder sffDataPlaneLocatorBuilder,
+                                                                 DataPlaneLocatorBuilder dataPlaneLocatorBuilder,
+                                                                 String dplName) {
+        SffOvsLocatorOptionsAugmentationBuilder sffOvsLocatorOptionsAugmentationBuilder =
+                new SffOvsLocatorOptionsAugmentationBuilder();
+        sffOvsLocatorOptionsAugmentationBuilder.setOvsOptions(
+                ovsOptionsBuilder(new OvsOptionsBuilder(), 6633).build());
+
+        return sffDataPlaneLocatorBuilder
+                .setName(new SffDataPlaneLocatorName(dplName))
+                .setDataPlaneLocator(dataPlaneLocatorBuilder.build())
+                .addAugmentation(SffOvsLocatorOptionsAugmentation.class,
+                        sffOvsLocatorOptionsAugmentationBuilder.build());
+    }
+
+    public SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder(
+            SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder, String ip, int port) {
+        return sffSfDataPlaneLocatorBuilder
+                .setLocatorType(ipBuilder(ip, port).build())
+                .setTransport(VxlanGpe.class);
+    }
+
+    public ServiceFunctionDictionaryBuilder serviceFunctionDictionaryBuilder(
+            ServiceFunctionDictionaryBuilder serviceFunctionDictionaryBuilder,
+            String sfName, Class<? extends ServiceFunctionTypeIdentity> type,
+            SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder) {
+
+        return serviceFunctionDictionaryBuilder
+                .setName(new SfName(sfName))
+                .setType(type)
+                .setSffSfDataPlaneLocator(sffSfDataPlaneLocatorBuilder.build());
+    }
+
+    public OvsBridgeBuilder ovsBridgeBuilder(OvsBridgeBuilder ovsBridgeBuilder, String bridgeNme) {
+        return ovsBridgeBuilder.setBridgeName(bridgeNme);
+    }
+
+    public ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder(
+            ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder,
+            String sffName, String serviceNodeName, String bridgeName,
+            List<SffDataPlaneLocator> sffDataPlaneLocatorList,
+            List<ServiceFunctionDictionary> serviceFunctionDictionaryList) {
+
+        SffOvsBridgeAugmentationBuilder sffOvsBridgeAugmentationBuilder = new SffOvsBridgeAugmentationBuilder();
+        sffOvsBridgeAugmentationBuilder.setOvsBridge(ovsBridgeBuilder(new OvsBridgeBuilder(), bridgeName).build());
+
+        return serviceFunctionForwarderBuilder
+                .setName(new SffName(sffName))
+                .setServiceNode(new SnName(serviceNodeName))
+                .setServiceFunctionDictionary(serviceFunctionDictionaryList)
+                .setSffDataPlaneLocator(sffDataPlaneLocatorList)
+                .addAugmentation(SffOvsBridgeAugmentation.class, sffOvsBridgeAugmentationBuilder.build());
+    }
+
+    public ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder(
+            ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder,
+            List<ServiceFunctionForwarder> serviceFunctionForwarderList) {
+        return serviceFunctionForwardersBuilder.setServiceFunctionForwarder(serviceFunctionForwarderList);
+    }
+
+    public ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder(
+            String sffName, String sffIp, int port, String sffDplName,
+            String sfName, String sfIp, String snName, String bridgeName,
+            Class<? extends ServiceFunctionTypeIdentity> type) {
+
+        DataPlaneLocatorBuilder dataPlaneLocatorBuilder =
+                dataPlaneLocatorBuilder(new DataPlaneLocatorBuilder(), sffIp, port);
+        SffDataPlaneLocatorBuilder sffDataPlaneLocatorBuilder =
+                sffDataPlaneLocatorBuilder( new SffDataPlaneLocatorBuilder(), dataPlaneLocatorBuilder, sffDplName);
+        List<SffDataPlaneLocator> sffDataPlaneLocatorList =
+                list(new ArrayList<SffDataPlaneLocator>(), sffDataPlaneLocatorBuilder);
+
+        SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder =
+                sffSfDataPlaneLocatorBuilder(new SffSfDataPlaneLocatorBuilder(), sffIp, port);
+        ServiceFunctionDictionaryBuilder serviceFunctionDictionaryBuilder =
+                serviceFunctionDictionaryBuilder(new ServiceFunctionDictionaryBuilder(), sfName, type,
+                        sffSfDataPlaneLocatorBuilder);
+        List<ServiceFunctionDictionary> serviceFunctionDictionaryList =
+                list(new ArrayList<ServiceFunctionDictionary>(), serviceFunctionDictionaryBuilder);
+
+        ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder =
+                serviceFunctionForwarderBuilder(
+                        new ServiceFunctionForwarderBuilder(), sffName, snName, bridgeName,
+                        sffDataPlaneLocatorList, serviceFunctionDictionaryList);
+        return serviceFunctionForwarderBuilder;
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionPathUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionPathUtils.java
new file mode 100644 (file)
index 0000000..4f9dfd9
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright Â© 2015 Red Hat, 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.openstack.netvirt.sfc.utils;
+
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfpName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPathsBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathBuilder;
+
+public class ServiceFunctionPathUtils extends AbstractUtils {
+    public ServiceFunctionPathBuilder serviceFunctionPathBuilder(
+            ServiceFunctionPathBuilder serviceFunctionPathBuilder,
+            String sfpName, String sfcName, short startingIndex, Boolean symmetric) {
+
+        return serviceFunctionPathBuilder
+                .setSymmetric(symmetric)
+                .setName(SfpName.getDefaultInstance(sfpName))
+                .setServiceChainName(SfcName.getDefaultInstance(sfcName))
+                .setStartingIndex(startingIndex);
+    }
+
+    public ServiceFunctionPathsBuilder serviceFunctionPathsBuilder(
+            List<ServiceFunctionPath> serviceFunctionPathList) {
+
+        return new ServiceFunctionPathsBuilder().setServiceFunctionPath(serviceFunctionPathList);
+    }
+}
diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionUtils.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/ServiceFunctionUtils.java
new file mode 100644 (file)
index 0000000..39f3838
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright Â© 2015 Red Hat, 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.openstack.netvirt.sfc.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfDataPlaneLocatorName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.entry.SfDataPlaneLocator;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.entry.SfDataPlaneLocatorBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sft.rev140701.Firewall;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sft.rev140701.ServiceFunctionTypeIdentity;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+
+public class ServiceFunctionUtils extends AbstractUtils {
+    public SfDataPlaneLocatorBuilder sfDataPlaneLocatorBuilder(SfDataPlaneLocatorBuilder sfDataPlaneLocatorBuilder,
+                                                               String ip, int port, String dplName, String sffName) {
+        return sfDataPlaneLocatorBuilder
+                .setLocatorType(ipBuilder(ip, port).build())
+                .setName(new SfDataPlaneLocatorName(dplName))
+                .setTransport(VxlanGpe.class)
+                .setServiceFunctionForwarder(new SffName(sffName));
+    }
+
+    public ServiceFunctionBuilder serviceFunctionBuilder(ServiceFunctionBuilder serviceFunctionBuilder,
+                                                         String ip, String sfName,
+                                                         List<SfDataPlaneLocator> sfDataPlaneLocatorList,
+                                                         Class<? extends ServiceFunctionTypeIdentity> type) {
+        return serviceFunctionBuilder
+                .setSfDataPlaneLocator(sfDataPlaneLocatorList)
+                .setName(new SfName(sfName))
+                .setIpMgmtAddress(new IpAddress(ip.toCharArray()))
+                .setType(type)
+                .setNshAware(true);
+    }
+
+    public ServiceFunctionsBuilder serviceFunctionsBuilder(ServiceFunctionsBuilder serviceFunctionsBuilder,
+                                                           List<ServiceFunction> serviceFunctionList) {
+        return serviceFunctionsBuilder.setServiceFunction(serviceFunctionList);
+    }
+
+    public ServiceFunctionBuilder serviceFunctionBuilder(String sfIp, int port, String sf1DplName,
+                                                         String sffname, String sfName) {
+        SfDataPlaneLocatorBuilder sfDataPlaneLocator =
+                sfDataPlaneLocatorBuilder(new SfDataPlaneLocatorBuilder(), sfIp, port, sf1DplName, sffname);
+        List<SfDataPlaneLocator> sfDataPlaneLocatorList =
+                list(new ArrayList<SfDataPlaneLocator>(), sfDataPlaneLocator);
+        return serviceFunctionBuilder(
+                new ServiceFunctionBuilder(), sfIp, sfName, sfDataPlaneLocatorList, Firewall.class);
+    }
+
+
+}
index 99fd35e1ce250723968dfa3e3776c48ebf24f4da..5b24ef437a6e73ed5bf2c4ae513e688d99fefba0 100644 (file)
@@ -11,9 +11,7 @@ package org.opendaylight.ovsdb.openstack.netvirt.sfc.utils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.SfcBuilder;
 
 public class SfcUtils {
-    public SfcBuilder createSfc(SfcBuilder sfcBuilder, String sfcName) {
-        sfcBuilder.setName(sfcName);
-
-        return sfcBuilder;
+    public SfcBuilder sfcBuilder(SfcBuilder sfcBuilder, String sfcName) {
+        return sfcBuilder.setName(sfcName);
     }
 }
index 3b5584c3e3002a12c2ac69dcedb248d3b60636c4..fdc004d35affc3a121e9e4560908bf64394394bd 100644 (file)
@@ -120,6 +120,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>utils.servicehelper</artifactId>
       <version>${ovsdb.utils.servicehelper.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yang-common</artifactId>
index 3097b0379463ee107d08b41a9b473a7a2e637821..ee392fbea3950f98c0092b6ea785c5efd98890dd 100644 (file)
@@ -16,6 +16,44 @@ import java.util.List;
 import org.apache.commons.lang3.tuple.Pair;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.api.ArpProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolver;
+import org.opendaylight.ovsdb.openstack.netvirt.api.InboundNatProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.L3ForwardingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.MultiTenantAwareRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheListener;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.OutboundNatProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbInventoryListener;
+import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbInventoryService;
+import org.opendaylight.ovsdb.openstack.netvirt.api.RoutingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityGroupCacheManger;
+import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.VlanConfigurationCache;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.BridgeConfigurationManagerImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.ConfigurationServiceImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.EventDispatcherImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.NodeCacheManagerImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.OpenstackRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.OvsdbInventoryServiceImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.ProviderNetworkManagerImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.SecurityGroupCacheManagerImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.SecurityServicesImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.SouthboundImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.TenantNetworkManagerImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.VlanConfigurationCacheImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFloatingIPCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
@@ -49,8 +87,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronRouter
 import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityGroupAware;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityRuleAware;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSubnetAware;
-import org.opendaylight.ovsdb.openstack.netvirt.api.*;
-import org.opendaylight.ovsdb.openstack.netvirt.impl.*;
+import org.opendaylight.ovsdb.utils.mdsal.utils.NeutronModelsDataStoreHelper;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -155,7 +192,8 @@ public class ConfigActivator implements BundleActivator {
         registerService(context,
                 new String[]{EventDispatcher.class.getName()}, null, eventDispatcher);
 
-        final NeutronL3Adapter neutronL3Adapter = new NeutronL3Adapter();
+        final NeutronL3Adapter neutronL3Adapter = new NeutronL3Adapter(
+                new NeutronModelsDataStoreHelper(this.providerContext.getSALService(DataBroker.class)));
         registerService(context,
                 new String[]{NeutronL3Adapter.class.getName()}, null, neutronL3Adapter);
 
@@ -200,6 +238,7 @@ public class ConfigActivator implements BundleActivator {
                 securityServices, neutronL3Adapter);
         trackService(context, INeutronPortCRUD.class, tenantNetworkManager, lBaaSHandler, lBaaSPoolHandler,
                 lBaaSPoolMemberHandler, securityServices, neutronL3Adapter);
+        trackService(context, INeutronFloatingIPCRUD.class, neutronL3Adapter);
         trackService(context, INeutronLoadBalancerCRUD.class, lBaaSHandler, lBaaSPoolHandler, lBaaSPoolMemberHandler);
         trackService(context, INeutronLoadBalancerPoolCRUD.class, lBaaSHandler, lBaaSPoolMemberHandler);
         trackService(context, LoadBalancerProvider.class, lBaaSHandler, lBaaSPoolHandler, lBaaSPoolMemberHandler);
index 87fc3e0c2f47f2caa8745fd9a49ef7e7c72d6410..28cc30f9b02d50a094a03508c8a0e087e0db6dd6 100644 (file)
@@ -58,6 +58,7 @@ public class MdsalHelper {
     public static final String OVSDB_URI_PREFIX = "ovsdb";
     public static final String BRIDGE_URI_PREFIX = "bridge";
     public static final String TP_URI_PREFIX = "termination-point";
+    public static final String DISABLE_IN_BAND = "disable-in-band";
 
     public static final ImmutableBiMap<Class<? extends OvsdbBridgeProtocolBase>,String> OVSDB_PROTOCOL_MAP
             = new ImmutableBiMap.Builder<Class<? extends OvsdbBridgeProtocolBase>,String>()
index 5289742d8c250dd50237520703dc4a6058be665b..f0baac9d1cb7672db24c918fc968be4b4b9077a3 100644 (file)
@@ -31,6 +31,7 @@ public interface Southbound {
     OvsdbNodeAugmentation extractOvsdbNode(Node node);
     NodeId extractBridgeOvsdbNodeId(Node bridgeNode);
     List<Node> readOvsdbTopologyNodes();
+    List<Node> readOvsdbTopologyBridgeNodes();
     Node readOvsdbNode(Node bridgeNode);
     boolean isBridgeOnOvsdbNode(Node node, String bridgeName);
     String getOvsdbNodeUUID(Node node);
index b01dc1fc518076a0431e4255aaf2841266f96308..5fb2e967500c8768470e7b6e6e274612c4f163a1 100644 (file)
@@ -44,14 +44,18 @@ public class MdsalUtils {
     public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean delete(
             final LogicalDatastoreType store, final InstanceIdentifier<D> path)  {
         boolean result = false;
-        final WriteTransaction transaction = databroker.newWriteOnlyTransaction();
-        transaction.delete(store, path);
-        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
-        try {
-            future.checkedGet();
+        if(this.read(store,path) != null) {
+            final WriteTransaction transaction = databroker.newWriteOnlyTransaction();
+            transaction.delete(store, path);
+            CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+            try {
+                future.checkedGet();
+                result = true;
+            } catch (TransactionCommitFailedException e) {
+                LOG.warn("Failed to delete {} ", path, e);
+            }
+        } else {
             result = true;
-        } catch (TransactionCommitFailedException e) {
-            LOG.warn("Failed to delete {} ", path, e);
         }
         return result;
     }
index ce4954ee4356f650bf2ac85b502be4f4aae5b208..8d379f416fb06258daccb1525b36d667ceffc011 100644 (file)
@@ -8,8 +8,35 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.impl;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
+import org.opendaylight.ovsdb.openstack.netvirt.api.ArpProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolver;
+import org.opendaylight.ovsdb.openstack.netvirt.api.InboundNatProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.L3ForwardingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.OutboundNatProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.RoutingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Status;
+import org.opendaylight.ovsdb.openstack.netvirt.api.StatusCode;
+import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
@@ -18,39 +45,31 @@ import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interfa
 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFloatingIPCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
-import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
-import org.opendaylight.ovsdb.openstack.netvirt.api.*;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronIAwareUtil;
+import org.opendaylight.ovsdb.utils.mdsal.utils.NeutronModelsDataStoreHelper;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 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.yang.types.rev100924.MacAddress;
 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.neutron.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
-import org.osgi.framework.ServiceReference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
 /**
  * Neutron L3 Adapter implements a hub-like adapter for the various Neutron events. Based on
  * these events, the abstract router callbacks can be generated to the multi-tenant aware router,
@@ -66,6 +85,7 @@ public class NeutronL3Adapter implements ConfigInterface {
     private volatile INeutronNetworkCRUD neutronNetworkCache;
     private volatile INeutronSubnetCRUD neutronSubnetCache;
     private volatile INeutronPortCRUD neutronPortCache;
+    private volatile INeutronFloatingIPCRUD neutronFloatingIpCache;
     private volatile L3ForwardingProvider l3ForwardingProvider;
     private volatile InboundNatProvider inboundNatProvider;
     private volatile OutboundNatProvider outboundNatProvider;
@@ -100,43 +120,37 @@ public class NeutronL3Adapter implements ConfigInterface {
         }
     }
 
-    private Set<String> inboundIpRewriteCache;
-    private Set<String> outboundIpRewriteCache;
-    private Set<String> outboundIpRewriteExclusionCache;
-    private Set<String> routerInterfacesCache;
-    private Set<String> staticArpEntryCache;
-    private Set<String> l3ForwardingCache;
     private Map<String, String> networkIdToRouterMacCache;
     private Map<String, List<Neutron_IPs>> networkIdToRouterIpListCache;
     private Map<String, NeutronRouter_Interface> subnetIdToRouterInterfaceCache;
+
     private Map<String, Pair<Long, Uuid>> neutronPortToDpIdCache;
     private Map<String, FloatIpData> floatIpDataMapCache;
+
     private String externalRouterMac;
     private Boolean enabled = false;
     private Boolean flgDistributedARPEnabled = true;
-    private Southbound southbound;
+    private Boolean isCachePopulationDone = false;
     private final ExecutorService gatewayMacResolverPool = Executors.newFixedThreadPool(5);
 
+    private Southbound southbound;
+    private NeutronModelsDataStoreHelper neutronModelsDataStoreHelper;
+
     private static final String OWNER_ROUTER_INTERFACE = "network:router_interface";
     private static final String OWNER_ROUTER_INTERFACE_DISTRIBUTED = "network:router_interface_distributed";
     private static final String OWNER_ROUTER_GATEWAY = "network:router_gateway";
     private static final String OWNER_FLOATING_IP = "network:floatingip";
     private static final String DEFAULT_EXT_RTR_MAC = "00:00:5E:00:01:01";
 
-    public NeutronL3Adapter() {
+    public NeutronL3Adapter(NeutronModelsDataStoreHelper neutronHelper) {
         LOG.info(">>>>>> NeutronL3Adapter constructor {}", this.getClass());
+        this.neutronModelsDataStoreHelper = neutronHelper;
     }
 
     private void initL3AdapterMembers() {
         Preconditions.checkNotNull(configurationService);
 
         if (configurationService.isL3ForwardingEnabled()) {
-            this.inboundIpRewriteCache = new HashSet<>();
-            this.outboundIpRewriteCache = new HashSet<>();
-            this.outboundIpRewriteExclusionCache = new HashSet<>();
-            this.routerInterfacesCache = new HashSet<>();
-            this.staticArpEntryCache = new HashSet<>();
-            this.l3ForwardingCache = new HashSet<>();
             this.networkIdToRouterMacCache = new HashMap<>();
             this.networkIdToRouterIpListCache = new HashMap<>();
             this.subnetIdToRouterInterfaceCache = new HashMap<>();
@@ -161,10 +175,158 @@ public class NeutronL3Adapter implements ConfigInterface {
         }
     }
 
-    //
-    // Callbacks from OVSDB's northbound handlers
-    //
 
+    private void populateL3ForwardingCaches() {
+        if (!this.enabled) {
+            return;
+        }
+        if(this.isCachePopulationDone || this.neutronFloatingIpCache == null
+                || this.neutronPortCache == null ||this.neutronNetworkCache == null) {
+            return;
+        }
+        this.isCachePopulationDone = true;
+        LOG.debug("Populating NetVirt L3 caches from data store configuration");
+        Routers routers = this.neutronModelsDataStoreHelper.readAllNeutronRouters();
+        Ports ports = this.neutronModelsDataStoreHelper.readAllNeutronPorts();
+        if(routers != null && routers.getRouter() != null && ports != null) {
+            LOG.debug("L3 Cache Population : {} Neutron router present in data store",routers.getRouter().size());
+            for( Router router : routers.getRouter()) {
+                LOG.debug("L3 Cache Population : Populate caches for router {}",router);
+                if(!ports.getPort().isEmpty()) {
+                    for( Port port : ports.getPort()) {
+                        if (port.getDeviceId().equals(router.getUuid().getValue()) &&
+                                port.getDeviceOwner().equals(OWNER_ROUTER_INTERFACE)) {
+                            LOG.debug("L3 Cache Population : Router interface {} found.",port);
+                            networkIdToRouterMacCache.put(port.getNetworkId().getValue()
+                                    , port.getMacAddress());
+
+                            networkIdToRouterIpListCache.put(port.getNetworkId().getValue(),
+                                    NeutronIAwareUtil.convertMDSalIpToNeutronIp(port.getFixedIps()));
+                            subnetIdToRouterInterfaceCache.put(port.getFixedIps().get(0).getSubnetId().getValue(),
+                                    NeutronIAwareUtil.convertMDSalInterfaceToNeutronRouterInterface(port));
+                        }
+                    }
+                }else {
+                    LOG.warn("L3 Cache Population :Did not find any port information " +
+                            "in config Data Store for router {}",router);
+                }
+            }
+        }
+        LOG.debug("NetVirt L3 caches population is done");
+    }
+
+    private Pair<Long, Uuid> getDpIdOfNeutronPort(String neutronTenantPortUuid) {
+        if(neutronPortToDpIdCache.get(neutronTenantPortUuid) == null) {
+            List<Node> bridges = this.southbound.readOvsdbTopologyBridgeNodes();
+            LOG.debug("getDpIdOfNeutronPort : {} bridges present in ovsdb topology",bridges.size());
+            for(Node bridge : bridges) {
+                List<OvsdbTerminationPointAugmentation> interfaces
+                        = southbound.extractTerminationPointAugmentations(bridge);
+                if(interfaces != null && !interfaces.isEmpty()) {
+                    LOG.debug("getDpIdOfNeutronPort : {} termination point present on bridge {}",
+                            interfaces.size(), bridge.getNodeId());
+                    for (OvsdbTerminationPointAugmentation intf : interfaces) {
+                        NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
+                        if(neutronPort != null && neutronPort.getID().equals(neutronTenantPortUuid)) {
+                            Long dpId = getDpidForIntegrationBridge(bridge);
+                            Uuid interfaceUuid = intf.getInterfaceUuid();
+                            LOG.debug("getDpIdOfNeutronPort : Found bridge {} and interface {} for the tenant neutron" +
+                                    " port {}",dpId,interfaceUuid,neutronTenantPortUuid);
+                            handleInterfaceEventAdd(neutronPort.getPortUUID(), dpId, interfaceUuid);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return neutronPortToDpIdCache.get(neutronTenantPortUuid);
+    }
+
+    private Collection<FloatIpData> getAllFloatingIPsWithMetadata() {
+        LOG.debug("getAllFloatingIPsWithMetadata : Fechting all floating Ips and it's metadata");
+        List<NeutronFloatingIP> neutronFloatingIps = neutronFloatingIpCache.getAllFloatingIPs();
+        if(neutronFloatingIps != null && !neutronFloatingIps.isEmpty()) {
+            for (NeutronFloatingIP neutronFloatingIP : neutronFloatingIps) {
+                if(!floatIpDataMapCache.containsKey(neutronFloatingIP.getID())){
+                    LOG.debug("Metadata for floating ip {} is not present in the cache. " +
+                            "Fetching from data store.",neutronFloatingIP.getID());
+                    this.getFloatingIPWithMetadata(neutronFloatingIP.getID());
+                }
+            }
+        }
+        LOG.debug("getAllFloatingIPsWithMetadata : {} floating points found in data store",floatIpDataMapCache.size());
+        return floatIpDataMapCache.values();
+    }
+    private FloatIpData getFloatingIPWithMetadata(String neutronFloatingId) {
+        LOG.debug("getFloatingIPWithMetadata : Get Floating ip and it's meta data for neutron " +
+                "floating id {} ",neutronFloatingId);
+        if(floatIpDataMapCache.get(neutronFloatingId) == null) {
+            NeutronFloatingIP neutronFloatingIP = neutronFloatingIpCache.getFloatingIP(neutronFloatingId);
+            if (neutronFloatingIP == null) {
+                LOG.error("getFloatingIPWithMetadata : Floating ip {} is missing from data store, that should not happen",neutronFloatingId);
+                return null;
+            }
+            List<NeutronPort> neutronPorts = neutronPortCache.getAllPorts();
+            NeutronPort neutronPortForFloatIp = null;
+            for (NeutronPort neutronPort : neutronPorts) {
+                if (neutronPort.getDeviceOwner().equals(OWNER_FLOATING_IP) &&
+                        neutronPort.getDeviceID().equals(neutronFloatingIP.getID())) {
+                    neutronPortForFloatIp = neutronPort;
+                    break;
+                }
+            }
+
+            String neutronTenantPortUuid = neutronFloatingIP.getPortUUID();
+            if(neutronTenantPortUuid == null) {
+                return null;
+            }
+            Pair<Long, Uuid> nodeIfPair = this.getDpIdOfNeutronPort(neutronTenantPortUuid);
+            String floatingIpMac = neutronPortForFloatIp == null ? null : neutronPortForFloatIp.getMacAddress();
+            String fixedIpAddress = neutronFloatingIP.getFixedIPAddress();
+            String floatingIpAddress = neutronFloatingIP.getFloatingIPAddress();
+
+            NeutronPort tenantNeutronPort = neutronPortCache.getPort(neutronTenantPortUuid);
+            NeutronNetwork tenantNeutronNetwork = tenantNeutronPort != null ?
+                    neutronNetworkCache.getNetwork(tenantNeutronPort.getNetworkUUID()) : null;
+            String providerSegmentationId = tenantNeutronNetwork != null ?
+                    tenantNeutronNetwork.getProviderSegmentationID() : null;
+            String neutronRouterMac = tenantNeutronNetwork != null ?
+                    networkIdToRouterMacCache.get(tenantNeutronNetwork.getID()) : null;
+
+            if (nodeIfPair == null || neutronTenantPortUuid == null ||
+                    providerSegmentationId == null || providerSegmentationId.isEmpty() ||
+                    floatingIpMac == null || floatingIpMac.isEmpty() ||
+                    neutronRouterMac == null || neutronRouterMac.isEmpty()) {
+                LOG.debug("getFloatingIPWithMetadata :Floating IP {}<->{}, incomplete floatPort {} tenantPortUuid {} " +
+                                "seg {} mac {} rtrMac {}",
+                        fixedIpAddress,
+                        floatingIpAddress,
+                        neutronPortForFloatIp,
+                        neutronTenantPortUuid,
+                        providerSegmentationId,
+                        floatingIpMac,
+                        neutronRouterMac);
+
+                return null;
+            }
+
+            // get ofport for patch port in br-int
+            final Long dpId = nodeIfPair.getLeft();
+            final Long ofPort = findOFPortForExtPatch(dpId);
+            if (ofPort == null) {
+                LOG.warn("getFloatingIPWithMetadata : Unable to locate OF port of patch port " +
+                                "to connect floating ip to external bridge. dpid {}",
+                        dpId);
+                return null;
+            }
+
+            final FloatIpData floatIpData = new FloatIpData(dpId, ofPort, providerSegmentationId, floatingIpMac,
+                    floatingIpAddress, fixedIpAddress, neutronRouterMac);
+            floatIpDataMapCache.put(neutronFloatingIP.getID(), floatIpData);
+
+        }
+        return floatIpDataMapCache.get(neutronFloatingId);
+    }
     /**
      * Invoked to configure the mac address for the external gateway in br-ex. ovsdb netvirt needs help in getting
      * mac for given ip in br-ex (bug 3378). For example, since ovsdb has no real arp, it needs a service in can
@@ -379,7 +541,7 @@ public class NeutronL3Adapter implements ConfigInterface {
     private void programFlowsForFloatingIPInbound(final NeutronFloatingIP neutronFloatingIP, final Action action) {
         Preconditions.checkNotNull(neutronFloatingIP);
 
-        final FloatIpData fid = floatIpDataMapCache.get(neutronFloatingIP.getID());
+        final FloatIpData fid = getFloatingIPWithMetadata(neutronFloatingIP.getID());
         if (fid == null) {
             LOG.trace("programFlowsForFloatingIPInboundAdd {} for {} uuid {} not in local cache",
                     action, neutronFloatingIP.getFloatingIPAddress(), neutronFloatingIP.getID());
@@ -396,7 +558,7 @@ public class NeutronL3Adapter implements ConfigInterface {
     private void programFlowsForFloatingIPOutbound(final NeutronFloatingIP neutronFloatingIP, final Action action) {
         Preconditions.checkNotNull(neutronFloatingIP);
 
-        final FloatIpData fid = floatIpDataMapCache.get(neutronFloatingIP.getID());
+        final FloatIpData fid = getFloatingIPWithMetadata(neutronFloatingIP.getID());
         if (fid == null) {
             LOG.trace("programFlowsForFloatingIPOutbound {} for {} uuid {} not in local cache",
                     action, neutronFloatingIP.getFloatingIPAddress(), neutronFloatingIP.getID());
@@ -406,13 +568,13 @@ public class NeutronL3Adapter implements ConfigInterface {
     }
 
     private void flushExistingIpRewrite() {
-        for (FloatIpData fid : floatIpDataMapCache.values()) {
+        for (FloatIpData fid : getAllFloatingIPsWithMetadata()) {
             programOutboundIpRewriteStage1(fid, Action.DELETE);
         }
     }
 
     private void rebuildExistingIpRewrite() {
-        for (FloatIpData fid : floatIpDataMapCache.values()) {
+        for (FloatIpData fid : getAllFloatingIPsWithMetadata()) {
             programOutboundIpRewriteStage1(fid, Action.ADD);
         }
     }
@@ -427,16 +589,10 @@ public class NeutronL3Adapter implements ConfigInterface {
         Preconditions.checkNotNull(neutronFloatingIP.getFixedIPAddress());
         Preconditions.checkNotNull(neutronFloatingIP.getFloatingIPAddress());
 
-        if (floatIpDataMapCache.get(neutronFloatingIP.getID()) != null) {
-            LOG.trace("programFlowsForFloatingIPArpAdd for neutronFloatingIP {} uuid {} is already done",
-                    neutronFloatingIP.getFloatingIPAddress(), neutronFloatingIP.getID());
-            return;
-        }
-
         // find bridge Node where floating ip is configured by looking up cache for its port
         final NeutronPort neutronPortForFloatIp = findNeutronPortForFloatingIp(neutronFloatingIP.getID());
         final String neutronTenantPortUuid = neutronFloatingIP.getPortUUID();
-        final Pair<Long, Uuid> nodeIfPair = neutronPortToDpIdCache.get(neutronTenantPortUuid);
+        final Pair<Long, Uuid> nodeIfPair = this.getDpIdOfNeutronPort(neutronTenantPortUuid);
         final String floatingIpMac = neutronPortForFloatIp == null ? null : neutronPortForFloatIp.getMacAddress();
         final String fixedIpAddress = neutronFloatingIP.getFixedIPAddress();
         final String floatingIpAddress = neutronFloatingIP.getFloatingIPAddress();
@@ -487,7 +643,7 @@ public class NeutronL3Adapter implements ConfigInterface {
     }
 
     private void programFlowsForFloatingIPArpDelete(final String neutronFloatingIPUuid) {
-        final FloatIpData floatIpData = floatIpDataMapCache.get(neutronFloatingIPUuid);
+        final FloatIpData floatIpData = getFloatingIPWithMetadata(neutronFloatingIPUuid);
         if (floatIpData == null) {
             LOG.trace("programFlowsForFloatingIPArpDelete for uuid {} is not needed", neutronFloatingIPUuid);
             return;
@@ -571,8 +727,7 @@ public class NeutronL3Adapter implements ConfigInterface {
         if (neutronPort != null) {
             final String neutronPortUuid = neutronPort.getPortUUID();
 
-            if (action != Action.DELETE && neutronPortToDpIdCache.get(neutronPortUuid) == null &&
-                    dpId != null && interfaceUuid != null) {
+            if (action != Action.DELETE && dpId != null && interfaceUuid != null) {
                 handleInterfaceEventAdd(neutronPortUuid, dpId, interfaceUuid);
             }
 
@@ -709,33 +864,17 @@ public class NeutronL3Adapter implements ConfigInterface {
     private void programL3ForwardingStage1(Node node, Long dpid, String providerSegmentationId,
                                            String macAddress, String ipStr,
                                            Action actionForNode) {
-        // Based on the local cache, figure out whether programming needs to occur. To do this, we
-        // will look at desired action for node.
-
-        final String cacheKey = node.getNodeId().getValue() + ":" + providerSegmentationId + ":" + ipStr;
-        final boolean isProgrammed = l3ForwardingCache.contains(cacheKey);
-
-        if (actionForNode == Action.DELETE && !isProgrammed) {
-            LOG.trace("programL3ForwardingStage1 for node {} providerId {} mac {} ip {} action {} is already done",
+        if (actionForNode == Action.DELETE) {
+            LOG.trace("Deleting Flow : programL3ForwardingStage1 for node {} providerId {} mac {} ip {} action {}",
                          node.getNodeId().getValue(), providerSegmentationId, macAddress, ipStr, actionForNode);
-            return;
         }
-        if (actionForNode == Action.ADD && isProgrammed) {
-            LOG.trace("programL3ForwardingStage1 for node {} providerId {} mac {} ip {} action {} is already done",
+        if (actionForNode == Action.ADD) {
+            LOG.trace("Adding Flow : programL3ForwardingStage1 for node {} providerId {} mac {} ip {} action {}",
                     node.getNodeId().getValue(), providerSegmentationId, macAddress, ipStr, actionForNode);
-            return;
         }
 
-        Status status = this.programL3ForwardingStage2(node, dpid, providerSegmentationId,
+        this.programL3ForwardingStage2(node, dpid, providerSegmentationId,
                                                        macAddress, ipStr, actionForNode);
-        if (status.isSuccess()) {
-            // Update cache
-            if (actionForNode == Action.ADD) {
-                l3ForwardingCache.add(cacheKey);
-            } else {
-                l3ForwardingCache.remove(cacheKey);
-            }
-        }
     }
 
     private Status programL3ForwardingStage2(Node node, Long dpid, String providerSegmentationId,
@@ -961,41 +1100,22 @@ public class NeutronL3Adapter implements ConfigInterface {
                                               String destinationSegmentationId,
                                               String macAddress, String ipStr, int mask,
                                               Action actionForNode) {
-        // Based on the local cache, figure out whether programming needs to occur. To do this, we
-        // will look at desired action for node.
-        //
-        final String cacheKey = node.getNodeId().getValue() + ":" +
-                                sourceSegmentationId + ":" + destinationSegmentationId + ":" +
-                                ipStr + "/" + Integer.toString(mask);
-        final boolean isProgrammed = routerInterfacesCache.contains(cacheKey);
-
-        if (actionForNode == Action.DELETE && !isProgrammed) {
-            LOG.trace("programRouterInterfaceStage1 for node {} sourceSegId {} destSegId {} mac {} ip {} mask {}" +
-                         " action {} is already done",
+        if (actionForNode == Action.DELETE) {
+            LOG.trace("Deleting Flow : programRouterInterfaceStage1 for node {} sourceSegId {} destSegId {} mac {} ip {} mask {}" +
+                         " action {}",
                          node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
                          macAddress, ipStr, mask, actionForNode);
             return;
         }
-        if (actionForNode == Action.ADD && isProgrammed) {
-            LOG.trace("programRouterInterfaceStage1 for node {} sourceSegId {} destSegId {} mac {} ip {} mask {}" +
-                         " action {} is already done",
+        if (actionForNode == Action.ADD) {
+            LOG.trace("Adding Flow : programRouterInterfaceStage1 for node {} sourceSegId {} destSegId {} mac {} ip {} mask {}" +
+                         " action {}",
                          node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
                          macAddress, ipStr, mask, actionForNode);
-            return;
         }
 
-        Status status = this.programRouterInterfaceStage2(node, dpid, sourceSegmentationId, destinationSegmentationId,
+        this.programRouterInterfaceStage2(node, dpid, sourceSegmentationId, destinationSegmentationId,
                                                           macAddress, ipStr, mask, actionForNode);
-        if (status.isSuccess()) {
-            // Update cache
-            if (actionForNode == Action.ADD) {
-                // TODO: multiTenantAwareRouter.addInterface(UUID.fromString(tenant), ...);
-                routerInterfacesCache.add(cacheKey);
-            } else {
-                // TODO: multiTenantAwareRouter.removeInterface(...);
-                routerInterfacesCache.remove(cacheKey);
-            }
-        }
     }
 
     private Status programRouterInterfaceStage2(Node node, Long dpid, String sourceSegmentationId,
@@ -1030,34 +1150,17 @@ public class NeutronL3Adapter implements ConfigInterface {
     private boolean programStaticArpStage1(Long dpid, String segOrOfPort,
                                            String macAddress, String ipStr,
                                            Action action) {
-        // Based on the local cache, figure out whether programming needs to occur. To do this, we
-        // will look at desired action for node.
-        //
-        final String cacheKey = dpid + ":" + segOrOfPort + ":" + ipStr;
-        final boolean isProgrammed = staticArpEntryCache.contains(cacheKey);
-
-        if (action == Action.DELETE && !isProgrammed) {
-            LOG.trace("programStaticArpStage1 dpid {} segOrOfPort {} mac {} ip {} action {} is already done",
+        if (action == Action.DELETE ) {
+            LOG.trace("Deleting Flow : programStaticArpStage1 dpid {} segOrOfPort {} mac {} ip {} action {}",
                     dpid, segOrOfPort, macAddress, ipStr, action);
-            return true;
         }
-        if (action == Action.ADD && isProgrammed) {
-            LOG.trace("programStaticArpStage1 dpid {} segOrOfPort {} mac {} ip {} action {} is already done",
+        if (action == Action.ADD) {
+            LOG.trace("Adding Flow : programStaticArpStage1 dpid {} segOrOfPort {} mac {} ip {} action {} is already done",
                     dpid, segOrOfPort, macAddress, ipStr, action);
-            return true;
         }
 
         Status status = this.programStaticArpStage2(dpid, segOrOfPort, macAddress, ipStr, action);
-        if (status.isSuccess()) {
-            // Update cache
-            if (action == Action.ADD) {
-                staticArpEntryCache.add(cacheKey);
-            } else {
-                staticArpEntryCache.remove(cacheKey);
-            }
-            return true;
-        }
-        return false;
+        return status.isSuccess();
     }
 
     private Status programStaticArpStage2(Long dpid,
@@ -1090,37 +1193,20 @@ public class NeutronL3Adapter implements ConfigInterface {
     private boolean programInboundIpRewriteStage1(Long dpid, Long inboundOFPort, String providerSegmentationId,
                                                   String matchAddress, String rewriteAddress,
                                                   Action action) {
-        // Based on the local cache, figure out whether programming needs to occur. To do this, we
-        // will look at desired action for node.
-        //
-        final String cacheKey = dpid + ":" + inboundOFPort + ":" + providerSegmentationId + ":" + matchAddress;
-        final boolean isProgrammed = inboundIpRewriteCache.contains(cacheKey);
-
-        if (action == Action.DELETE && !isProgrammed) {
-            LOG.trace("programInboundIpRewriteStage1 dpid {} OFPort {} seg {} matchAddress {} rewriteAddress {}" +
-                    " action {} is already done",
+        if (action == Action.DELETE ) {
+            LOG.trace("Deleting Flow : programInboundIpRewriteStage1 dpid {} OFPort {} seg {} matchAddress {} rewriteAddress {}" +
+                    " action {}",
                     dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
-            return true;
         }
-        if (action == Action.ADD && isProgrammed) {
-            LOG.trace("programInboundIpRewriteStage1 dpid {} OFPort {} seg {} matchAddress {} rewriteAddress {}" +
-                    " action is already done",
+        if (action == Action.ADD ) {
+            LOG.trace("Adding Flow : programInboundIpRewriteStage1 dpid {} OFPort {} seg {} matchAddress {} rewriteAddress {}" +
+                    " action {}",
                     dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
-            return true;
         }
 
         Status status = programInboundIpRewriteStage2(dpid, inboundOFPort, providerSegmentationId, matchAddress,
                 rewriteAddress, action);
-        if (status.isSuccess()) {
-            // Update cache
-            if (action == Action.ADD) {
-                inboundIpRewriteCache.add(cacheKey);
-            } else {
-                inboundIpRewriteCache.remove(cacheKey);
-            }
-            return true;
-        }
-        return false;
+        return status.isSuccess();
     }
 
     private Status programInboundIpRewriteStage2(Long dpid, Long inboundOFPort, String providerSegmentationId,
@@ -1155,33 +1241,16 @@ public class NeutronL3Adapter implements ConfigInterface {
 
     private void programIpRewriteExclusionStage1(Node node, Long dpid, String providerSegmentationId, String cidr,
                                                  Action actionForRewriteExclusion) {
-        // Based on the local cache, figure out whether programming needs to occur. To do this, we
-        // will look at desired action for node.
-        //
-        final String cacheKey = node.getNodeId().getValue() + ":" + providerSegmentationId + ":" + cidr;
-        final boolean isProgrammed = outboundIpRewriteExclusionCache.contains(cacheKey);
-
-        if (actionForRewriteExclusion == Action.DELETE && !isProgrammed) {
-            LOG.trace("programIpRewriteExclusionStage1 node {} providerId {} cidr {} action {} is already done",
+        if (actionForRewriteExclusion == Action.DELETE ) {
+            LOG.trace("Deleting Flow : programIpRewriteExclusionStage1 node {} providerId {} cidr {} action {}",
                          node.getNodeId().getValue(), providerSegmentationId, cidr, actionForRewriteExclusion);
-            return;
         }
-        if (actionForRewriteExclusion == Action.ADD && isProgrammed) {
-            LOG.trace("programIpRewriteExclusionStage1 node {} providerId {} cidr {} action {} is already done",
+        if (actionForRewriteExclusion == Action.ADD) {
+            LOG.trace("Adding Flow : programIpRewriteExclusionStage1 node {} providerId {} cidr {} action {}",
                          node.getNodeId().getValue(), providerSegmentationId, cidr, actionForRewriteExclusion);
-            return;
         }
 
-        Status status = this.programIpRewriteExclusionStage2(node, dpid, providerSegmentationId, cidr,
-                                                             actionForRewriteExclusion);
-        if (status.isSuccess()) {
-            // Update cache
-            if (actionForRewriteExclusion == Action.ADD) {
-                    outboundIpRewriteExclusionCache.add(cacheKey);
-            } else {
-                    outboundIpRewriteExclusionCache.remove(cacheKey);
-            }
-        }
+        this.programIpRewriteExclusionStage2(node, dpid, providerSegmentationId, cidr,actionForRewriteExclusion);
     }
 
     private Status programIpRewriteExclusionStage2(Node node, Long dpid, String providerSegmentationId, String cidr,
@@ -1202,34 +1271,17 @@ public class NeutronL3Adapter implements ConfigInterface {
     }
 
     private void programOutboundIpRewriteStage1(FloatIpData fid, Action action) {
-        // Based on the local cache, figure out whether programming needs to occur. To do this, we
-        // will look at desired action for node.
-        //
-        final String cacheKey = fid.dpid + ":" + fid.segId + ":" + fid.fixedIpAddress;
-        final boolean isProgrammed = outboundIpRewriteCache.contains(cacheKey);
 
-        if (action == Action.DELETE && !isProgrammed) {
-            LOG.trace("programOutboundIpRewriteStage1 dpid {} seg {} fixedIpAddress {} floatIp {} action {} " +
-                         "is already done",
+        if (action == Action.DELETE) {
+            LOG.trace("Deleting Flow : programOutboundIpRewriteStage1 dpid {} seg {} fixedIpAddress {} floatIp {} action {} ",
                     fid.dpid, fid.segId, fid.fixedIpAddress, fid.floatingIpAddress, action);
-            return;
         }
-        if (action == Action.ADD && isProgrammed) {
-            LOG.trace("programOutboundIpRewriteStage1 dpid {} seg {} fixedIpAddress {} floatIp {} action {} " +
-                         "is already done",
+        if (action == Action.ADD) {
+            LOG.trace("Adding Flow : programOutboundIpRewriteStage1 dpid {} seg {} fixedIpAddress {} floatIp {} action {} " ,
                     fid.dpid, fid.segId, fid.fixedIpAddress, fid.floatingIpAddress, action);
-            return;
         }
 
-        Status status = this.programOutboundIpRewriteStage2(fid, action);
-        if (status.isSuccess()) {
-            // Update cache
-            if (action == Action.ADD) {
-                outboundIpRewriteCache.add(cacheKey);
-            } else {
-                outboundIpRewriteCache.remove(cacheKey);
-            }
-        }
+        this.programOutboundIpRewriteStage2(fid, action);
     }
 
     private Status programOutboundIpRewriteStage2(FloatIpData fid, Action action) {
@@ -1432,6 +1484,8 @@ public class NeutronL3Adapter implements ConfigInterface {
             neutronPortCache = (INeutronPortCRUD)impl;
         } else if (impl instanceof INeutronSubnetCRUD) {
             neutronSubnetCache = (INeutronSubnetCRUD)impl;
+        } else if (impl instanceof INeutronFloatingIPCRUD) {
+            neutronFloatingIpCache = (INeutronFloatingIPCRUD)impl;
         } else if (impl instanceof ArpProvider) {
             arpProvider = (ArpProvider)impl;
         } else if (impl instanceof InboundNatProvider) {
@@ -1445,5 +1499,6 @@ public class NeutronL3Adapter implements ConfigInterface {
         }else if (impl instanceof GatewayMacResolver) {
             gatewayMacResolver = (GatewayMacResolver)impl;
         }
+        populateL3ForwardingCaches();
     }
 }
index 0f7cd698930dac213d07e4f8accb34de445578e4..7e21101e004a9e3cff4cab2f7adeacd8f6240e48 100644 (file)
@@ -164,6 +164,19 @@ public class NodeCacheManagerImpl extends AbstractHandler implements NodeCacheMa
         return nodes;
     }
 
+    private void populateNodeCache() {
+        LOG.debug("populateNodeCache : Populating the node cache");
+        List<Node> nodes = southbound.readOvsdbTopologyNodes();
+        for(Node ovsdbNode : nodes) {
+            this.nodeCache.put(ovsdbNode.getNodeId(), ovsdbNode);
+        }
+        nodes = southbound.readOvsdbTopologyBridgeNodes();
+        for(Node bridgeNode : nodes) {
+            this.nodeCache.put(bridgeNode.getNodeId(), bridgeNode);
+        }
+        LOG.debug("populateNodeCache : Node cache population is done. Total nodes : {}",this.nodeCache.size());
+    }
+
     @Override
     public void setDependencies(ServiceReference serviceReference) {
         southbound =
@@ -171,6 +184,7 @@ public class NodeCacheManagerImpl extends AbstractHandler implements NodeCacheMa
         eventDispatcher =
                 (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
         eventDispatcher.eventHandlerAdded(serviceReference, this);
+        populateNodeCache();
     }
 
     @Override
index 4e309a81b89666c43ff8b2ee6b278fa365f4a5e7..38eeaecbdab60b1cf01d9e76dbf35d85703f1943 100644 (file)
@@ -33,6 +33,8 @@ 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.OvsdbTerminationPointAugmentationBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsKey;
 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;
@@ -128,6 +130,21 @@ public class SouthboundImpl implements Southbound {
         return ovsdbNodes;
     }
 
+    public List<Node> readOvsdbTopologyBridgeNodes() {
+        List<Node> ovsdbNodes = new ArrayList<>();
+        InstanceIdentifier<Topology> topologyInstanceIdentifier = MdsalHelper.createInstanceIdentifier();
+        Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, topologyInstanceIdentifier);
+        if (topology != null && topology.getNode() != null) {
+            for (Node node : topology.getNode()) {
+                OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class);
+                if (ovsdbBridgeAugmentation != null) {
+                    ovsdbNodes.add(node);
+                }
+            }
+        }
+        return ovsdbNodes;
+    }
+
     public Node readOvsdbNode(Node bridgeNode) {
         Node ovsdbNode = null;
         OvsdbBridgeAugmentation bridgeAugmentation = extractBridgeAugmentation(bridgeNode);
@@ -182,6 +199,13 @@ public class SouthboundImpl implements Southbound {
             ovsdbBridgeAugmentationBuilder.setProtocolEntry(createMdsalProtocols());
             ovsdbBridgeAugmentationBuilder.setFailMode(
                     MdsalHelper.OVSDB_FAIL_MODE_MAP.inverse().get("secure"));
+            BridgeOtherConfigsBuilder bridgeOtherConfigsBuilder = new BridgeOtherConfigsBuilder();
+            bridgeOtherConfigsBuilder.setBridgeOtherConfigKey(MdsalHelper.DISABLE_IN_BAND);
+            bridgeOtherConfigsBuilder.setBridgeOtherConfigValue("true");
+            bridgeOtherConfigsBuilder.setBridgeOtherConfigKey(MdsalHelper.DISABLE_IN_BAND);
+            List<BridgeOtherConfigs> bridgeOtherConfigsList = new ArrayList<>();
+            bridgeOtherConfigsList.add(bridgeOtherConfigsBuilder.build());
+            ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(bridgeOtherConfigsList);
             setManagedByForBridge(ovsdbBridgeAugmentationBuilder, ovsdbNode.getKey());
             if (isOvsdbNodeDpdk(ovsdbNode)) {
                 ovsdbBridgeAugmentationBuilder.setDatapathType(DatapathTypeNetdev.class);
index 08d0d4d502f48b889e5457858e7dbffb58eccc66..08f0c415b97f15f594215c64fbbbfa680bf48081 100644 (file)
@@ -195,7 +195,10 @@ public class NeutronPortInterface extends AbstractNeutronInterface<Port, Neutron
             NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces().fetchINeutronSecurityGroupCRUD(this);
             INeutronSecurityGroupCRUD sgIf = interfaces.getSecurityGroupInterface();
             for (Uuid sgUuid : port.getSecurityGroups()) {
-                allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
+                NeutronSecurityGroup secGroup = sgIf.getNeutronSecurityGroup(sgUuid.getValue());
+                if (secGroup != null) {
+                    allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
+                }
             }
             List<NeutronSecurityGroup> groups = new ArrayList<>();
             groups.addAll(allGroups);
index c8466fec8141d8d70f3ed0a7acfb2c1f1731d3c5..fdb1e81953ce8c695e70991d86c75eef14d2cc7c 100644 (file)
@@ -8,6 +8,15 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceReference;
@@ -42,4 +51,31 @@ public class NeutronIAwareUtil {
         return instances;
     }
 
+    public static List<Neutron_IPs> convertMDSalIpToNeutronIp(List<FixedIps> fixedIps) {
+        List<Neutron_IPs> ips = null;
+        if (fixedIps != null) {
+            ips = new ArrayList<Neutron_IPs>();
+            for (FixedIps mdIP : fixedIps) {
+                Neutron_IPs ip = new Neutron_IPs();
+                ip.setIpAddress(String.valueOf(mdIP.getIpAddress().getValue()));
+                ip.setSubnetUUID(mdIP.getSubnetId().getValue());
+                ips.add(ip);
+            }
+        }
+        return ips;
+    }
+
+    public static NeutronRouter_Interface convertMDSalInterfaceToNeutronRouterInterface(
+            Port routerInterface) {
+        NeutronRouter_Interface neutronInterface = new NeutronRouter_Interface();
+        String id = String.valueOf(routerInterface.getUuid().getValue());
+        neutronInterface.setID(id);
+        neutronInterface.setTenantID(routerInterface.getTenantId().getValue());
+        neutronInterface.setSubnetUUID(routerInterface.getFixedIps().get(0).getSubnetId().getValue());
+        neutronInterface.setPortUUID(routerInterface.getUuid().getValue());
+        return neutronInterface;
+    }
+
+
+
 }
index 001cfedfad8560e82e50a7fb4d6b9a4220ed96f7..6f7bab994ce3256e36538665d2fc6f3efb7b3c53 100644 (file)
@@ -171,7 +171,10 @@ public class NeutronPortChangeListener implements DataChangeListener, AutoClosea
             NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces().fetchINeutronSecurityGroupCRUD(this);
             INeutronSecurityGroupCRUD sgIf = interfaces.getSecurityGroupInterface();
             for (Uuid sgUuid : port.getSecurityGroups()) {
-                allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
+                NeutronSecurityGroup secGroup = sgIf.getNeutronSecurityGroup(sgUuid.getValue());
+                if (secGroup != null) {
+                    allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
+                }
             }
             List<NeutronSecurityGroup> groups = new ArrayList<>();
             groups.addAll(allGroups);
index f07d2271157f468dd43b046c689586500edcb9b1..98f6a646943ab439eabc6bdd91b6ebc0ac37c085 100644 (file)
@@ -21,7 +21,9 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.OngoingStubbing;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
@@ -33,6 +35,8 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
+import org.powermock.api.mockito.PowerMockito;
+
 /**
  * Unit test for class {@link MdsalUtils}
  *
@@ -46,13 +50,24 @@ public class MdsalUtilsTest {
     @Mock private DataBroker databroker;
 
     @Test
-    public void testDelete() {
+    public void testDelete() throws ReadFailedException{
         WriteTransaction writeTransaction = mock(WriteTransaction.class);
         when(databroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
         CheckedFuture<Void, TransactionCommitFailedException> future = mock(CheckedFuture.class);
         when(writeTransaction.submit()).thenReturn(future );
+        InstanceIdentifier<?> iid = mock(InstanceIdentifier.class);
+
+        ReadOnlyTransaction readOnlyTransaction = mock(ReadOnlyTransaction.class);
+        when(databroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+        CheckedFuture<Optional, ReadFailedException> futureRead = mock(CheckedFuture.class);
+        Optional opt = mock(Optional.class);
+        when(opt.isPresent()).thenReturn(true);
+        DataObject obj = mock(DataObject.class);
+        when(opt.get()).thenReturn(obj );
+        when(futureRead.checkedGet()).thenReturn(opt);
+        when(readOnlyTransaction.read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(futureRead);
 
-        boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, mock(InstanceIdentifier.class));
+        boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, iid);
 
         verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
         verify(writeTransaction, times(1)).submit();
index 8fca5108934e086d172f86a60072c0c55c88959b..c0d6a019f396f60d42fe443132dbb5bc70b32eac 100644 (file)
@@ -280,7 +280,7 @@ public class NeutronL3AdapterTest {
 
         // Suppress the called to these functions
         MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programOutboundIpRewriteStage1", floatingIpClass, Action.class));
-
+        PowerMockito.doReturn(floatIpDataMapCache.values()).when(neutronL3Adapter, "getAllFloatingIPsWithMetadata");
         Whitebox.invokeMethod(neutronL3Adapter, "flushExistingIpRewrite");
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programOutboundIpRewriteStage1", any(floatingIpClass), eq(Action.DELETE));
     }
@@ -297,6 +297,7 @@ public class NeutronL3AdapterTest {
         // Suppress the called to these functions
         MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programOutboundIpRewriteStage1", floatingIpClass, Action.class));
 
+        PowerMockito.doReturn(floatIpDataMapCache.values()).when(neutronL3Adapter, "getAllFloatingIPsWithMetadata");
         Whitebox.invokeMethod(neutronL3Adapter, "rebuildExistingIpRewrite");
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programOutboundIpRewriteStage1", any(floatingIpClass), eq(Action.ADD));
     }
@@ -519,10 +520,8 @@ public class NeutronL3AdapterTest {
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programStaticArpStage1", anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
     }
 
-    // either add or remove item in l3ForwardingCache
     @Test
     public void testProgramL3ForwardingStage1() throws Exception {
-        Set<String> l3ForwardingCache = new HashSet<>();
 
         NodeId nodeId = mock(NodeId.class);
         when(nodeId.getValue()).thenReturn(ID);
@@ -533,22 +532,16 @@ public class NeutronL3AdapterTest {
         MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programL3ForwardingStage2", Node.class, Long.class, String.class, String.class, String.class, Action.class));
 
         // init instance variables
-        MemberModifier.field(NeutronL3Adapter.class, "l3ForwardingCache").set(neutronL3Adapter , l3ForwardingCache );
         PowerMockito.when(neutronL3Adapter, "programL3ForwardingStage2", any(Node.class), anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD)).thenReturn(new Status(StatusCode.SUCCESS));
         PowerMockito.when(neutronL3Adapter, "programL3ForwardingStage2", any(Node.class), anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE)).thenReturn(new Status(StatusCode.SUCCESS));
 
-        int temp = l3ForwardingCache.size();
 
         Whitebox.invokeMethod(neutronL3Adapter, "programL3ForwardingStage1", node, Long.valueOf(45), SEG_ID, MAC_ADDRESS, IP, Action.ADD);
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programL3ForwardingStage2", any(Node.class), anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
-        assertEquals("Error, did not add the value", temp, l3ForwardingCache.size()-1);
 
-        l3ForwardingCache.add(node.getNodeId().getValue() + ":" + SEG_ID + ":" + IP);
-        temp = l3ForwardingCache.size();
 
         Whitebox.invokeMethod(neutronL3Adapter, "programL3ForwardingStage1", node, Long.valueOf(45), SEG_ID, MAC_ADDRESS, IP, Action.DELETE);
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programL3ForwardingStage2", any(Node.class), anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
-        assertEquals("Error, did not delete the value", temp, l3ForwardingCache.size()+1);
     }
 
     @Test
@@ -715,7 +708,6 @@ public class NeutronL3AdapterTest {
 
     @Test
     public void testProgramRouterInterfaceStage1() throws Exception {
-        Set<String> routerInterfacesCache = new HashSet<>();
 
         NodeId nodeId = mock(NodeId.class);
         when(nodeId.getValue()).thenReturn(ID);
@@ -724,24 +716,18 @@ public class NeutronL3AdapterTest {
 
         MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programRouterInterfaceStage2", Node.class, Long.class, String.class, String.class, String.class, String.class, int.class, Action.class));
 
-        MemberModifier.field(NeutronL3Adapter.class, "routerInterfacesCache").set(neutronL3Adapter , routerInterfacesCache);
         PowerMockito.when(neutronL3Adapter, "programRouterInterfaceStage2", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyString(), anyInt(), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
 
-        int t = routerInterfacesCache.size();
 
         Whitebox.invokeMethod(neutronL3Adapter, "programRouterInterfaceStage1", node, Long.valueOf(12), SEG_ID, SEG_ID, MAC_ADDRESS, IP, 4, Action.ADD);
 
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programRouterInterfaceStage1", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyString(), anyInt(), eq(Action.ADD));
-        assertEquals("Error, did not add the interface", t, routerInterfacesCache.size() - 1);
 
-        t = routerInterfacesCache.size();
         Whitebox.invokeMethod(neutronL3Adapter, "programRouterInterfaceStage1", node, Long.valueOf(12), SEG_ID, SEG_ID, MAC_ADDRESS, IP, 4, Action.DELETE);
 
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programRouterInterfaceStage1", any(Node.class), anyLong(), anyString(), anyString(), anyString(), anyString(), anyInt(), eq(Action.DELETE));
-        assertEquals("Error, did not delete the interface", t, routerInterfacesCache.size() + 1);
     }
 
-    // either add or remove routerInterfacesCache
     @Test
     public void testProgramRouterInterfaceStage2() throws Exception {
         NodeId nodeId = mock(NodeId.class);
@@ -759,28 +745,21 @@ public class NeutronL3AdapterTest {
 
     }
 
-    //either add or remove staticArpEntryCache
     @Test
     public void testProgramStaticArpStage1() throws Exception {
-        Set<String> staticArpEntryCache = new HashSet<>();
 
         MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programStaticArpStage2", Long.class, String.class, String.class, String.class, Action.class));
 
-        MemberModifier.field(NeutronL3Adapter.class, "staticArpEntryCache").set(neutronL3Adapter , staticArpEntryCache);
         PowerMockito.when(neutronL3Adapter, "programStaticArpStage2", anyLong(), anyString(), anyString(), anyString(), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
 
-        int t = staticArpEntryCache.size();
 
         Whitebox.invokeMethod(neutronL3Adapter, "programStaticArpStage1", Long.valueOf(12), PORT_INT, MAC_ADDRESS, IP, Action.ADD);
 
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programStaticArpStage2", anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
-        assertEquals("Error, did not add the static arp", t, staticArpEntryCache.size() - 1);
 
-        t = staticArpEntryCache.size();
         Whitebox.invokeMethod(neutronL3Adapter, "programStaticArpStage1", Long.valueOf(12), PORT_INT, MAC_ADDRESS, IP, Action.DELETE);
 
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programStaticArpStage2", anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
-        assertEquals("Error, did not delete the static arp", t, staticArpEntryCache.size() + 1);
     }
 
     @Test
@@ -794,28 +773,21 @@ public class NeutronL3AdapterTest {
         assertEquals("Error, this not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(neutronL3Adapter, "programStaticArpStage2", Long.valueOf(45), PORT_INT, MAC_ADDRESS, IP, Action.ADD));
     }
 
-    // either add or remove inboundIpRewriteCache
     @Test
     public void testProgramInboundIpRewriteStage1() throws Exception {
-        Set<String> inboundIpRewriteCache = new HashSet<>();
 
         MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programInboundIpRewriteStage2", Long.class, Long.class, String.class, String.class, String.class, Action.class));
 
-        MemberModifier.field(NeutronL3Adapter.class, "inboundIpRewriteCache").set(neutronL3Adapter , inboundIpRewriteCache);
         PowerMockito.when(neutronL3Adapter, "programInboundIpRewriteStage2", anyLong(), anyLong(), anyString(), anyString(), anyString(), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
 
-        int t = inboundIpRewriteCache.size();
 
         Whitebox.invokeMethod(neutronL3Adapter, "programInboundIpRewriteStage1", Long.valueOf(12), Long.valueOf(12), PORT_INT, MAC_ADDRESS, IP, Action.ADD);
 
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programInboundIpRewriteStage2", anyLong(), anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
-        assertEquals("Error, did not add the inboundIpRewrite", t, inboundIpRewriteCache.size() - 1);
 
-        t = inboundIpRewriteCache.size();
         Whitebox.invokeMethod(neutronL3Adapter, "programInboundIpRewriteStage1", Long.valueOf(12), Long.valueOf(12),PORT_INT, MAC_ADDRESS, IP, Action.DELETE);
 
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programInboundIpRewriteStage2", anyLong(), anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
-        assertEquals("Error, did not delete the inboundIpRewrite", t, inboundIpRewriteCache.size() + 1);
     }
 
     @Test
@@ -829,10 +801,8 @@ public class NeutronL3AdapterTest {
         assertEquals("Error, this not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(neutronL3Adapter, "programInboundIpRewriteStage2", Long.valueOf(45), Long.valueOf(45), SEG_ID, MAC_ADDRESS, IP, Action.ADD));
     }
 
-    // either add or remove outboundIpRewriteExclusionCache
     @Test
     public void testProgramIpRewriteExclusionStage1() throws Exception {
-        Set<String> outboundIpRewriteExclusionCache = new HashSet<>();
 
         NodeId nodeId = mock(NodeId.class);
         when(nodeId.getValue()).thenReturn(ID);
@@ -841,21 +811,16 @@ public class NeutronL3AdapterTest {
 
         MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programIpRewriteExclusionStage2", Node.class, Long.class, String.class, String.class, Action.class));
 
-        MemberModifier.field(NeutronL3Adapter.class, "outboundIpRewriteExclusionCache").set(neutronL3Adapter , outboundIpRewriteExclusionCache);
         PowerMockito.when(neutronL3Adapter, "programIpRewriteExclusionStage2", any(Node.class), anyLong(), anyString(), anyString(), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
 
-        int t = outboundIpRewriteExclusionCache.size();
 
         Whitebox.invokeMethod(neutronL3Adapter, "programIpRewriteExclusionStage1", node, Long.valueOf(12), SEG_ID, CIDR, Action.ADD);
 
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programIpRewriteExclusionStage2", any(Node.class), anyLong(), anyString(), anyString(), eq(Action.ADD));
-        assertEquals("Error, did not add the outboundIpRewriteExclusion", t, outboundIpRewriteExclusionCache.size() - 1);
 
-        t = outboundIpRewriteExclusionCache.size();
         Whitebox.invokeMethod(neutronL3Adapter, "programIpRewriteExclusionStage1", node, Long.valueOf(12), SEG_ID, CIDR, Action.DELETE);
 
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programIpRewriteExclusionStage2", any(Node.class), anyLong(), anyString(), anyString(), eq(Action.DELETE));
-        assertEquals("Error, did not delete the outboundIpRewriteExclusion", t, outboundIpRewriteExclusionCache.size() + 1);
     }
 
     @Test
@@ -868,29 +833,22 @@ public class NeutronL3AdapterTest {
         assertEquals("Error, this not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(neutronL3Adapter, "programIpRewriteExclusionStage2", node, Long.valueOf(45), SEG_ID, CIDR, Action.ADD));
     }
 
-    // either add or remove outboundIpRewriteCache
     @SuppressWarnings("unchecked")
     @Test
     public void testProgramOutboundIpRewriteStage1() throws Exception{
-        Set<String> outboundIpRewriteCache = new HashSet<>();
 
         MemberModifier.suppress(MemberMatcher.method(NeutronL3Adapter.class, "programOutboundIpRewriteStage2", floatingIpClass, Action.class));
 
-        MemberModifier.field(NeutronL3Adapter.class, "outboundIpRewriteCache").set(neutronL3Adapter , outboundIpRewriteCache);
         PowerMockito.when(neutronL3Adapter, "programOutboundIpRewriteStage2", any(floatingIpClass), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
 
-        int t = outboundIpRewriteCache.size();
 
         Whitebox.invokeMethod(neutronL3Adapter, "programOutboundIpRewriteStage1", floatingIpObject, Action.ADD);
 
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programOutboundIpRewriteStage2", any(floatingIpClass), eq(Action.ADD));
-        assertEquals("Error, did not add the outbound ip", t, outboundIpRewriteCache.size() - 1);
 
-        t = outboundIpRewriteCache.size();
         Whitebox.invokeMethod(neutronL3Adapter, "programOutboundIpRewriteStage1", floatingIpObject, Action.DELETE);
 
         PowerMockito.verifyPrivate(neutronL3Adapter, times(1)).invoke("programOutboundIpRewriteStage2", any(floatingIpClass), eq(Action.DELETE));
-        assertEquals("Error, did not delete the outbound ip", t, outboundIpRewriteCache.size() + 1);
     }
 
     /*@Test
@@ -967,6 +925,8 @@ public class NeutronL3AdapterTest {
 
     @Test
     public void testSetDependenciesObject() throws Exception{
+        MemberModifier.field(NeutronL3Adapter.class, "enabled").set(neutronL3Adapter , false);
+
         INeutronNetworkCRUD iNeutronNetworkCRUD = mock(INeutronNetworkCRUD.class);
         neutronL3Adapter.setDependencies(iNeutronNetworkCRUD);
         assertEquals("Error, did not return the correct object", getField("neutronNetworkCache"), iNeutronNetworkCRUD);
@@ -998,6 +958,8 @@ public class NeutronL3AdapterTest {
         L3ForwardingProvider l3ForwardingProvider = mock(L3ForwardingProvider.class);
         neutronL3Adapter.setDependencies(l3ForwardingProvider);
         assertEquals("Error, did not return the correct object", getField("l3ForwardingProvider"), l3ForwardingProvider);
+
+        MemberModifier.field(NeutronL3Adapter.class, "enabled").set(neutronL3Adapter , true);
     }
 
     private Object getField(String fieldName) throws Exception {
@@ -1011,6 +973,6 @@ public class NeutronL3AdapterTest {
         Class clazz = Whitebox.getInnerClassType(NeutronL3Adapter.class, "FloatIpData");
         Constructor [] constructors = clazz.getConstructors();
         Constructor c  = constructors[0];
-        return c.newInstance(new NeutronL3Adapter(), 415L, 415L, "a", "b", "c", "d", "e");
+        return c.newInstance(neutronL3Adapter, 415L, 415L, "a", "b", "c", "d", "e");
     }
 }
diff --git a/resources/commons/Ovsdb-HwvtepSouthbound-Collection.json.postman_collection b/resources/commons/Ovsdb-HwvtepSouthbound-Collection.json.postman_collection
new file mode 100755 (executable)
index 0000000..d629dbd
--- /dev/null
@@ -0,0 +1,222 @@
+{
+    "id":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+    "name":"Ovsdb HwvtepSouthbound",
+    "timestamp":1424977469540,
+    "order":[
+        "e9ff6957-4dc2-9257-c0c6-21560bfd5de2",
+        "ee151670-85a0-30ec-b22b-5defe7b66e0b",
+        "6de1ede7-817c-ccbb-3df9-ef510bdaf583",
+        "6e7c88e4-485d-ab9f-4c3a-cc235e022905",
+        "92ee7422-5b08-6d63-2b95-961ec0e18ffa",
+        "e92ac963-daaf-0899-c3e8-a00d897be0e2",
+        "9bc22ca7-049c-af51-7c12-6bf71044b2ec",
+        "f6d300f7-380a-d090-0d4a-2b2ddefe5104",
+        "f9f71d74-a49d-b190-d929-b6772ce0ba73",
+        "18032e93-3bc5-9976-4525-fe1e77e98207",
+        "22354294-1d01-cebf-180c-d609747be9bc",
+        "c8e8f3fd-3bfb-aafa-e3ec-a671a942f426",
+        "d362ddc4-1c5f-67d5-e354-c2a8d2ba9d79",
+        "538c71b3-e3e6-f01b-cc4c-d2b686686aa8"
+    ],
+    "owner":0,
+    "sharedWithTeam":false,
+    "synced":false,
+    "subscribed":false,
+    "hasRequests":true,
+    "requests":[
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"18032e93-3bc5-9976-4525-fe1e77e98207",
+            "name":"Delete Specific Config Logical Switch",
+            "description":"This restconf request delete specific logical switch from the config data store.",
+            "url":"http://odl:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F192.168.1.115:6640%2Flogicalswitch%2Fls0",
+            "method":"DELETE",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":[],
+            "dataMode":"params",
+            "timestamp":0,
+            "version":2,
+            "time":1447335528744
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"22354294-1d01-cebf-180c-d609747be9bc",
+            "name":"Get All Operational Topology",
+            "description":"This restconf request will fetch the operational topology. Operational topology details are fetch by hwvtepsouthbound plugin from all the connected hwvtep node.",
+            "url":"http://odl:8181/restconf/operational/network-topology:network-topology/",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":[],
+            "dataMode":"params",
+            "timestamp":0,
+            "version":2
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"538c71b3-e3e6-f01b-cc4c-d2b686686aa8",
+            "name":"Get Specific Operational Logical Switch",
+            "description":"This restconf request fetch the operational for specific Logical Switch",
+            "url":"http://odl:8181/restconf/operational/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F192.168.1.115:6640%2logicalswitch%2ls0",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://192.168.1.115:6640/logicalswitch/ls0\",\n            \"hwvtep-node-description\": \"\",\n            \"hwvtep-node-name\": \"ls0\",\n            \"tunnel-key\": \"10000\"\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447335701900
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"6de1ede7-817c-ccbb-3df9-ef510bdaf583",
+            "name":"Create Specific Config HwvtepNode",
+            "description":"Fire this Restconf request if you want to initiate the connection to hwvtep node from controller. It assumes that hwvtep node is listening for tcp connection in passive mode.",
+            "url":"http://odl:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/",
+            "method":"POST",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://192.168.1.115:6640\",\n            \"connection-info\": {\n              \"ovsdb:remote-port\": 6640,\n              \"ovsdb:remote-ip\": \"192.168.1.115\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447334840814
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"6e7c88e4-485d-ab9f-4c3a-cc235e022905",
+            "name":"Update Specific Config HwvtepNode",
+            "description":"Fire this Restconf request if you want to update the connection to Hwvtep node from controller.",
+            "url":"http://odl:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F192.168.1.115:6640",
+            "method":"PUT",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://192.168.1.115:6640\",\n            \"connection-info\": {\n              \"ovsdb:remote-port\": 6640,\n              \"ovsdb:remote-ip\": \"192.168.1.115\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447334483164
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"92ee7422-5b08-6d63-2b95-961ec0e18ffa",
+            "name":"Get Specific Config HwvtepNode",
+            "description":"This restconf request fetch the configration for specific hwvtep node.",
+            "url":"http://odl:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F192.168.1.115:6640",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://192.168.1.115:6640\",\n            \"connection-info\": {\n              \"ovsdb:remote-port\": 6640,\n              \"ovsdb:remote-ip\": \"192.168.1.115\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447334914971
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"9bc22ca7-049c-af51-7c12-6bf71044b2ec",
+            "name":"Create Specific Config Logical Switch",
+            "description":"Fire this Restconf request if you want to create a logical switch.",
+            "url":"http://odl:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/",
+            "method":"POST",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://192.168.1.115:6640/logicalswitch/ls0\",\n            \"hwvtep-node-description\": \"\",\n            \"hwvtep-node-name\": \"ls0\",\n            \"tunnel-key\": \"10000\",\n            \"managed-by\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://192.168.1.115:6640']\"             \n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447340822378
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"c8e8f3fd-3bfb-aafa-e3ec-a671a942f426",
+            "name":"Get Operational Hwvtep Topology",
+            "description":"",
+            "url":"http://odl:8181/restconf/operational/network-topology:network-topology/hwvtep:1/",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://192.168.1.115:6640\",\n            \"connection-info\": {\n              \"ovsdb:remote-port\": 6640,\n              \"ovsdb:remote-ip\": \"192.168.1.115\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447335830695
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"d362ddc4-1c5f-67d5-e354-c2a8d2ba9d79",
+            "name":"Get Specific Operational HwvtepNode",
+            "description":"This restconf request fetch the operational for specific HwvtepNode",
+            "url":"http://odl:8181/restconf/operational/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F192.168.1.115:6640",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://192.168.1.115:6640/logicalswitch/ls0\",\n            \"hwvtep-node-description\": \"\",\n            \"hwvtep-node-name\": \"ls0\",\n            \"tunnel-key\": \"10000\"\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447335686540
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"e92ac963-daaf-0899-c3e8-a00d897be0e2",
+            "name":"Delete Specific Config HwvtepNode",
+            "description":"This restconf request delete any node (ovsdb node or bridge node) from the config data store. You can use the same request to delete the ovsdb node by using the following URI: http://localhost:8080/restconf/config/network-topology:network-topology/topology/ovsdb:1/node/ovsdb:%2F%2F10.10.10.10:22222",
+            "url":"http://odl:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F219.141.189.115:6640",
+            "method":"DELETE",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":[],
+            "dataMode":"params",
+            "timestamp":0,
+            "version":2
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"e9ff6957-4dc2-9257-c0c6-21560bfd5de2",
+            "name":"Get All Config Topology",
+            "description":"Fetch all the config topology from configuration data store.",
+            "url":"http://odl:8181/restconf/config/network-topology:network-topology/",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://219.141.189.115:6640\",\n            \"connection-info\": {\n              \"ovsdb:remote-port\": 6640,\n              \"ovsdb:remote-ip\": \"219.141.189.115\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447311894927
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"ee151670-85a0-30ec-b22b-5defe7b66e0b",
+            "name":"Get Config  Hwvtep Topology",
+            "description":"Fetch the config hwvtep topology from configuration data store.",
+            "url":"http://odl:8181/restconf/config/network-topology:network-topology/hwvtep:1/",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://192.168.1.115:6640\",\n            \"connection-info\": {\n              \"ovsdb:remote-port\": 6640,\n              \"ovsdb:remote-ip\": \"192.168.1.115\"\n            }\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447335823182
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"f6d300f7-380a-d090-0d4a-2b2ddefe5104",
+            "name":"Create Specific Config Logical Switch",
+            "description":"Fire this request if you want to update specific logical switch.",
+            "url":"http://odl:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F192.168.1.115:6640%2Flogicalswitch%2Fls0",
+            "method":"PUT",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://192.168.1.115:6640/logicalswitch/ls0\",\n            \"hwvtep-node-description\": \"\",\n            \"hwvtep-node-name\": \"ls0\",\n            \"tunnel-key\": \"10000\",\n            \"managed-by\": \"/network-topology:network-topology/network-topology:topology[network-topology:topology-id='hwvtep:1']/network-topology:node[network-topology:node-id='hwvtep://192.168.1.115:6640']\"             \n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447340847211
+        },
+        {
+            "collectionId":"19f6b1a8-4d54-62f8-6bd6-f52e0b6e40b8",
+            "id":"f9f71d74-a49d-b190-d929-b6772ce0ba73",
+            "name":"Get Specific Config Logical Switch",
+            "description":"This restconf request fetch configuration for specific logical switch.",
+            "url":"http://odl:8181/restconf/config/network-topology:network-topology/topology/hwvtep:1/node/hwvtep:%2F%2F192.168.1.115:6640%2Flogicalswitch%2Fls0",
+            "method":"GET",
+            "headers":"Authorization: Basic YWRtaW46YWRtaW4=\n",
+            "data":"{\n  \"network-topology:node\": [\n        {\n            \"node-id\": \"hwvtep://192.168.1.115:6640/logicalswitch/ls0\",\n            \"hwvtep-node-description\": \"\",\n            \"hwvtep-node-name\": \"ls0\",\n            \"tunnel-key\": \"10000\"\n        }\n    ]\n}",
+            "dataMode":"raw",
+            "timestamp":0,
+            "version":2,
+            "time":1447335408595
+        }
+    ]
+}
index 25cf72cccfcd29a3282a6e2e0d7d567127c018c9..0cad7271a01ba6b95242b5232038e55125f7d4bb 100644 (file)
@@ -14,13 +14,13 @@ Contents
 - showOvsdbMdsal.py : Dumps mdsal related info from running ODL that is related to ovsdb and netvirt. Use 'showOvsdbMdsal.py -h' for usage
 
 - ODL-Clustering.json.postman_collection : Collection contains Restconf request to fetch clustering service related data to check the state of 3 node cluster and inventory/topology shards.
-       - Please import and load 3-Node-Cluster-Setup-Environment-Variables.postman_environment file, because Restconf request present in this collection depends on the variable defined in this collection.
+    - Please import and load 3-Node-Cluster-Setup-Environment-Variables.postman_environment file, because Restconf request present in this collection depends on the variable defined in this collection.
 
 - Ovsdb-Southbound-Collection-for-Single-Node-Cluster.json.postman_collection : Collection contains Restconf request for doing CRUD operations (connection, bridge, termination point) on southbound plugin running in standalone controller.
-       - Please import and load Single-Node-Cluster-Setup-Environment-Variables.postman_environment file, because Restconf request present in this collection depends on the variable defined in this collection.
+    - Please import and load Single-Node-Cluster-Setup-Environment-Variables.postman_environment file, because Restconf request present in this collection depends on the variable defined in this collection.
 
-- Ovsdb-Southbound-Collection-for-3-Node-Cluster.json.postman_collection : 
-       - Please import and load 3-Node-Cluster-Setup-Environment-Variables.postman_environment file, because Restconf request present in this collection depends on the variable defined in this collection.
+- Ovsdb-Southbound-Collection-for-3-Node-Cluster.json.postman_collection :
+    - Please import and load 3-Node-Cluster-Setup-Environment-Variables.postman_environment file, because Restconf request present in this collection depends on the variable defined in this collection.
 
 
 - Single-Node-Cluster-Setup-Environment-Variables.postman_environment : Postman environment file that defines variables for Restconf request for southbound plugin running in Single controller instance
@@ -28,3 +28,5 @@ Contents
 - 3-Node-Cluster-Setup-Environment-Variables.postman_environment : Postman environment file that defines variables for Restconf request for southbound plugin running in 3 node cluster environment
 
 - NetvirtSfc.json.postman_collection : Collection of REST-APIs to interact with Netvirt-Sfc.
+
+- Ovsdb-HwvtepSouthbound-Collection.json.postman_collection : Collection contains Restconf request for doing CRUD operations (hwvtep global node, physical switch, logical switch, physical locator, and physical port) on hwvtepsouthbound plugin running in standalone controller.
index aa232f171ecd91b171099fb71e25f8a46ec5a091..605f15f8f6b236337d2f161ca15aef06cb0ed0d3 100644 (file)
@@ -70,7 +70,6 @@ public class OvsdbConnectionInstance implements OvsdbClient {
     private TransactionInvoker txInvoker;
     private Map<DatabaseSchema,TransactInvoker> transactInvokers;
     private MonitorCallBack callback;
-    // private ConnectionInfo key;
     private InstanceIdentifier<Node> instanceIdentifier;
     private volatile boolean hasDeviceOwnership = false;
     private Entity connectedEntity;
index b1925261035d2877de9ba8ac930939b1cae42ee3..ecfedfe48f1b787f71331f454c1dc944ad72898e 100644 (file)
@@ -107,12 +107,13 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
                 return ovsdbConnectionInstance;
             }
             LOG.warn("OVSDB Connection Instance {} being replaced with client {}", key, externalClient);
-            ovsdbConnectionInstance.disconnect();
 
             // Unregister Cluster Ownership for ConnectionInfo
             // Because the ovsdbConnectionInstance is about to be completely replaced!
             unregisterEntityForOwnership(ovsdbConnectionInstance);
 
+            ovsdbConnectionInstance.disconnect();
+
             removeConnectionInstance(key);
         }
 
@@ -130,13 +131,17 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
         ConnectionInfo key = SouthboundMapper.createConnectionInfo(client);
         OvsdbConnectionInstance ovsdbConnectionInstance = getConnectionInstance(key);
         if (ovsdbConnectionInstance != null) {
+            // Unregister Entity ownership as soon as possible ,so this instance should
+            // not be used as a candidate in Entity election (given that this instance is
+            // about to disconnect as well), if current owner get disconnected from
+            // OVSDB device.
+            unregisterEntityForOwnership(ovsdbConnectionInstance);
+
             txInvoker.invoke(new OvsdbNodeRemoveCommand(ovsdbConnectionInstance, null, null));
-            removeConnectionInstance(key);
 
-            // Unregister Cluster Onwership for ConnectionInfo
-            unregisterEntityForOwnership(ovsdbConnectionInstance);
+            removeConnectionInstance(key);
         } else {
-            LOG.warn("OVSDB disconnected event did not find connection instance for {}", key);
+            LOG.warn("disconnected : Connection instance not found for OVSDB Node {} ", key);
         }
         LOG.trace("OvsdbConnectionManager: disconnected exit");
     }
@@ -159,7 +164,7 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
             // Register Cluster Ownership for ConnectionInfo
             registerEntityForOwnership(ovsdbConnectionInstance);
         } else {
-            LOG.warn("Failed to connect to Ovsdb Node {}", ovsdbNode.getConnectionInfo());
+            LOG.warn("Failed to connect to OVSDB Node {}", ovsdbNode.getConnectionInfo());
         }
         return client;
     }
@@ -167,12 +172,14 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
     public void disconnect(OvsdbNodeAugmentation ovsdbNode) throws UnknownHostException {
         OvsdbConnectionInstance client = getConnectionInstance(ovsdbNode.getConnectionInfo());
         if (client != null) {
-            client.disconnect();
-
             // Unregister Cluster Onwership for ConnectionInfo
             unregisterEntityForOwnership(client);
 
+            client.disconnect();
+
             removeInstanceIdentifier(ovsdbNode.getConnectionInfo());
+        } else {
+            LOG.debug("disconnect : connection instance not found for {}",ovsdbNode.getConnectionInfo());
         }
     }
 
@@ -302,33 +309,27 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
 
     private void handleOwnershipChanged(EntityOwnershipChange ownershipChange) {
         OvsdbConnectionInstance ovsdbConnectionInstance = getConnectionInstanceFromEntity(ownershipChange.getEntity());
-        LOG.info("handleOwnershipChanged: {} event received for device {}",
+        LOG.debug("handleOwnershipChanged: {} event received for device {}",
                 ownershipChange, ovsdbConnectionInstance != null ? ovsdbConnectionInstance.getConnectionInfo()
-                        : "THAT'S NOT REGISTERED BY THIS SOUTHBOUND PLUGIN INSTANCE");
+                        : "that's currently NOT registered by *this* southbound plugin instance");
 
         if (ovsdbConnectionInstance == null) {
             if (ownershipChange.isOwner()) {
-                LOG.warn("handleOwnershipChanged: found no connection instance for {}", ownershipChange.getEntity());
+                LOG.warn("handleOwnershipChanged: *this* instance is elected as an owner of the device {} but it "
+                        + "is NOT registered for ownership", ownershipChange.getEntity());
             } else {
                 // EntityOwnershipService sends notification to all the nodes, irrespective of whether
                 // that instance registered for the device ownership or not. It is to make sure that
                 // If all the controller instance that was connected to the device are down, so the
                 // running instance can clear up the operational data store even though it was not
                 // connected to the device.
-                LOG.debug("handleOwnershipChanged: found no connection instance for {}", ownershipChange.getEntity());
+                LOG.debug("handleOwnershipChanged: No connection instance found for {}", ownershipChange.getEntity());
             }
 
             // If entity has no owner, clean up the operational data store (it's possible because owner controller
             // might went down abruptly and didn't get a chance to clean up the operational data store.
             if (!ownershipChange.hasOwner()) {
-                LOG.debug("{} has no onwer, cleaning up the operational data store", ownershipChange.getEntity());
-                // Below code might look weird but it's required. We want to give first opportunity to the
-                // previous owner of the device to clean up the operational data store if there is no owner now.
-                // That way we will avoid lot of nasty md-sal exceptions because of concurrent delete.
-                if (ownershipChange.wasOwner()) {
-                    cleanEntityOperationalData(ownershipChange.getEntity());
-                }
-                // If first cleanEntityOperationalData() was called, this call will be no-op.
+                LOG.info("{} has no owner, cleaning up the operational data store", ownershipChange.getEntity());
                 cleanEntityOperationalData(ownershipChange.getEntity());
             }
             return;
@@ -337,15 +338,17 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
         putConnectionInstance(ovsdbConnectionInstance.getMDConnectionInfo(),ovsdbConnectionInstance);
 
         if (ownershipChange.isOwner() == ovsdbConnectionInstance.getHasDeviceOwnership()) {
-            LOG.debug("handleOwnershipChanged: no change in ownership for {}. Ownership status is : {}",
-                    ovsdbConnectionInstance.getConnectionInfo(), ovsdbConnectionInstance.getHasDeviceOwnership());
+            LOG.info("handleOwnershipChanged: no change in ownership for {}. Ownership status is : {}",
+                    ovsdbConnectionInstance.getConnectionInfo(), ovsdbConnectionInstance.getHasDeviceOwnership()
+                            ? SouthboundConstants.OWNERSHIPSTATES.OWNER.getState()
+                            : SouthboundConstants.OWNERSHIPSTATES.NONOWNER.getState());
             return;
         }
 
         ovsdbConnectionInstance.setHasDeviceOwnership(ownershipChange.isOwner());
         // You were not an owner, but now you are
         if (ownershipChange.isOwner()) {
-            LOG.info("handleOwnershipChanged: *this* southbound plugin instance is owner of device {}",
+            LOG.info("handleOwnershipChanged: *this* southbound plugin instance is an OWNER of the device {}",
                     ovsdbConnectionInstance.getConnectionInfo());
 
             //*this* instance of southbound plugin is owner of the device,
@@ -360,7 +363,8 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
             //when clustering service implement a ownership grant strategy which can revoke the
             //device ownership for load balancing the devices across the instances.
             //Once this condition occur, we should unregister the callback.
-            LOG.error("handleOwnershipChanged: *this* southbound plugin instance is no longer the owner of device {}",
+            LOG.error("handleOwnershipChanged: *this* southbound plugin instance is no longer the owner of device {}."
+                    + "This should NOT happen.",
                     ovsdbConnectionInstance.getNodeId().getValue());
         }
     }
@@ -423,7 +427,7 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
             iid = SouthboundMapper.getInstanceIdentifier(openvswitchRow);
             LOG.info("InstanceIdentifier {} generated for device "
                     + "connection {}",iid,ovsdbConnectionInstance.getConnectionInfo());
-
+            ovsdbConnectionInstance.setInstanceIdentifier(iid);
         }
         YangInstanceIdentifier entityId = SouthboundUtil.getInstanceIdentifierCodec().getYangInstanceIdentifier(iid);
         Entity deviceEntity = new Entity(ENTITY_TYPE, entityId);
@@ -445,7 +449,7 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
             EntityOwnershipCandidateRegistration registration =
                     entityOwnershipService.registerCandidate(candidateEntity);
             ovsdbConnectionInstance.setDeviceOwnershipCandidateRegistration(registration);
-            LOG.info("OVSDB entity {} is registred for ownership.", candidateEntity);
+            LOG.info("OVSDB entity {} is registered for ownership.", candidateEntity);
 
             //If entity already has owner, it won't get notification from EntityOwnershipService
             //so cache the connection instances.
@@ -454,16 +458,14 @@ public class OvsdbConnectionManager implements OvsdbConnectionListener, AutoClos
             if (ownershipStateOpt.isPresent()) {
                 EntityOwnershipState ownershipState = ownershipStateOpt.get();
                 if (ownershipState.hasOwner() && !ownershipState.isOwner()) {
-                    if (getConnectionInstance(ovsdbConnectionInstance.getMDConnectionInfo()) != null) {
-                        LOG.info("OVSDB entity {} is already owned by other southbound plugin "
-                                + "instance, so *this* instance is NOT an OWNER of the device",
-                                ovsdbConnectionInstance.getConnectionInfo());
-                        putConnectionInstance(ovsdbConnectionInstance.getMDConnectionInfo(),ovsdbConnectionInstance);
-                    }
+                    LOG.info("OVSDB entity {} is already owned by other southbound plugin "
+                                    + "instance, so *this* instance is NOT an OWNER of the device",
+                            ovsdbConnectionInstance.getConnectionInfo());
+                    putConnectionInstance(ovsdbConnectionInstance.getMDConnectionInfo(),ovsdbConnectionInstance);
                 }
             }
         } catch (CandidateAlreadyRegisteredException e) {
-            LOG.warn("OVSDB entity {} was already registered for {} ownership", candidateEntity, e);
+            LOG.warn("OVSDB entity {} was already registered for ownership", candidateEntity, e);
         }
 
     }
index 42c452ca5c70efa068e3a44c2170c6458105bab3..854d5b2febddd1fb03a980c7606d19bf793048e7 100755 (executable)
@@ -114,4 +114,23 @@ public class SouthboundConstants {
             return this.mode;
         }
     }
+
+    public enum OWNERSHIPSTATES {
+        OWNER("OWNER"),
+        NONOWNER("NON-OWNER");
+
+        private final String state;
+
+        OWNERSHIPSTATES(String state) {
+            this.state = state;
+        }
+        @Override
+        public String toString() {
+            return state;
+        }
+
+        public String getState() {
+            return this.state;
+        }
+    }
 }
index 8ffe4275acfa4b63616c4ba624592e952eaaea97..6055ca05f4f9d27e889b69dff40d6a307323479b 100644 (file)
@@ -245,7 +245,8 @@ public class SouthboundMapper {
         try {
             protocols = bridge.getProtocolsColumn().getData();
         } catch (SchemaVersionMismatchException e) {
-            LOG.warn("protocols not supported by this version of ovsdb", e);
+            // We don't care about the exception stack trace here
+            LOG.warn("protocols not supported by this version of ovsdb: {}", e.getMessage());
         }
         List<ProtocolEntry> protocolList = new ArrayList<>();
         if (protocols != null && protocols.size() > 0) {
index 189f5030eba576667d52f42f64af1254e94e36ac..d88074b9b3f0ee3228de54d6e49d2a6747a512eb 100644 (file)
@@ -87,6 +87,7 @@ public class SouthboundProvider implements BindingAwareProvider, AutoCloseable {
                 if (ownershipState.hasOwner() && !ownershipState.isOwner()) {
                     ovsdbConnection.registerConnectionListener(cm);
                     ovsdbConnection.startOvsdbManager(SouthboundConstants.DEFAULT_OVSDB_PORT);
+                    LOG.info("*This* instance of OVSDB southbound provider is set as a SLAVE instance");
                 }
             }
         } catch (CandidateAlreadyRegisteredException e) {
index f32cfac2df7d29d50959175861cd2306c1cc8acd..e76b96682441f1f7312f8a588d86c5028aa6592f 100644 (file)
@@ -53,7 +53,7 @@ public class ProtocolUpdateCommand extends AbstractTransactCommand {
                         entry.getKey().firstIdentifierOf(OvsdbBridgeAugmentation.class);
                 Optional<OvsdbBridgeAugmentation> bridgeOptional =
                         getOperationalState().getOvsdbBridgeAugmentation(bridgeIid);
-                OvsdbBridgeAugmentation ovsdbBridge = null;
+                OvsdbBridgeAugmentation ovsdbBridge;
                 if (bridgeOptional.isPresent()) {
                     ovsdbBridge = bridgeOptional.get();
                 } else {
@@ -74,7 +74,8 @@ public class ProtocolUpdateCommand extends AbstractTransactCommand {
                                 .where(bridge.getNameColumn().getSchema().opEqual(bridge.getNameColumn().getData()))
                                 .build());
                         } catch (SchemaVersionMismatchException e) {
-                            LOG.warn("protocol not supported by this version of ovsdb", e);
+                            // We don't care about the exception stack trace here
+                            LOG.warn("protocol not supported by this version of ovsdb: {}", e.getMessage());
                         }
                     }
                 }
index dc8bd53c94b9b40627c08cabfcfe6a5a26bed0c6..2ca74ee343b87eef35dc15ad2a7f6a05a30c20ae 100644 (file)
@@ -209,7 +209,8 @@ public class OpenVSwitchUpdateCommand extends AbstractTransactionCommand {
             }
             ovsdbNodeBuilder.setInterfaceTypeEntry(ifEntryList);
         } catch (SchemaVersionMismatchException e) {
-            LOG.debug("Iface types  not supported by this version of ovsdb",e);
+            // We don't care about the exception stack trace here
+            LOG.debug("Iface types  not supported by this version of ovsdb: {}", e.getMessage());
         }
     }
 
@@ -233,7 +234,8 @@ public class OpenVSwitchUpdateCommand extends AbstractTransactionCommand {
             }
             ovsdbNodeBuilder.setDatapathTypeEntry(dpEntryList);
         } catch (SchemaVersionMismatchException e) {
-            LOG.debug("Datapath types not supported by this version of ovsdb",e);
+            // We don't care about the exception stack trace here
+            LOG.debug("Datapath types not supported by this version of ovsdb: {}", e.getMessage());
         }
     }
 
index 55aba8b987f0e101d2d38eaeaa1ba8a57e04ae3a..47767f9da1f5c12613bcbc8ad0c3f854aaccdbb9 100644 (file)
@@ -185,7 +185,8 @@ public class OvsdbBridgeUpdateCommand extends AbstractTransactionCommand {
                 }
             }
         } catch (SchemaVersionMismatchException e) {
-            LOG.warn("protocol not supported by this version of ovsdb", e);
+            // We don't care about the exception stack trace here
+            LOG.warn("protocol not supported by this version of ovsdb: {}", e.getMessage());
         }
         return result;
     }
index 73a70f818d5487eddb30eb87d909a11c03520f9e..735ae97251b141d348946aeb8e188b12140ca85a 100644 (file)
@@ -60,7 +60,7 @@ public class OvsdbNodeRemoveCommand extends AbstractTransactionCommand {
                             getOvsdbConnectionInstance().getInstanceIdentifier());
                 } else {
                     LOG.debug("Other southbound plugin instances in cluster are connected to the device,"
-                            + " not deleting OvsdbNode form data store.");
+                            + " not deleting OvsdbNode from operational data store.");
                 }
             }
         } catch (Exception e) {
@@ -86,13 +86,14 @@ public class OvsdbNodeRemoveCommand extends AbstractTransactionCommand {
             if (connectedManager == 0) {
                 return true;
             }
-        }
-        /*When switch is listening in passive mode, this number represent number of active connection to the device
-        This is to handle the controller initiated connection scenario, where all the controller will connect, but
-        switch will have only one manager.
-        */
-        if (onlyConnectedManager.getNumberOfConnections() > ONE_ACTIVE_CONNECTION_IN_PASSIVE_MODE) {
-            return false;
+
+            /*When switch is listening in passive mode, this number represent number of active connection to the device
+            This is to handle the controller initiated connection scenario, where all the controller will connect, but
+            switch will have only one manager.
+            */
+            if (onlyConnectedManager.getNumberOfConnections() > ONE_ACTIVE_CONNECTION_IN_PASSIVE_MODE) {
+                return false;
+            }
         }
         return true;
     }
diff --git a/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/DataChangesManagedByOvsdbNodeEventTest.java b/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/DataChangesManagedByOvsdbNodeEventTest.java
new file mode 100644 (file)
index 0000000..1d4b052
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest()
+public class DataChangesManagedByOvsdbNodeEventTest {
+
+    @Mock private InstanceIdentifier<?> iid;
+    @Mock private AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> event;
+    private Set<InstanceIdentifier<?>> removedPaths;
+    private DataChangesManagedByOvsdbNodeEvent dataChangesManagedByOvsdbNodeEvent;
+
+    @Before
+    public void setUp() throws Exception {
+        dataChangesManagedByOvsdbNodeEvent = mock(DataChangesManagedByOvsdbNodeEvent.class, Mockito.CALLS_REAL_METHODS);
+        MemberModifier.field(DataChangesManagedByOvsdbNodeEvent.class, "event").set(dataChangesManagedByOvsdbNodeEvent, event);
+    }
+
+    @Test
+    public void testDataChangesManagedByOvsdbNodeEvent() {
+        DataChangesManagedByOvsdbNodeEvent dataChangesManagedByOvsdbNodeEvent1 = new DataChangesManagedByOvsdbNodeEvent(iid, event);
+        assertEquals(iid, Whitebox.getInternalState(dataChangesManagedByOvsdbNodeEvent1, "iid"));
+        assertEquals(event, Whitebox.getInternalState(dataChangesManagedByOvsdbNodeEvent1, "event"));
+    }
+
+    @Test
+    public void testGetMethods() {
+        Map<InstanceIdentifier<?>,DataObject> data = new HashMap<>();
+        DataObject dataObject = mock(DataObject.class);
+
+        //Test getCreatedData()
+        when(event.getCreatedData()).thenReturn(data);
+        assertEquals(data, dataChangesManagedByOvsdbNodeEvent.getCreatedData());
+
+        //Test getUpdatedData()
+        when(event.getUpdatedData()).thenReturn(data);
+        assertEquals(data, dataChangesManagedByOvsdbNodeEvent.getUpdatedData());
+
+        //Test getOriginalData()
+        when(event.getOriginalData()).thenReturn(data);
+        assertEquals(data, dataChangesManagedByOvsdbNodeEvent.getOriginalData());
+
+        //Test getOriginalSubtree()
+        when(event.getOriginalSubtree()).thenReturn(dataObject);
+        assertEquals(dataObject, dataChangesManagedByOvsdbNodeEvent.getOriginalSubtree());
+
+        //Test getUpdatedSubtree()
+        when(event.getUpdatedSubtree()).thenReturn(dataObject);
+        assertEquals(dataObject, dataChangesManagedByOvsdbNodeEvent.getUpdatedSubtree());
+
+        //Test getRemovedPaths()
+        removedPaths = new HashSet<>();
+        when(event.getRemovedPaths()).thenReturn(removedPaths);
+        assertEquals(removedPaths, dataChangesManagedByOvsdbNodeEvent.getRemovedPaths());
+    }
+}
diff --git a/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/OpenVSwitchBridgeAddCommandTest.java b/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/OpenVSwitchBridgeAddCommandTest.java
new file mode 100644 (file)
index 0000000..6e086b6
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.opendaylight.ovsdb.lib.notation.Column;
+import org.opendaylight.ovsdb.lib.notation.Mutator;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.operations.Insert;
+import org.opendaylight.ovsdb.lib.operations.Mutate;
+import org.opendaylight.ovsdb.lib.operations.Operation;
+import org.opendaylight.ovsdb.lib.operations.Operations;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({TyperUtils.class, TransactUtils.class})
+public class OpenVSwitchBridgeAddCommandTest {
+    private OpenVSwitchBridgeAddCommand openVSwitchBridgeAddCommand;
+
+    @Before
+    public void setUp() {
+        openVSwitchBridgeAddCommand = mock(OpenVSwitchBridgeAddCommand.class, Mockito.CALLS_REAL_METHODS);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testExecute() throws Exception {
+        TransactionBuilder transaction = mock(TransactionBuilder.class);
+        List<Operation> operations = new ArrayList<>();
+        when(transaction.getOperations()).thenReturn(operations);
+
+        Bridge bridge = mock(Bridge.class);
+        when(transaction.getDatabaseSchema()).thenReturn(mock(DatabaseSchema.class));
+        PowerMockito.mockStatic(TyperUtils.class);
+        PowerMockito.when(TyperUtils.getTypedRowWrapper(any(DatabaseSchema.class), eq(Bridge.class))).thenReturn(bridge);
+
+        List<Insert> inserts = new ArrayList<>();
+        Insert insert = mock(Insert.class);
+        inserts.add(insert);
+        PowerMockito.mockStatic(TransactUtils.class);
+        when(bridge.getSchema()).thenReturn(mock(GenericTableSchema.class));
+        PowerMockito.when(TransactUtils.extractInsert(any(TransactionBuilder.class), any(GenericTableSchema.class))).thenReturn(inserts);
+
+        OpenVSwitch ovs = mock(OpenVSwitch.class);
+        PowerMockito.when(TyperUtils.getTypedRowWrapper(any(DatabaseSchema.class), eq(OpenVSwitch.class))).thenReturn(ovs);
+        PowerMockito.when(TransactUtils.extractNamedUuid(any(Insert.class))).thenReturn(mock(UUID.class));
+        doNothing().when(ovs).setBridges(any(Set.class));
+
+        Mutate<GenericTableSchema> mutate = mock(Mutate.class);
+        Operations op = (Operations) setField("op");
+        when(op.mutate(any(OpenVSwitch.class))).thenReturn(mutate);
+        Column<GenericTableSchema, Set<UUID>> column = mock(Column.class);
+        when(ovs.getBridgesColumn()).thenReturn(column);
+        when(column.getSchema()).thenReturn(mock(ColumnSchema.class));
+        when(column.getData()).thenReturn(new HashSet<UUID>());
+        when(mutate.addMutation(any(ColumnSchema.class), any(Mutator.class), any(Set.class))).thenReturn(mutate);
+        when(transaction.add(any(Operation.class))).thenReturn(transaction);
+
+        openVSwitchBridgeAddCommand.execute(transaction);
+        verify(transaction).add(any(Operation.class));
+    }
+
+    private Object setField(String fieldName) throws Exception {
+        Field field = Operations.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        field.set(field.get(Operations.class), mock(Operations.class));
+        return field.get(Operations.class);
+    }
+}
diff --git a/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/OvsdbNodeUpdateCommandTest.java b/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/OvsdbNodeUpdateCommandTest.java
new file mode 100644 (file)
index 0000000..be1aa59
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.ovsdb.lib.notation.Column;
+import org.opendaylight.ovsdb.lib.operations.Mutate;
+import org.opendaylight.ovsdb.lib.operations.Operation;
+import org.opendaylight.ovsdb.lib.operations.Operations;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
+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.PortNumber;
+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.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberMatcher;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.google.common.collect.ImmutableMap;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({TransactUtils.class, TyperUtils.class, OvsdbNodeUpdateCommand.class, InstanceIdentifier.class})
+public class OvsdbNodeUpdateCommandTest {
+
+    private static final String EXTERNAL_ID_KEY = "external id key";
+    private static final String EXTERNAL_ID_VALUE = "external id value";
+    private static final String OTHER_CONFIG_KEY = "other config key";
+    private static final String OTHER_CONFIG_VALUE = "other config value";
+
+    @Mock private AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes;
+    private OvsdbNodeUpdateCommand ovsdbNodeUpdateCommand;
+
+    @Before
+    public void setUp() {
+        ovsdbNodeUpdateCommand = mock(OvsdbNodeUpdateCommand.class, Mockito.CALLS_REAL_METHODS);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testExecute() throws Exception {
+        TransactionBuilder transaction = mock(TransactionBuilder.class);
+        Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> updated = new HashMap<>();
+        InstanceIdentifier<OvsdbNodeAugmentation> iid = mock(InstanceIdentifier.class);
+        OvsdbNodeAugmentation ovsdbNode = mock(OvsdbNodeAugmentation.class);
+        updated.put(iid, ovsdbNode);
+        PowerMockito.mockStatic(TransactUtils.class);
+        PowerMockito.when(TransactUtils.extractCreatedOrUpdated(any(AsyncDataChangeEvent.class), eq(OvsdbNodeAugmentation.class))).thenReturn(updated);
+
+        ConnectionInfo connectionInfo = mock(ConnectionInfo.class);
+        when(ovsdbNode.getConnectionInfo()).thenReturn(connectionInfo);
+        when(connectionInfo.getRemoteIp()).thenReturn(mock(IpAddress.class));
+        when(connectionInfo.getRemotePort()).thenReturn(mock(PortNumber.class));
+
+        OpenVSwitch ovs = mock(OpenVSwitch.class);
+        when(transaction.getDatabaseSchema()).thenReturn(mock(DatabaseSchema.class));
+        PowerMockito.mockStatic(TyperUtils.class);
+        PowerMockito.when(TyperUtils.getTypedRowWrapper(any(DatabaseSchema.class), eq(OpenVSwitch.class))).thenReturn(ovs);
+
+        List<OpenvswitchExternalIds> externalIds = new ArrayList<>();
+        OpenvswitchExternalIds externalId = mock(OpenvswitchExternalIds.class);
+        externalIds.add(externalId);
+        when(externalId.getExternalIdKey()).thenReturn(EXTERNAL_ID_KEY);
+        when(externalId.getExternalIdValue()).thenReturn(EXTERNAL_ID_VALUE);
+        when(ovsdbNode.getOpenvswitchExternalIds()).thenReturn(externalIds);
+        PowerMockito.suppress(MemberMatcher.method(OvsdbNodeUpdateCommand.class, "stampInstanceIdentifier", TransactionBuilder.class, InstanceIdentifier.class));
+        PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(InstanceIdentifier.class));
+        doNothing().when(ovs).setExternalIds(any(ImmutableMap.class));
+
+        Mutate<GenericTableSchema> mutate = mock(Mutate.class);
+        Operations op = (Operations) setField("op");
+        Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+        when(ovs.getExternalIdsColumn()).thenReturn(column);
+        when(column.getSchema()).thenReturn(mock(ColumnSchema.class));
+        when(column.getData()).thenReturn(new HashMap<String, String>());
+        when(op.mutate(any(OpenVSwitch.class))).thenReturn(mutate);
+        when(transaction.add(any(Operation.class))).thenReturn(transaction);
+
+        List<OpenvswitchOtherConfigs> otherConfigs = new ArrayList<>();
+        OpenvswitchOtherConfigs otherConfig = mock(OpenvswitchOtherConfigs.class);
+        otherConfigs.add(otherConfig);
+        when(ovsdbNode.getOpenvswitchOtherConfigs()).thenReturn(otherConfigs);
+        when(otherConfig.getOtherConfigKey()).thenReturn(OTHER_CONFIG_KEY);
+        when(otherConfig.getOtherConfigValue()).thenReturn(OTHER_CONFIG_VALUE);
+        doNothing().when(ovs).setOtherConfig(any(ImmutableMap.class));
+        when(ovs.getOtherConfigColumn()).thenReturn(column);
+
+        ovsdbNodeUpdateCommand.execute(transaction);
+        verify(externalId).getExternalIdKey();
+        verify(otherConfig).getOtherConfigKey();
+        verify(ovs, times(2)).getExternalIdsColumn();
+        verify(transaction, times(2)).add(any(Operation.class));
+    }
+
+    private Object setField(String fieldName) throws Exception {
+        Field field = Operations.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        field.set(field.get(Operations.class), mock(Operations.class));
+        return field.get(Operations.class);
+    }
+}
diff --git a/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/ProtocolUpdateCommandTest.java b/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/ProtocolUpdateCommandTest.java
new file mode 100644 (file)
index 0000000..776110f
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.ovsdb.lib.notation.Column;
+import org.opendaylight.ovsdb.lib.notation.Condition;
+import org.opendaylight.ovsdb.lib.notation.Mutator;
+import org.opendaylight.ovsdb.lib.operations.Mutate;
+import org.opendaylight.ovsdb.lib.operations.Operation;
+import org.opendaylight.ovsdb.lib.operations.Operations;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.operations.Where;
+import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+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.OvsdbBridgeName;
+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.OvsdbBridgeProtocolOpenflow10;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberMatcher;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import com.google.common.base.Optional;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({InstanceIdentifier.class, ProtocolUpdateCommand.class, TyperUtils.class})
+public class ProtocolUpdateCommandTest {
+    private static final String BRIDGE_NAME_COLUMN = null;
+    private Map<InstanceIdentifier<ProtocolEntry>, ProtocolEntry> protocols = new HashMap<>();
+    private ProtocolUpdateCommand protocolUpdateCommand;
+    @Mock private ProtocolEntry protocolEntry;
+
+    @SuppressWarnings("unchecked")
+    @Before
+    public void setUp() throws Exception {
+        protocolUpdateCommand = PowerMockito.mock(ProtocolUpdateCommand.class, Mockito.CALLS_REAL_METHODS);
+        protocols.put(mock(InstanceIdentifier.class), protocolEntry);
+        MemberModifier.field(ProtocolUpdateCommand.class, "protocols").set(protocolUpdateCommand, protocols);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testProtocolUpdateCommand() {
+        BridgeOperationalState state = mock(BridgeOperationalState.class);
+        AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes = mock(AsyncDataChangeEvent.class);
+        ProtocolUpdateCommand protocolUpdateCommand1 = new ProtocolUpdateCommand(state, changes);
+        assertEquals(state, Whitebox.getInternalState(protocolUpdateCommand1, "operationalState"));
+        assertEquals(changes, Whitebox.getInternalState(protocolUpdateCommand1, "changes"));
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testExecute() throws Exception {
+        TransactionBuilder transaction = mock(TransactionBuilder.class);
+
+        MemberModifier.suppress(MemberMatcher.method(ProtocolUpdateCommand.class, "getOperationalState"));
+        BridgeOperationalState bridgeOpState = mock(BridgeOperationalState.class);
+        when(protocolUpdateCommand.getOperationalState()).thenReturn(bridgeOpState);
+        Optional<ProtocolEntry> operationalProtocolEntryOptional = mock(Optional.class);
+        when(bridgeOpState.getProtocolEntry(any(InstanceIdentifier.class))).thenReturn(operationalProtocolEntryOptional);
+
+        when(operationalProtocolEntryOptional.isPresent()).thenReturn(false);
+        PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(InstanceIdentifier.class));
+
+        Optional<OvsdbBridgeAugmentation> bridgeOptional = mock(Optional.class);
+        when(bridgeOpState.getOvsdbBridgeAugmentation(any(InstanceIdentifier.class))).thenReturn(bridgeOptional);
+        OvsdbBridgeAugmentation ovsdbBridge= mock(OvsdbBridgeAugmentation.class);
+        when(bridgeOptional.isPresent()).thenReturn(true);
+        when(bridgeOptional.get()).thenReturn(ovsdbBridge);
+
+        OvsdbBridgeName ovsdbBridgeName = mock(OvsdbBridgeName.class);
+        when(ovsdbBridge.getBridgeName()).thenReturn(ovsdbBridgeName);
+        when(protocolEntry.getProtocol()).thenAnswer(new Answer<Class<? extends OvsdbBridgeProtocolBase>>() {
+            public Class<? extends OvsdbBridgeProtocolBase> answer(
+                    InvocationOnMock invocation) throws Throwable {
+                return OvsdbBridgeProtocolOpenflow10.class;
+            }
+        });
+
+        Bridge bridge= mock(Bridge.class);
+        PowerMockito.mockStatic(TyperUtils.class);
+        when(transaction.getDatabaseSchema()).thenReturn(mock(DatabaseSchema.class));
+        when(TyperUtils.getTypedRowWrapper(any(DatabaseSchema.class), eq(Bridge.class))).thenReturn(bridge);
+        doNothing().when(bridge).setName(anyString());
+        doNothing().when(bridge).setProtocols(any(Set.class));
+
+        Operations op = (Operations) setField("op");
+        Mutate<GenericTableSchema> mutate = mock(Mutate.class);
+        when(op.mutate(any(Bridge.class))).thenReturn(mutate);
+        Column<GenericTableSchema, Set<String>> column = mock(Column.class);
+        when(bridge.getProtocolsColumn()).thenReturn(column);
+        when(column.getSchema()).thenReturn(mock(ColumnSchema.class));
+        when(column.getData()).thenReturn(new HashSet<String>());
+        when(mutate.addMutation(any(ColumnSchema.class), any(Mutator.class), any(Set.class))).thenReturn(mutate);
+
+        Column<GenericTableSchema, String> nameColumn = mock(Column.class);
+        when(bridge.getNameColumn()).thenReturn(nameColumn);
+        when(nameColumn.getData()).thenReturn(BRIDGE_NAME_COLUMN);
+        ColumnSchema<GenericTableSchema, String> columnSchema = mock(ColumnSchema.class);
+        when(nameColumn.getSchema()).thenReturn(columnSchema);
+        when(columnSchema.opEqual(anyString())).thenReturn(mock(Condition.class));
+        Where where = mock(Where.class);
+        when(mutate.where(any(Condition.class))).thenReturn(where);
+        when(where.build()).thenReturn(mock(Operation.class));
+        when(transaction.add(any(Operation.class))).thenReturn(transaction);
+
+        protocolUpdateCommand.execute(transaction);
+        verify(transaction).add(any(Operation.class));
+    }
+
+    private Object setField(String fieldName) throws Exception {
+        Field field = Operations.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        field.set(field.get(Operations.class), mock(Operations.class));
+        return field.get(Operations.class);
+    }
+}
diff --git a/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TerminationPointDeleteCommandTest.java b/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TerminationPointDeleteCommandTest.java
new file mode 100644 (file)
index 0000000..d1644bd
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+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.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({TransactUtils.class, TerminationPointDeleteCommand.class, TyperUtils.class})
+public class TerminationPointDeleteCommandTest {
+
+    private TerminationPointDeleteCommand terminationPointDeleteCommand;
+    @Mock private BridgeOperationalState state;
+    @Mock private AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes;
+    private Map<InstanceIdentifier<OvsdbTerminationPointAugmentation>, OvsdbTerminationPointAugmentation> originals = new HashMap<>();
+    private Map<InstanceIdentifier<Node>, Node> originalNodes = new HashMap<>();
+    private Set<InstanceIdentifier<OvsdbTerminationPointAugmentation>> removedTps = new HashSet<>();
+
+    @Before
+    public void setUp() throws Exception {
+        terminationPointDeleteCommand = mock(TerminationPointDeleteCommand.class, Mockito.CALLS_REAL_METHODS);
+        MemberModifier.field(TerminationPointDeleteCommand.class, "operationalState").set(terminationPointDeleteCommand, state);
+        MemberModifier.field(TerminationPointDeleteCommand.class, "changes").set(terminationPointDeleteCommand, changes);
+    }
+
+    @Test
+    public void testExecute() {
+        TransactionBuilder transaction = mock(TransactionBuilder.class);
+        PowerMockito.mockStatic(TransactUtils.class);
+        when(TransactUtils.extractOriginal(changes, OvsdbTerminationPointAugmentation.class)).thenReturn(originals);
+        when(TransactUtils.extractOriginal(changes, Node.class)).thenReturn(originalNodes);
+        when(TransactUtils.extractRemoved(changes, OvsdbTerminationPointAugmentation.class)).thenReturn(removedTps);
+        terminationPointDeleteCommand.execute(transaction);
+        verify(terminationPointDeleteCommand, times(3)).getChanges();
+    }
+}
index 038edc3e11fd95a0ee2fd1b3f84da08c4e8b9353..1d09749f6d96643ed91cb38c52347a3b020778b1 100644 (file)
@@ -26,6 +26,7 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Properties;
 import java.util.Set;
@@ -37,6 +38,9 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
@@ -72,6 +76,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.ovsdb.node.attributes.ConnectionInfoBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.DatapathTypeEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.InterfaceTypeEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsBuilder;
@@ -97,6 +102,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
 import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.Option;
@@ -121,11 +127,12 @@ public class SouthboundIT extends AbstractMdsalTestBase {
     private static final String NETDEV_DP_TYPE = "netdev";
     private static final Logger LOG = LoggerFactory.getLogger(SouthboundIT.class);
     private static final int OVSDB_UPDATE_TIMEOUT = 1000;
+    private static final int OVSDB_ROUNDTRIP_TIMEOUT = 10000;
     private static final String FORMAT_STR = "%s_%s_%d";
     private static String addressStr;
     private static int portNumber;
     private static String connectionType;
-    private static Boolean setup = false;
+    private static boolean setup = false;
     private static MdsalUtils mdsalUtils = null;
 
     // TODO Constants copied from AbstractConfigTestBase, need to be removed (see TODO below)
@@ -137,6 +144,56 @@ public class SouthboundIT extends AbstractMdsalTestBase {
     @Inject
     private BundleContext bundleContext;
 
+    private static final NotifyingDataChangeListener CONFIGURATION_LISTENER =
+            new NotifyingDataChangeListener(LogicalDatastoreType.CONFIGURATION);
+    private static final NotifyingDataChangeListener OPERATIONAL_LISTENER =
+            new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL);
+
+    private static class NotifyingDataChangeListener implements DataChangeListener {
+        private final LogicalDatastoreType type;
+        private final Set<InstanceIdentifier<?>> createdIids = new HashSet<>();
+        private final Set<InstanceIdentifier<?>> removedIids = new HashSet<>();
+        private final Set<InstanceIdentifier<?>> updatedIids = new HashSet<>();
+
+        private NotifyingDataChangeListener(LogicalDatastoreType type) {
+            this.type = type;
+        }
+
+        @Override
+        public void onDataChanged(
+                AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent) {
+            LOG.info("{} DataChanged: created {}", type, asyncDataChangeEvent.getCreatedData().keySet());
+            LOG.info("{} DataChanged: removed {}", type, asyncDataChangeEvent.getRemovedPaths());
+            LOG.info("{} DataChanged: updated {}", type, asyncDataChangeEvent.getUpdatedData().keySet());
+            createdIids.addAll(asyncDataChangeEvent.getCreatedData().keySet());
+            removedIids.addAll(asyncDataChangeEvent.getRemovedPaths());
+            updatedIids.addAll(asyncDataChangeEvent.getUpdatedData().keySet());
+            // Handled managed iids
+            for (DataObject obj : asyncDataChangeEvent.getCreatedData().values()) {
+                if (obj instanceof ManagedNodeEntry) {
+                    ManagedNodeEntry managedNodeEntry = (ManagedNodeEntry) obj;
+                    LOG.info("{} DataChanged: created managed {}", managedNodeEntry.getBridgeRef().getValue());
+                    createdIids.add(managedNodeEntry.getBridgeRef().getValue());
+                }
+            }
+            synchronized(this) {
+                notifyAll();
+            }
+        }
+
+        public boolean isCreated(InstanceIdentifier<?> iid) {
+            return createdIids.remove(iid);
+        }
+
+        public boolean isRemoved(InstanceIdentifier<?> iid) {
+            return removedIids.remove(iid);
+        }
+
+        public boolean isUpdated(InstanceIdentifier<?> iid) {
+            return updatedIids.remove(iid);
+        }
+    }
+
     @Configuration
     public Option[] config() {
         // TODO Figure out how to use the parent Karaf setup, then just use super.config()
@@ -274,6 +331,13 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         }
 
         mdsalUtils = new MdsalUtils(dataBroker);
+        dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                createInstanceIdentifier(getConnectionInfo(addressStr, portNumber)), CONFIGURATION_LISTENER,
+                AsyncDataBroker.DataChangeScope.SUBTREE);
+        dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                createInstanceIdentifier(getConnectionInfo(addressStr, portNumber)), OPERATIONAL_LISTENER,
+                AsyncDataBroker.DataChangeScope.SUBTREE);
+
         setup = true;
     }
 
@@ -343,14 +407,6 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                 topology);
     }
 
-    private boolean addOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
-        boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION,
-                createInstanceIdentifier(connectionInfo),
-                createNode(connectionInfo));
-        Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-        return result;
-    }
-
     private InstanceIdentifier<Node> createInstanceIdentifier(
             ConnectionInfo connectionInfo) {
         return InstanceIdentifier
@@ -360,40 +416,66 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                         createNodeKey(connectionInfo.getRemoteIp(), connectionInfo.getRemotePort()));
     }
 
-    private Node getOvsdbNode(final ConnectionInfo connectionInfo) {
-        return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
-                createInstanceIdentifier(connectionInfo));
-    }
-
-    private boolean deleteOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
-        boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
-                createInstanceIdentifier(connectionInfo));
-        Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-        return result;
-    }
-
     private Node connectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
-        Assert.assertTrue(addOvsdbNode(connectionInfo));
-        Node node = getOvsdbNode(connectionInfo);
+        final InstanceIdentifier<Node> iid = createInstanceIdentifier(connectionInfo);
+        Assert.assertTrue(mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, iid, createNode(connectionInfo)));
+        waitForOperationalCreation(iid);
+        Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, iid);
         Assert.assertNotNull(node);
         LOG.info("Connected to {}", connectionInfoToString(connectionInfo));
         return node;
     }
 
-    private boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
-        Assert.assertTrue(deleteOvsdbNode(connectionInfo));
-        Node node = getOvsdbNode(connectionInfo);
+    private void waitForOperationalCreation(InstanceIdentifier<Node> iid) throws InterruptedException {
+        synchronized (OPERATIONAL_LISTENER) {
+            long _start = System.currentTimeMillis();
+            LOG.info("Waiting for OPERATIONAL DataChanged creation on {}", iid);
+            while (!OPERATIONAL_LISTENER.isCreated(
+                    iid) && (System.currentTimeMillis() - _start) < OVSDB_ROUNDTRIP_TIMEOUT) {
+                OPERATIONAL_LISTENER.wait(OVSDB_UPDATE_TIMEOUT);
+            }
+            LOG.info("Woke up, waited {} for creation of {}", (System.currentTimeMillis() - _start), iid);
+        }
+    }
+
+    private void waitForOperationalDeletion(InstanceIdentifier<Node> iid) throws InterruptedException {
+        synchronized (OPERATIONAL_LISTENER) {
+            long _start = System.currentTimeMillis();
+            LOG.info("Waiting for OPERATIONAL DataChanged deletion on {}", iid);
+            while (!OPERATIONAL_LISTENER.isRemoved(
+                    iid) && (System.currentTimeMillis() - _start) < OVSDB_ROUNDTRIP_TIMEOUT) {
+                OPERATIONAL_LISTENER.wait(OVSDB_UPDATE_TIMEOUT);
+            }
+            LOG.info("Woke up, waited {} for deletion of {}", (System.currentTimeMillis() - _start), iid);
+        }
+    }
+
+    private void waitForOperationalUpdate(InstanceIdentifier<Node> iid) throws InterruptedException {
+        synchronized (OPERATIONAL_LISTENER) {
+            long _start = System.currentTimeMillis();
+            LOG.info("Waiting for OPERATIONAL DataChanged update on {}", iid);
+            while (!OPERATIONAL_LISTENER.isUpdated(
+                    iid) && (System.currentTimeMillis() - _start) < OVSDB_ROUNDTRIP_TIMEOUT) {
+                OPERATIONAL_LISTENER.wait(OVSDB_UPDATE_TIMEOUT);
+            }
+            LOG.info("Woke up, waited {} for update of {}", (System.currentTimeMillis() - _start), iid);
+        }
+    }
+
+    private void disconnectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
+        final InstanceIdentifier<Node> iid = createInstanceIdentifier(connectionInfo);
+        Assert.assertTrue(mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, iid));
+        waitForOperationalDeletion(iid);
+        Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, iid);
         Assert.assertNull(node);
-        //Assume.assumeNotNull(node); // Using assumeNotNull because there is no assumeNull
         LOG.info("Disconnected from {}", connectionInfoToString(connectionInfo));
-        return true;
     }
 
     @Test
     public void testAddDeleteOvsdbNode() throws InterruptedException {
         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
         connectOvsdbNode(connectionInfo);
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     @Test
@@ -422,37 +504,51 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                     Assert.assertNotNull(bridge);
                     Assert.assertEquals(dpType, bridge.getDatapathType());
 
-                    // Add dpdk port
-                    final String TEST_PORT_NAME = "testDPDKPort";
-                    OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
-                            createGenericDpdkOvsdbTerminationPointAugmentationBuilder(TEST_PORT_NAME);
-                    Assert.assertTrue(addTerminationPoint(bridgeNodeId, TEST_PORT_NAME, ovsdbTerminationBuilder));
+                    // Add port for all dpdk interface types (dpdkvhost not supported in existing dpdk ovs)
+                    List<String> dpdkTypes = new ArrayList<String>();
+                    dpdkTypes.add("dpdk");
+                    dpdkTypes.add("dpdkr");
+                    dpdkTypes.add("dpdkvhostuser");
+                    //dpdkTypes.add("dpdkvhost");
+
+                    for (String dpdkType : dpdkTypes) {
+                        String testPortname = "test"+dpdkType+"port";
+                        LOG.info("DPDK portname and type is {}, {}", testPortname, dpdkType);
+                        Class<? extends InterfaceTypeBase> dpdkIfType = SouthboundConstants.OVSDB_INTERFACE_TYPE_MAP
+                                .get( dpdkType);
+                        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationpointBuilder =
+                                createSpecificDpdkOvsdbTerminationPointAugmentationBuilder(testPortname, dpdkIfType);
+                        Assert.assertTrue(addTerminationPoint(bridgeNodeId, testPortname , ovsdbTerminationpointBuilder));
+                    }
 
-                    // Verify that DPDK port was created
+                    // Verify that all DPDK ports are created
                     InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
                     Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
                             terminationPointIid);
                     Assert.assertNotNull(terminationPointNode);
 
-                    // Verify that each termination point has DPDK ifType
-                    Class<? extends InterfaceTypeBase> dpdkIfType = SouthboundConstants.OVSDB_INTERFACE_TYPE_MAP
-                            .get("dpdk");
-                    List<TerminationPoint> terminationPoints = terminationPointNode.getTerminationPoint();
-                    for (TerminationPoint terminationPoint : terminationPoints) {
-                        OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation = terminationPoint
-                                .getAugmentation(OvsdbTerminationPointAugmentation.class);
-                        if (ovsdbTerminationPointAugmentation.getName().equals(TEST_PORT_NAME)) {
-                            Class<? extends InterfaceTypeBase> opPort = ovsdbTerminationPointAugmentation
-                                    .getInterfaceType();
-                            Assert.assertEquals(dpdkIfType, opPort);
+                    // Verify that each termination point has the specific DPDK ifType
+                    for (String dpdkType : dpdkTypes) {
+                        String testPortname = "test"+dpdkType+"port";
+                        Class<? extends InterfaceTypeBase> dpdkIfType = SouthboundConstants.OVSDB_INTERFACE_TYPE_MAP
+                                .get(dpdkType);
+                        List<TerminationPoint> terminationPoints = terminationPointNode.getTerminationPoint();
+                        for (TerminationPoint terminationPoint : terminationPoints) {
+                            OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation = terminationPoint
+                                    .getAugmentation(OvsdbTerminationPointAugmentation.class);
+                            if (ovsdbTerminationPointAugmentation.getName().equals(testPortname)) {
+                                Class<? extends InterfaceTypeBase> opPort = ovsdbTerminationPointAugmentation
+                                        .getInterfaceType();
+                                Assert.assertEquals(dpdkIfType, opPort);
+                            }
                         }
                     }
-                    Assert.assertTrue(deleteBridge(connectionInfo));
-                    break;
                 }
+                Assert.assertTrue(deleteBridge(connectionInfo));
+                break;
             }
         }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     @Test
@@ -462,7 +558,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
         Assert.assertNotNull(ovsdbNodeAugmentation);
         assertNotNull(ovsdbNodeAugmentation.getOvsVersion());
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     @Test
@@ -484,7 +580,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         } else {
             LOG.info("other_config is not present");
         }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     @Test
@@ -510,7 +606,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         }
 
         Assert.assertTrue(deleteBridge(connectionInfo));
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     private List<ControllerEntry> createControllerEntry(String controllerTarget) {
@@ -557,6 +653,15 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         return ovsdbTerminationBuilder;
     }
 
+    private OvsdbTerminationPointAugmentationBuilder createSpecificDpdkOvsdbTerminationPointAugmentationBuilder(
+            String testPortname,Class<? extends InterfaceTypeBase> dpdkIfType) {
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
+                createGenericOvsdbTerminationPointAugmentationBuilder();
+        ovsdbTerminationBuilder.setName(testPortname);
+        ovsdbTerminationBuilder.setInterfaceType(dpdkIfType);
+        return ovsdbTerminationBuilder;
+    }
+
     private boolean addTerminationPoint(final NodeId bridgeNodeId, final String portName,
                                         final OvsdbTerminationPointAugmentationBuilder
                                                 ovsdbTerminationPointAugmentationBuilder)
@@ -634,8 +739,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
             ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(otherConfigs);
         }
         bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
-        LOG.debug("Built with the intent to store bridge data {}",
-                ovsdbBridgeAugmentationBuilder.toString());
+        LOG.debug("Built with the intent to store bridge data {}", ovsdbBridgeAugmentationBuilder.toString());
         boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
                 bridgeIid, bridgeNodeBuilder.build());
         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
@@ -719,9 +823,9 @@ public class SouthboundIT extends AbstractMdsalTestBase {
     private boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName)
             throws InterruptedException {
 
-        boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
-                createInstanceIdentifier(connectionInfo,
-                        new OvsdbBridgeName(bridgeName)));
+        final InstanceIdentifier<Node> iid = createInstanceIdentifier(connectionInfo,
+                new OvsdbBridgeName(bridgeName));
+        boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, iid);
         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
         return result;
     }
@@ -738,7 +842,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
 
         Assert.assertTrue(deleteBridge(connectionInfo));
 
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     private InstanceIdentifier<Node> getTpIid(ConnectionInfo connectionInfo, OvsdbBridgeAugmentation bridge) {
@@ -810,7 +914,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
 
         // DELETE
         Assert.assertTrue(deleteBridge(connectionInfo));
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     @Test
@@ -862,32 +966,30 @@ public class SouthboundIT extends AbstractMdsalTestBase {
 
         // DELETE
         Assert.assertTrue(deleteBridge(connectionInfo));
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
-    /*
-     * @see <code>SouthboundIT.testCRUDPortExternalIds()</code>
-     * This is helper test method to compare a test "set" of BridgeExternalIds against an expected "set"
-     */
-    private void assertExpectedPortExternalIdsExist( List<PortExternalIds> expected,
-                                                     List<PortExternalIds> test ) {
-
-        if (expected != null) {
-            for (PortExternalIds expectedExternalId : expected) {
-                Assert.assertTrue("The retrieved ids don't contain " + expectedExternalId,
-                        test.contains(expectedExternalId));
+    private <T> void assertExpectedExist(List<T> expected, List<T> test) {
+        if (expected != null && test != null) {
+            for (T exp : expected) {
+                Assert.assertTrue("The retrieved values don't contain " + exp, test.contains(exp));
             }
         }
     }
 
+    private interface SouthboundTerminationPointHelper<T> {
+        void writeValues(OvsdbTerminationPointAugmentationBuilder builder, List<T> values);
+        List<T> readValues(OvsdbTerminationPointAugmentation augmentation);
+    }
+
     /*
      * Tests the CRUD operations for <code>Port</code> <code>external_ids</code>.
      *
      * @see <code>SouthboundIT.generatePortExternalIdsTestCases()</code> for specific test case information
      */
-    @Test
-    public void testCRUDTerminationPointPortExternalIds() throws InterruptedException {
-        final String TEST_PREFIX = "CRUDTPPortExternalIds";
+    private <T> void testCRUDTerminationPoint(
+            KeyValueBuilder<T> builder, String prefix, SouthboundTerminationPointHelper<T> helper)
+            throws InterruptedException {
         final int TERMINATION_POINT_TEST_INDEX = 0;
 
         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
@@ -895,18 +997,12 @@ public class SouthboundIT extends AbstractMdsalTestBase {
 
         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
         // the update has been performed.
-        List<SouthboundTestCase<PortExternalIds>> updateFromTestCases =
-                generateKeyValueTestCases(new SouthboundPortExternalIdsBuilder(), "PortExternalIdsFrom");
-        List<SouthboundTestCase<PortExternalIds>> updateToTestCases =
-                generateKeyValueTestCases(new SouthboundPortExternalIdsBuilder(), "PortExternalIdsTo");
-
-        for (SouthboundTestCase<PortExternalIds> updateFromTestCase : updateFromTestCases) {
-            List<PortExternalIds> updateFromInputExternalIds = updateFromTestCase.inputValues;
-            List<PortExternalIds> updateFromExpectedExternalIds = updateFromTestCase.expectedValues;
-            for (SouthboundTestCase<PortExternalIds> updateToTestCase : updateToTestCases) {
-                String testBridgeAndPortName = String.format("%s_%s", TEST_PREFIX, updateToTestCase.name);
-                List<PortExternalIds> updateToInputExternalIds = updateToTestCase.inputValues;
-                List<PortExternalIds> updateToExpectedExternalIds = updateToTestCase.expectedValues;
+        List<SouthboundTestCase<T>> updateFromTestCases = generateKeyValueTestCases(builder, prefix + "From");
+        List<SouthboundTestCase<T>> updateToTestCases = generateKeyValueTestCases(builder, prefix + "To");
+
+        for (SouthboundTestCase<T> updateFromTestCase : updateFromTestCases) {
+            for (SouthboundTestCase<T> updateToTestCase : updateToTestCases) {
+                String testBridgeAndPortName = String.format("%s_%s", prefix, updateToTestCase.name);
 
                 // CREATE: Create the test bridge
                 Assert.assertTrue(addBridge(connectionInfo, null, testBridgeAndPortName, null, true,
@@ -916,7 +1012,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                 OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
                         createGenericOvsdbTerminationPointAugmentationBuilder();
                 tpCreateAugmentationBuilder.setName(testBridgeAndPortName);
-                tpCreateAugmentationBuilder.setPortExternalIds(updateFromInputExternalIds);
+                helper.writeValues(tpCreateAugmentationBuilder, updateFromTestCase.inputValues);
                 Assert.assertTrue(
                         addTerminationPoint(testBridgeNodeId, testBridgeAndPortName, tpCreateAugmentationBuilder));
 
@@ -926,25 +1022,24 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                         getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
                                 LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
                 if (updateFromConfigurationTerminationPointAugmentation != null) {
-                    List<PortExternalIds> updateFromConfigurationExternalIds =
-                            updateFromConfigurationTerminationPointAugmentation.getPortExternalIds();
-                    assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds,
-                            updateFromConfigurationExternalIds);
+                    List<T> updateFromConfigurationValues =
+                            helper.readValues(updateFromConfigurationTerminationPointAugmentation);
+                    assertExpectedExist(updateFromTestCase.expectedValues, updateFromConfigurationValues);
                 }
                 OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmentation =
                         getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
                                 LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
                 if (updateFromOperationalTerminationPointAugmentation != null) {
-                    List<PortExternalIds> updateFromOperationalExternalIds =
-                            updateFromOperationalTerminationPointAugmentation.getPortExternalIds();
-                    assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds, updateFromOperationalExternalIds);
+                    List<T> updateFromOperationalValues =
+                            helper.readValues(updateFromOperationalTerminationPointAugmentation);
+                    assertExpectedExist(updateFromTestCase.expectedValues, updateFromOperationalValues);
                 }
 
-                // UPDATE:  update the external_ids
+                // UPDATE:  update the values
                 testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeAndPortName).getNodeId();
                 OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
                         new OvsdbTerminationPointAugmentationBuilder();
-                tpUpdateAugmentationBuilder.setPortExternalIds(updateToInputExternalIds);
+                helper.writeValues(tpUpdateAugmentationBuilder, updateToTestCase.inputValues);
                 InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
                 NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
                 NodeId portUpdateNodeId = createManagedNodeId(portIid);
@@ -965,45 +1060,39 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                         getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
                                 LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
                 if (updateToConfigurationTerminationPointAugmentation != null) {
-                    List<PortExternalIds> updateToConfigurationExternalIds =
-                            updateToConfigurationTerminationPointAugmentation.getPortExternalIds();
-                    assertExpectedPortExternalIdsExist(updateToExpectedExternalIds, updateToConfigurationExternalIds);
-                    assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds, updateToConfigurationExternalIds);
+                    List<T> updateToConfigurationValues =
+                            helper.readValues(updateToConfigurationTerminationPointAugmentation);
+                    assertExpectedExist(updateToTestCase.expectedValues, updateToConfigurationValues);
+                    assertExpectedExist(updateFromTestCase.expectedValues, updateToConfigurationValues);
                 }
                 OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
                         getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
                                 LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
                 if (updateToOperationalTerminationPointAugmentation != null) {
-                    List<PortExternalIds> updateToOperationalExternalIds =
-                            updateToOperationalTerminationPointAugmentation.getPortExternalIds();
-                    if (updateFromExpectedExternalIds != null ) {
-                        assertExpectedPortExternalIdsExist(updateToExpectedExternalIds, updateToOperationalExternalIds);
-                        assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds,
-                                updateToOperationalExternalIds);
+                    List<T> updateToOperationalValues =
+                            helper.readValues(updateToOperationalTerminationPointAugmentation);
+                    if (updateFromTestCase.expectedValues != null ) {
+                        assertExpectedExist(updateToTestCase.expectedValues, updateToOperationalValues);
+                        assertExpectedExist(updateFromTestCase.expectedValues, updateToOperationalValues);
                     }
-                    // testCRUDTerminationPointInterfaceExternalIds()'s null assertion of updateToOperationalExternalIds
-                    // fails here
                 }
 
                 // DELETE
                 Assert.assertTrue(deleteBridge(connectionInfo, testBridgeAndPortName));
             }
         }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     /*
-     * @see <code>SouthboundIT.testCRUDInterfaceExternalIds()</code>
-     * This is helper test method to compare a test "set" of InterfaceExternalIds against an expected "set"
+     * Tests the CRUD operations for <code>Port</code> <code>external_ids</code>.
+     *
+     * @see <code>SouthboundIT.generatePortExternalIdsTestCases()</code> for specific test case information
      */
-    private void assertExpectedInterfaceExternalIdsExist( List<InterfaceExternalIds> expected,
-                                                          List<InterfaceExternalIds> test ) {
-
-        if (expected != null) {
-            for (InterfaceExternalIds expectedExternalId : expected) {
-                Assert.assertTrue(test.contains(expectedExternalId));
-            }
-        }
+    @Test
+    public void testCRUDTerminationPointPortExternalIds() throws InterruptedException {
+        testCRUDTerminationPoint(new SouthboundPortExternalIdsBuilder(), "TPPortExternalIds",
+                new PortExternalIdsSouthboundHelper());
     }
 
     /*
@@ -1013,127 +1102,8 @@ public class SouthboundIT extends AbstractMdsalTestBase {
      */
     @Test
     public void testCRUDTerminationPointInterfaceExternalIds() throws InterruptedException {
-        final String TEST_PREFIX = "CRUDTPInterfaceExternalIds";
-        final int TERMINATION_POINT_TEST_INDEX = 0;
-
-        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
-        connectOvsdbNode(connectionInfo);
-
-        // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
-        // the update has been performed.
-        List<SouthboundTestCase<InterfaceExternalIds>> updateFromTestCases = generateKeyValueTestCases(
-                new SouthboundInterfaceExternalIdsBuilder(), "InterfaceExternalIdsFrom");
-        List<SouthboundTestCase<InterfaceExternalIds>> updateToTestCases = generateKeyValueTestCases(
-                new SouthboundInterfaceExternalIdsBuilder(), "InterfaceExternalIdsTo");
-
-        for (SouthboundTestCase<InterfaceExternalIds> updateFromTestCase : updateFromTestCases) {
-            List<InterfaceExternalIds> updateFromInputExternalIds = updateFromTestCase.inputValues;
-            List<InterfaceExternalIds> updateFromExpectedExternalIds = updateFromTestCase.expectedValues;
-            for (SouthboundTestCase<InterfaceExternalIds> updateToTestCase : updateToTestCases) {
-                String testBridgeAndPortName = String.format("%s_%s", TEST_PREFIX, updateToTestCase.name);
-                List<InterfaceExternalIds> updateToInputExternalIds = updateToTestCase.inputValues;
-                List<InterfaceExternalIds> updateToExpectedExternalIds = updateToTestCase.expectedValues;
-
-                // CREATE: Create the test interface
-                Assert.assertTrue(addBridge(connectionInfo, null, testBridgeAndPortName, null, true,
-                        SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null, null, null));
-                NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
-                        connectionInfo, new OvsdbBridgeName(testBridgeAndPortName)));
-                OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
-                        createGenericOvsdbTerminationPointAugmentationBuilder();
-                tpCreateAugmentationBuilder.setName(testBridgeAndPortName);
-                tpCreateAugmentationBuilder.setInterfaceExternalIds(updateFromInputExternalIds);
-                Assert.assertTrue(
-                        addTerminationPoint(testBridgeNodeId, testBridgeAndPortName, tpCreateAugmentationBuilder));
-
-                // READ: Read the test interface and ensure changes are propagated to the CONFIGURATION data store,
-                // then repeat for OPERATIONAL data store
-                OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-                if (updateFromConfigurationTerminationPointAugmentation != null) {
-                    List<InterfaceExternalIds> updateFromConfigurationExternalIds =
-                            updateFromConfigurationTerminationPointAugmentation.getInterfaceExternalIds();
-                    assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
-                            updateFromConfigurationExternalIds);
-                }
-                OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-                if (updateFromOperationalTerminationPointAugmentation != null) {
-                    List<InterfaceExternalIds> updateFromOperationalExternalIds =
-                            updateFromOperationalTerminationPointAugmentation.getInterfaceExternalIds();
-                    assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
-                            updateFromOperationalExternalIds);
-                }
-
-                // UPDATE:  update the external_ids
-                testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeAndPortName).getNodeId();
-                OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
-                        new OvsdbTerminationPointAugmentationBuilder();
-                tpUpdateAugmentationBuilder.setInterfaceExternalIds(updateToInputExternalIds);
-                InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
-                NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
-                NodeId portUpdateNodeId = createManagedNodeId(portIid);
-                portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
-                TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
-                tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testBridgeAndPortName)));
-                tpUpdateBuilder.addAugmentation(
-                        OvsdbTerminationPointAugmentation.class,
-                        tpUpdateAugmentationBuilder.build());
-                portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-                Assert.assertTrue(mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                        portIid, portUpdateNodeBuilder.build()));
-                Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-
-                // READ: the test interface and ensure changes are propagated to the CONFIGURATION data store,
-                // then repeat for OPERATIONAL data store
-                OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-                if (updateToConfigurationTerminationPointAugmentation != null) {
-                    List<InterfaceExternalIds> updateToConfigurationExternalIds =
-                            updateToConfigurationTerminationPointAugmentation.getInterfaceExternalIds();
-                    assertExpectedInterfaceExternalIdsExist(updateToExpectedExternalIds,
-                            updateToConfigurationExternalIds);
-                    assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
-                            updateToConfigurationExternalIds);
-                }
-                OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-                if (updateToOperationalTerminationPointAugmentation != null) {
-                    List<InterfaceExternalIds> updateToOperationalExternalIds =
-                            updateToOperationalTerminationPointAugmentation.getInterfaceExternalIds();
-                    if (updateFromExpectedExternalIds != null) {
-                        assertExpectedInterfaceExternalIdsExist(updateToExpectedExternalIds,
-                                updateToOperationalExternalIds);
-                        assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
-                                updateToOperationalExternalIds);
-                    } else {
-                        Assert.assertNull(updateToOperationalExternalIds);
-                    }
-                }
-
-                // DELETE
-                Assert.assertTrue(deleteBridge(connectionInfo, testBridgeAndPortName));
-            }
-        }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
-    }
-
-    /*
-     * @see <code>SouthboundIT.testCRUDTerminationPointOptions()</code>
-     * This is helper test method to compare a test "set" of Options against an expected "set"
-     */
-    private void assertExpectedOptionsExist( List<Options> expected,
-                                             List<Options> test ) {
-
-        if (expected != null) {
-            for (Options expectedOption : expected) {
-                Assert.assertTrue(test.contains(expectedOption));
-            }
-        }
+        testCRUDTerminationPoint(new SouthboundInterfaceExternalIdsBuilder(), "TPInterfaceExternalIds",
+                new InterfaceExternalIdsSouthboundHelper());
     }
 
     /*
@@ -1143,119 +1113,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
      */
     @Test
     public void testCRUDTerminationPointOptions() throws InterruptedException {
-        final String TEST_PREFIX = "CRUDTPOptions";
-        final int TERMINATION_POINT_TEST_INDEX = 0;
-
-        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
-        connectOvsdbNode(connectionInfo);
-
-        // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
-        // the update has been performed.
-        List<SouthboundTestCase<Options>> updateFromTestCases =
-                generateKeyValueTestCases(new SouthboundOptionsBuilder(), "OptionsFrom");
-        List<SouthboundTestCase<Options>> updateToTestCases = generateKeyValueTestCases(new SouthboundOptionsBuilder(),
-                "OptionsTo");
-
-        for (SouthboundTestCase<Options> updateFromTestCase : updateFromTestCases) {
-            List<Options> updateFromInputOptions = updateFromTestCase.inputValues;
-            List<Options> updateFromExpectedOptions = updateFromTestCase.expectedValues;
-            for (SouthboundTestCase<Options> updateToTestCase : updateToTestCases) {
-                String testBridgeAndPortName = String.format("%s_%s", TEST_PREFIX, updateToTestCase.name);
-                List<Options> updateToInputOptions = updateToTestCase.inputValues;
-                List<Options> updateToExpectedOptions = updateToTestCase.expectedValues;
-
-                // CREATE: Create the test interface
-                Assert.assertTrue(addBridge(connectionInfo, null, testBridgeAndPortName, null, true,
-                        SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null, null, null));
-                NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
-                        connectionInfo, new OvsdbBridgeName(testBridgeAndPortName)));
-                OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
-                        createGenericOvsdbTerminationPointAugmentationBuilder();
-                tpCreateAugmentationBuilder.setName(testBridgeAndPortName);
-                tpCreateAugmentationBuilder.setOptions(updateFromInputOptions);
-                Assert.assertTrue(
-                        addTerminationPoint(testBridgeNodeId, testBridgeAndPortName, tpCreateAugmentationBuilder));
-
-                // READ: Read the test interface and ensure changes are propagated to the CONFIGURATION data store,
-                // then repeat for OPERATIONAL data store
-                OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-                if (updateFromConfigurationTerminationPointAugmentation != null) {
-                    List<Options> updateFromConfigurationOptions =
-                            updateFromConfigurationTerminationPointAugmentation.getOptions();
-                    assertExpectedOptionsExist(updateFromExpectedOptions, updateFromConfigurationOptions);
-                }
-                OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-                if (updateFromOperationalTerminationPointAugmentation != null) {
-                    List<Options> updateFromOperationalOptions =
-                            updateFromOperationalTerminationPointAugmentation.getOptions();
-                    assertExpectedOptionsExist(updateFromExpectedOptions, updateFromOperationalOptions);
-                }
-
-                // UPDATE:  update the external_ids
-                testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeAndPortName).getNodeId();
-                OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
-                        new OvsdbTerminationPointAugmentationBuilder();
-                tpUpdateAugmentationBuilder.setOptions(updateToInputOptions);
-                InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
-                NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
-                NodeId portUpdateNodeId = createManagedNodeId(portIid);
-                portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
-                TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
-                tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testBridgeAndPortName)));
-                tpUpdateBuilder.addAugmentation(
-                        OvsdbTerminationPointAugmentation.class,
-                        tpUpdateAugmentationBuilder.build());
-                portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-                Assert.assertTrue(mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                        portIid, portUpdateNodeBuilder.build()));
-                Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-
-                // READ: the test interface and ensure changes are propagated to the CONFIGURATION data store,
-                // then repeat for OPERATIONAL data store
-                OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-                if (updateToConfigurationTerminationPointAugmentation != null) {
-                    List<Options> updateToConfigurationOptions =
-                            updateToConfigurationTerminationPointAugmentation.getOptions();
-                    assertExpectedOptionsExist(updateToExpectedOptions, updateToConfigurationOptions);
-                    assertExpectedOptionsExist(updateFromExpectedOptions, updateToConfigurationOptions);
-                }
-                OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-                if (updateToOperationalTerminationPointAugmentation != null) {
-                    List<Options> updateToOperationalOptions =
-                            updateToOperationalTerminationPointAugmentation.getOptions();
-                    if (updateFromExpectedOptions != null) {
-                        assertExpectedOptionsExist(updateToExpectedOptions, updateToOperationalOptions);
-                        assertExpectedOptionsExist(updateFromExpectedOptions, updateToOperationalOptions);
-                    }
-                }
-
-                // DELETE
-                Assert.assertTrue(deleteBridge(connectionInfo, testBridgeAndPortName));
-            }
-        }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
-    }
-
-    /*
-     * @see <code>SouthboundIT.testCRUDInterfaceOtherConfigs()</code>
-     * This is helper test method to compare a test "set" of Options against an expected "set"
-     */
-    private void assertExpectedInterfaceOtherConfigsExist( List<InterfaceOtherConfigs> expected,
-                                                           List<InterfaceOtherConfigs> test ) {
-
-        if (expected != null && test != null) {
-            for (InterfaceOtherConfigs expectedOtherConfigs : expected) {
-                Assert.assertTrue(test.contains(expectedOtherConfigs));
-            }
-        }
+        testCRUDTerminationPoint(new SouthboundOptionsBuilder(), "TPOptions", new OptionsSouthboundHelper());
     }
 
     /*
@@ -1265,125 +1123,8 @@ public class SouthboundIT extends AbstractMdsalTestBase {
      */
     @Test
     public void testCRUDTerminationPointInterfaceOtherConfigs() throws InterruptedException {
-        final String TEST_PREFIX = "CRUDTPInterfaceOtherConfigs";
-        final int TERMINATION_POINT_TEST_INDEX = 0;
-
-        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
-        connectOvsdbNode(connectionInfo);
-
-        // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
-        // the update has been performed.
-        List<SouthboundTestCase<InterfaceOtherConfigs>> updateFromTestCases =
-                generateKeyValueTestCases(new SouthboundInterfaceOtherConfigsBuilder(), "InterfaceOtherConfigsFrom");
-        List<SouthboundTestCase<InterfaceOtherConfigs>> updateToTestCases =
-                generateKeyValueTestCases(new SouthboundInterfaceOtherConfigsBuilder(), "InterfaceOtherConfigsTo");
-
-        for (SouthboundTestCase<InterfaceOtherConfigs> updateFromTestCase : updateFromTestCases) {
-            List<InterfaceOtherConfigs> updateFromInputOtherConfigs = updateFromTestCase.inputValues;
-            List<InterfaceOtherConfigs> updateFromExpectedOtherConfigs = updateFromTestCase.expectedValues;
-            for (SouthboundTestCase<InterfaceOtherConfigs> updateToTestCase : updateToTestCases) {
-                String testBridgeAndPortName = String.format("%s_%s", TEST_PREFIX, updateToTestCase.name);
-                List<InterfaceOtherConfigs> updateToInputOtherConfigs = updateToTestCase.inputValues;
-                List<InterfaceOtherConfigs> updateToExpectedOtherConfigs = updateToTestCase.expectedValues;
-
-                // CREATE: Create the test interface
-                Assert.assertTrue(addBridge(connectionInfo, null, testBridgeAndPortName, null, true,
-                        SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null, null, null));
-                NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
-                        connectionInfo, new OvsdbBridgeName(testBridgeAndPortName)));
-                OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
-                        createGenericOvsdbTerminationPointAugmentationBuilder();
-                tpCreateAugmentationBuilder.setName(testBridgeAndPortName);
-                tpCreateAugmentationBuilder.setInterfaceOtherConfigs(updateFromInputOtherConfigs);
-                Assert.assertTrue(
-                        addTerminationPoint(testBridgeNodeId, testBridgeAndPortName, tpCreateAugmentationBuilder));
-
-                // READ: Read the test interface and ensure changes are propagated to the CONFIGURATION data store,
-                // then repeat for OPERATIONAL data store
-                OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-                if (updateFromConfigurationTerminationPointAugmentation != null) {
-                    List<InterfaceOtherConfigs> updateFromConfigurationOtherConfigs =
-                            updateFromConfigurationTerminationPointAugmentation.getInterfaceOtherConfigs();
-                    assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
-                            updateFromConfigurationOtherConfigs);
-                }
-                OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-                if (updateFromOperationalTerminationPointAugmentation != null) {
-                    List<InterfaceOtherConfigs> updateFromOperationalOtherConfigs =
-                            updateFromOperationalTerminationPointAugmentation.getInterfaceOtherConfigs();
-                    assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
-                            updateFromOperationalOtherConfigs);
-                }
-
-                // UPDATE:  update the other_configs
-                testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeAndPortName).getNodeId();
-                OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
-                        new OvsdbTerminationPointAugmentationBuilder();
-                tpUpdateAugmentationBuilder.setInterfaceOtherConfigs(updateToInputOtherConfigs);
-                InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
-                NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
-                NodeId portUpdateNodeId = createManagedNodeId(portIid);
-                portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
-                TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
-                tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testBridgeAndPortName)));
-                tpUpdateBuilder.addAugmentation(
-                        OvsdbTerminationPointAugmentation.class,
-                        tpUpdateAugmentationBuilder.build());
-                portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-                Assert.assertTrue(mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                        portIid, portUpdateNodeBuilder.build()));
-                Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-
-                // READ: the test interface and ensure changes are propagated to the CONFIGURATION data store,
-                // then repeat for OPERATIONAL data store
-                OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-                if (updateToConfigurationTerminationPointAugmentation != null) {
-                    List<InterfaceOtherConfigs> updateToConfigurationOtherConfigs =
-                            updateToConfigurationTerminationPointAugmentation.getInterfaceOtherConfigs();
-                    assertExpectedInterfaceOtherConfigsExist(updateToExpectedOtherConfigs,
-                            updateToConfigurationOtherConfigs);
-                    assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
-                            updateToConfigurationOtherConfigs);
-                }
-                OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-                if (updateToOperationalTerminationPointAugmentation != null) {
-                    List<InterfaceOtherConfigs> updateToOperationalOtherConfigs =
-                            updateToOperationalTerminationPointAugmentation.getInterfaceOtherConfigs();
-                    if (updateFromExpectedOtherConfigs != null) {
-                        assertExpectedInterfaceOtherConfigsExist(updateToExpectedOtherConfigs,
-                                updateToOperationalOtherConfigs);
-                        assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
-                                updateToOperationalOtherConfigs);
-                    }
-                }
-
-                // DELETE
-                Assert.assertTrue(deleteBridge(connectionInfo, testBridgeAndPortName));
-            }
-        }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
-    }
-
-    /*
-     * @see <code>SouthboundIT.testCRUDPortOtherConfigs()</code>
-     * This is helper test method to compare a test "set" of Options against an expected "set"
-     */
-    private void assertExpectedPortOtherConfigsExist( List<PortOtherConfigs> expected,
-                                                      List<PortOtherConfigs> test ) {
-
-        if (expected != null && test != null) {
-            for (PortOtherConfigs expectedOtherConfigs : expected) {
-                Assert.assertTrue(test.contains(expectedOtherConfigs));
-            }
-        }
+        testCRUDTerminationPoint(new SouthboundInterfaceOtherConfigsBuilder(), "TPInterfaceOtherConfigs",
+                new InterfaceOtherConfigsSouthboundHelper());
     }
 
     /*
@@ -1393,111 +1134,8 @@ public class SouthboundIT extends AbstractMdsalTestBase {
      */
     @Test
     public void testCRUDTerminationPointPortOtherConfigs() throws InterruptedException {
-        final String TEST_PREFIX = "CRUDTPPortOtherConfigs";
-        final int TERMINATION_POINT_TEST_INDEX = 0;
-
-        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
-        connectOvsdbNode(connectionInfo);
-
-        // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
-        // the update has been performed.
-        List<SouthboundTestCase<PortOtherConfigs>> updateFromTestCases =
-                generateKeyValueTestCases(new SouthboundPortOtherConfigsBuilder(), "PortOtherConfigsFrom");
-        List<SouthboundTestCase<PortOtherConfigs>> updateToTestCases =
-                generateKeyValueTestCases(new SouthboundPortOtherConfigsBuilder(), "PortOtherConfigsTo");
-
-        for (SouthboundTestCase<PortOtherConfigs> updateFromTestCase : updateFromTestCases) {
-            List<PortOtherConfigs> updateFromInputOtherConfigs = updateFromTestCase.inputValues;
-            List<PortOtherConfigs> updateFromExpectedOtherConfigs = updateFromTestCase.expectedValues;
-            for (SouthboundTestCase<PortOtherConfigs> updateToTestCase : updateToTestCases) {
-                String testBridgeAndPortName = String.format("%s_%s", TEST_PREFIX, updateToTestCase.name);
-                List<PortOtherConfigs> updateToInputOtherConfigs = updateToTestCase.inputValues;
-                List<PortOtherConfigs> updateToExpectedOtherConfigs = updateToTestCase.expectedValues;
-
-                // CREATE: Create the test port
-                Assert.assertTrue(addBridge(connectionInfo, null, testBridgeAndPortName, null, true,
-                        SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null, null, null));
-                NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
-                        connectionInfo, new OvsdbBridgeName(testBridgeAndPortName)));
-                OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
-                        createGenericOvsdbTerminationPointAugmentationBuilder();
-                tpCreateAugmentationBuilder.setName(testBridgeAndPortName);
-                tpCreateAugmentationBuilder.setPortOtherConfigs(updateFromInputOtherConfigs);
-                Assert.assertTrue(
-                        addTerminationPoint(testBridgeNodeId, testBridgeAndPortName, tpCreateAugmentationBuilder));
-
-                // READ: Read the test port and ensure changes are propagated to the CONFIGURATION data store,
-                // then repeat for OPERATIONAL data store
-                OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-                if (updateFromConfigurationTerminationPointAugmentation != null) {
-                    List<PortOtherConfigs> updateFromConfigurationOtherConfigs =
-                            updateFromConfigurationTerminationPointAugmentation.getPortOtherConfigs();
-                    assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
-                            updateFromConfigurationOtherConfigs);
-                }
-                OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-                if (updateFromOperationalTerminationPointAugmentation != null) {
-                    List<PortOtherConfigs> updateFromOperationalOtherConfigs =
-                            updateFromOperationalTerminationPointAugmentation.getPortOtherConfigs();
-                    assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
-                            updateFromOperationalOtherConfigs);
-                }
-
-                // UPDATE:  update the other_configs
-                testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeAndPortName).getNodeId();
-                OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
-                        new OvsdbTerminationPointAugmentationBuilder();
-                tpUpdateAugmentationBuilder.setPortOtherConfigs(updateToInputOtherConfigs);
-                InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
-                NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
-                NodeId portUpdateNodeId = createManagedNodeId(portIid);
-                portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
-                TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
-                tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testBridgeAndPortName)));
-                tpUpdateBuilder.addAugmentation(
-                        OvsdbTerminationPointAugmentation.class,
-                        tpUpdateAugmentationBuilder.build());
-                portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-                Assert.assertTrue(mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                        portIid, portUpdateNodeBuilder.build()));
-                Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-
-                // READ: the test port and ensure changes are propagated to the CONFIGURATION data store,
-                // then repeat for OPERATIONAL data store
-                OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-                if (updateToConfigurationTerminationPointAugmentation != null) {
-                    List<PortOtherConfigs> updateToConfigurationOtherConfigs =
-                            updateToConfigurationTerminationPointAugmentation.getPortOtherConfigs();
-                    assertExpectedPortOtherConfigsExist(updateToExpectedOtherConfigs,
-                            updateToConfigurationOtherConfigs);
-                    assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
-                            updateToConfigurationOtherConfigs);
-                }
-                OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
-                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeAndPortName,
-                                LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-                if (updateToOperationalTerminationPointAugmentation != null) {
-                    List<PortOtherConfigs> updateToOperationalOtherConfigs =
-                            updateToOperationalTerminationPointAugmentation.getPortOtherConfigs();
-                    if (updateFromExpectedOtherConfigs != null) {
-                        assertExpectedPortOtherConfigsExist(updateToExpectedOtherConfigs,
-                                updateToOperationalOtherConfigs);
-                        assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
-                                updateToOperationalOtherConfigs);
-                    }
-                }
-
-                // DELETE
-                Assert.assertTrue(deleteBridge(connectionInfo, testBridgeAndPortName));
-            }
-        }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        testCRUDTerminationPoint(new SouthboundPortOtherConfigsBuilder(), "TPPortOtherConfigs",
+                new PortOtherConfigsSouthboundHelper());
     }
 
     @Test
@@ -1554,9 +1192,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                 tpUpdateAugmentationBuilder.build());
         tpUpdateBuilder.setTpId(new TpId(portName));
         portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-        boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                portIid, portUpdateNodeBuilder.build());
-        Assert.assertTrue(result);
+        Assert.assertTrue(mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, portIid, portUpdateNodeBuilder.build()));
         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
 
         terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
@@ -1574,7 +1210,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
 
         // DELETE
         Assert.assertTrue(deleteBridge(connectionInfo));
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     @Test
@@ -1627,9 +1263,8 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                     tpUpdateAugmentationBuilder.build());
             tpUpdateBuilder.setTpId(new TpId(portName));
             portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-            boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                    portIid, portUpdateNodeBuilder.build());
-            Assert.assertTrue(result);
+            Assert.assertTrue(
+                    mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, portIid, portUpdateNodeBuilder.build()));
             Thread.sleep(OVSDB_UPDATE_TIMEOUT);
 
             terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
@@ -1646,7 +1281,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
             // DELETE
             Assert.assertTrue(deleteBridge(connectionInfo));
         }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     @SuppressWarnings("unchecked")
@@ -1725,9 +1360,8 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                     tpUpdateAugmentationBuilder.build());
             tpUpdateBuilder.setTpId(new TpId(portName));
             portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-            boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                    portIid, portUpdateNodeBuilder.build());
-            Assert.assertTrue(result);
+            Assert.assertTrue(
+                    mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, portIid, portUpdateNodeBuilder.build()));
             Thread.sleep(OVSDB_UPDATE_TIMEOUT);
 
             terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
@@ -1744,7 +1378,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
             // DELETE
             Assert.assertTrue(deleteBridge(connectionInfo));
         }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        disconnectOvsdbNode(connectionInfo);
     }
 
     @Test
@@ -1769,21 +1403,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
             }
         }
         Assert.assertNotNull("Expected to find Node: " + expectedNodeId, foundNode);
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
-    }
-
-    /*
-     * @see <code>SouthboundIT.testCRUDBridgeOtherConfigs()</code>
-     * This is helper test method to compare a test "set" of BridgeExternalIds against an expected "set"
-     */
-    private void assertExpectedBridgeOtherConfigsExist( List<BridgeOtherConfigs> expected,
-                                                        List<BridgeOtherConfigs> test ) {
-
-        if (expected != null) {
-            for (BridgeOtherConfigs expectedOtherConfig : expected) {
-                Assert.assertTrue(test.contains(expectedOtherConfig));
-            }
-        }
+        disconnectOvsdbNode(connectionInfo);
     }
 
     /*
@@ -1791,90 +1411,86 @@ public class SouthboundIT extends AbstractMdsalTestBase {
      */
     @Test
     public void testCRUDBridgeOtherConfigs() throws InterruptedException {
-        final String TEST_BRIDGE_PREFIX = "CRUDBridgeOtherConfigs";
+        testCRUDBridge("BridgeOtherConfigs", new SouthboundBridgeOtherConfigsBuilder(),
+                new BridgeOtherConfigsSouthboundHelper());
+    }
+
+    private interface SouthboundBridgeHelper<T> {
+        void writeValues(OvsdbBridgeAugmentationBuilder builder, List<T> values);
+        List<T> readValues(OvsdbBridgeAugmentation augmentation);
+    }
+
+    private <T> void testCRUDBridge(String prefix, KeyValueBuilder<T> builder, SouthboundBridgeHelper<T> helper)
+            throws InterruptedException {
         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
         connectOvsdbNode(connectionInfo);
         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
         // the update has been performed.
-        List<SouthboundTestCase<BridgeOtherConfigs>> updateFromTestCases =
-                generateKeyValueTestCases(new SouthboundBridgeOtherConfigsBuilder(), "BridgeOtherConfigsFrom");
-        List<SouthboundTestCase<BridgeOtherConfigs>> updateToTestCases = generateKeyValueTestCases(
-                new SouthboundBridgeOtherConfigsBuilder(), "BridgeOtherConfigsTo");
-        for (SouthboundTestCase<BridgeOtherConfigs> updateFromTestCase : updateFromTestCases) {
-            List<BridgeOtherConfigs> updateFromInputOtherConfigs = updateFromTestCase.inputValues;
-            List<BridgeOtherConfigs> updateFromExpectedOtherConfigs = updateFromTestCase.expectedValues;
-            for (SouthboundTestCase<BridgeOtherConfigs> updateToTestCase : updateToTestCases) {
-                String testBridgeName = String.format("%s_%s", TEST_BRIDGE_PREFIX, updateToTestCase.name);
-                List<BridgeOtherConfigs> updateToInputOtherConfigs = updateToTestCase.inputValues;
-                List<BridgeOtherConfigs> updateToExpectedOtherConfigs = updateToTestCase.expectedValues;
+        List<SouthboundTestCase<T>> updateFromTestCases = generateKeyValueTestCases(builder, prefix + "From");
+        List<SouthboundTestCase<T>> updateToTestCases = generateKeyValueTestCases(builder, prefix + "To");
+        for (SouthboundTestCase<T> updateFromTestCase : updateFromTestCases) {
+            for (SouthboundTestCase<T> updateToTestCase : updateToTestCases) {
+                String testBridgeName = String.format("%s_%s", prefix, updateToTestCase.name);
 
                 // CREATE: Create the test bridge
-                boolean bridgeAdded = addBridge(connectionInfo, null,
-                        testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
-                        true, null, null, null, updateFromInputOtherConfigs);
-                Assert.assertTrue(bridgeAdded);
+                final OvsdbBridgeName ovsdbBridgeName = new OvsdbBridgeName(testBridgeName);
+                final InstanceIdentifier<Node> bridgeIid = createInstanceIdentifier(connectionInfo, ovsdbBridgeName);
+                final NodeId bridgeNodeId = SouthboundMapper.createManagedNodeId(bridgeIid);
+                final NodeBuilder bridgeCreateNodeBuilder = new NodeBuilder();
+                bridgeCreateNodeBuilder.setNodeId(bridgeNodeId);
+                OvsdbBridgeAugmentationBuilder bridgeCreateAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
+                bridgeCreateAugmentationBuilder.setBridgeName(ovsdbBridgeName);
+                bridgeCreateAugmentationBuilder.setProtocolEntry(createMdsalProtocols());
+                bridgeCreateAugmentationBuilder.setFailMode(
+                        SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"));
+                setManagedBy(bridgeCreateAugmentationBuilder, connectionInfo);
+                helper.writeValues(bridgeCreateAugmentationBuilder, updateFromTestCase.inputValues);
+                bridgeCreateNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class,
+                        bridgeCreateAugmentationBuilder.build());
+                LOG.debug("Built with the intent to store bridge data {}", bridgeCreateAugmentationBuilder.toString());
+                Assert.assertTrue(mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, bridgeIid,
+                        bridgeCreateNodeBuilder.build()));
+                Thread.sleep(OVSDB_UPDATE_TIMEOUT);
 
                 // READ: Read the test bridge and ensure changes are propagated to the CONFIGURATION data store,
                 // then repeat for OPERATIONAL data store
-                List<BridgeOtherConfigs> updateFromConfigurationOtherConfigs = getBridge(connectionInfo, testBridgeName,
-                        LogicalDatastoreType.CONFIGURATION).getBridgeOtherConfigs();
-                assertExpectedBridgeOtherConfigsExist(updateFromExpectedOtherConfigs,
-                        updateFromConfigurationOtherConfigs);
-                List<BridgeOtherConfigs> updateFromOperationalOtherConfigs = getBridge(connectionInfo, testBridgeName).getBridgeOtherConfigs();
-                assertExpectedBridgeOtherConfigsExist(updateFromExpectedOtherConfigs,
-                        updateFromOperationalOtherConfigs);
-
-                // UPDATE:  update the external_ids
-                OvsdbBridgeAugmentationBuilder bridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
-                bridgeAugmentationBuilder.setBridgeOtherConfigs(updateToInputOtherConfigs);
-                InstanceIdentifier<Node> bridgeIid =
-                        createInstanceIdentifier(connectionInfo,
-                                new OvsdbBridgeName(testBridgeName));
-                NodeBuilder bridgeNodeBuilder = new NodeBuilder();
-                Node bridgeNode = getBridgeNode(connectionInfo, testBridgeName);
-                bridgeNodeBuilder.setNodeId(bridgeNode.getNodeId());
-                bridgeNodeBuilder.setKey(bridgeNode.getKey());
-                bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, bridgeAugmentationBuilder.build());
-                boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, bridgeIid,
-                        bridgeNodeBuilder.build());
+                List<T> updateFromConfigurationExternalIds = helper.readValues(getBridge(connectionInfo, testBridgeName,
+                        LogicalDatastoreType.CONFIGURATION));
+                assertExpectedExist(updateFromTestCase.expectedValues, updateFromConfigurationExternalIds);
+                List<T> updateFromOperationalExternalIds = helper.readValues(getBridge(connectionInfo, testBridgeName));
+                assertExpectedExist(updateFromTestCase.expectedValues, updateFromOperationalExternalIds);
+
+                // UPDATE:  update the values
+                final OvsdbBridgeAugmentationBuilder bridgeUpdateAugmentationBuilder =
+                        new OvsdbBridgeAugmentationBuilder();
+                helper.writeValues(bridgeUpdateAugmentationBuilder, updateToTestCase.inputValues);
+                final NodeBuilder bridgeUpdateNodeBuilder = new NodeBuilder();
+                final Node bridgeNode = getBridgeNode(connectionInfo, testBridgeName);
+                bridgeUpdateNodeBuilder.setNodeId(bridgeNode.getNodeId());
+                bridgeUpdateNodeBuilder.setKey(bridgeNode.getKey());
+                bridgeUpdateNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class,
+                        bridgeUpdateAugmentationBuilder.build());
+                Assert.assertTrue(mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, bridgeIid,
+                        bridgeUpdateNodeBuilder.build()));
                 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-                Assert.assertTrue(result);
 
                 // READ: the test bridge and ensure changes are propagated to the CONFIGURATION data store,
                 // then repeat for OPERATIONAL data store
-                List<BridgeOtherConfigs> updateToConfigurationOtherConfigs = getBridge(connectionInfo, testBridgeName,
-                        LogicalDatastoreType.CONFIGURATION).getBridgeOtherConfigs();
-                assertExpectedBridgeOtherConfigsExist(updateToExpectedOtherConfigs, updateToConfigurationOtherConfigs);
-                assertExpectedBridgeOtherConfigsExist(updateFromExpectedOtherConfigs,
-                        updateToConfigurationOtherConfigs);
-                List<BridgeOtherConfigs> updateToOperationalOtherConfigs = getBridge(connectionInfo, testBridgeName)
-                        .getBridgeOtherConfigs();
-                if (updateFromExpectedOtherConfigs != null) {
-                    assertExpectedBridgeOtherConfigsExist(updateToExpectedOtherConfigs,
-                            updateToOperationalOtherConfigs);
-                    assertExpectedBridgeOtherConfigsExist(updateFromExpectedOtherConfigs,
-                            updateToOperationalOtherConfigs);
+                List<T> updateToConfigurationExternalIds = helper.readValues(getBridge(connectionInfo, testBridgeName,
+                        LogicalDatastoreType.CONFIGURATION));
+                assertExpectedExist(updateToTestCase.expectedValues, updateToConfigurationExternalIds);
+                assertExpectedExist(updateFromTestCase.expectedValues, updateToConfigurationExternalIds);
+                List<T> updateToOperationalExternalIds = helper.readValues(getBridge(connectionInfo, testBridgeName));
+                if (updateFromTestCase.expectedValues != null) {
+                    assertExpectedExist(updateToTestCase.expectedValues, updateToOperationalExternalIds);
+                    assertExpectedExist(updateFromTestCase.expectedValues, updateToOperationalExternalIds);
                 }
 
                 // DELETE
                 Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
             }
         }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
-    }
-
-    /*
-     * @see <code>SouthboundIT.testCRUDBridgeExternalIds()</code>
-     * This is helper test method to compare a test "set" of BridgeExternalIds against an expected "set"
-     */
-    private void assertExpectedBridgeExternalIdsExist( List<BridgeExternalIds> expected,
-                                                       List<BridgeExternalIds> test ) {
-
-        if (expected != null) {
-            for (BridgeExternalIds expectedExternalId : expected) {
-                Assert.assertTrue(test.contains(expectedExternalId));
-            }
-        }
+        disconnectOvsdbNode(connectionInfo);
     }
 
     /*
@@ -1882,71 +1498,8 @@ public class SouthboundIT extends AbstractMdsalTestBase {
      */
     @Test
     public void testCRUDBridgeExternalIds() throws InterruptedException {
-        final String TEST_BRIDGE_PREFIX = "CRUDBridgeExternalIds";
-        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
-        connectOvsdbNode(connectionInfo);
-        // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
-        // the update has been performed.
-        List<SouthboundTestCase<BridgeExternalIds>> updateFromTestCases = generateKeyValueTestCases(
-                new SouthboundBridgeExternalIdsBuilder(), "BridgeExternalIdsFrom");
-        List<SouthboundTestCase<BridgeExternalIds>> updateToTestCases = generateKeyValueTestCases(
-                new SouthboundBridgeExternalIdsBuilder(), "BridgeExternalIdsTo");
-        for (SouthboundTestCase<BridgeExternalIds> updateFromTestCase : updateFromTestCases) {
-            List<BridgeExternalIds> updateFromInputExternalIds = updateFromTestCase.inputValues;
-            List<BridgeExternalIds> updateFromExpectedExternalIds = updateFromTestCase.expectedValues;
-            for (SouthboundTestCase<BridgeExternalIds> updateToTestCase : updateToTestCases) {
-                String testBridgeName = String.format("%s_%s", TEST_BRIDGE_PREFIX, updateToTestCase.name);
-                List<BridgeExternalIds> updateToInputExternalIds = updateToTestCase.inputValues;
-                List<BridgeExternalIds> updateToExpectedExternalIds = updateToTestCase.expectedValues;
-
-                // CREATE: Create the test bridge
-                boolean bridgeAdded = addBridge(connectionInfo, null,
-                        testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
-                        true, null, updateFromInputExternalIds, null, null);
-                Assert.assertTrue(bridgeAdded);
-
-                // READ: Read the test bridge and ensure changes are propagated to the CONFIGURATION data store,
-                // then repeat for OPERATIONAL data store
-                List<BridgeExternalIds> updateFromConfigurationExternalIds = getBridge(connectionInfo, testBridgeName,
-                        LogicalDatastoreType.CONFIGURATION).getBridgeExternalIds();
-                assertExpectedBridgeExternalIdsExist(updateFromExpectedExternalIds, updateFromConfigurationExternalIds);
-                List<BridgeExternalIds> updateFromOperationalExternalIds = getBridge(connectionInfo, testBridgeName).getBridgeExternalIds();
-                assertExpectedBridgeExternalIdsExist(updateFromExpectedExternalIds, updateFromOperationalExternalIds);
-
-                // UPDATE:  update the external_ids
-                OvsdbBridgeAugmentationBuilder bridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
-                bridgeAugmentationBuilder.setBridgeExternalIds(updateToInputExternalIds);
-                InstanceIdentifier<Node> bridgeIid =
-                        createInstanceIdentifier(connectionInfo,
-                                new OvsdbBridgeName(testBridgeName));
-                NodeBuilder bridgeNodeBuilder = new NodeBuilder();
-                Node bridgeNode = getBridgeNode(connectionInfo, testBridgeName);
-                bridgeNodeBuilder.setNodeId(bridgeNode.getNodeId());
-                bridgeNodeBuilder.setKey(bridgeNode.getKey());
-                bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, bridgeAugmentationBuilder.build());
-                boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, bridgeIid,
-                        bridgeNodeBuilder.build());
-                Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-                Assert.assertTrue(result);
-
-                // READ: the test bridge and ensure changes are propagated to the CONFIGURATION data store,
-                // then repeat for OPERATIONAL data store
-                List<BridgeExternalIds> updateToConfigurationExternalIds = getBridge(connectionInfo, testBridgeName,
-                        LogicalDatastoreType.CONFIGURATION).getBridgeExternalIds();
-                assertExpectedBridgeExternalIdsExist(updateToExpectedExternalIds, updateToConfigurationExternalIds);
-                assertExpectedBridgeExternalIdsExist(updateFromExpectedExternalIds, updateToConfigurationExternalIds);
-                List<BridgeExternalIds> updateToOperationalExternalIds = getBridge(connectionInfo, testBridgeName)
-                        .getBridgeExternalIds();
-                if (updateFromExpectedExternalIds != null) {
-                    assertExpectedBridgeExternalIdsExist(updateToExpectedExternalIds, updateToOperationalExternalIds);
-                    assertExpectedBridgeExternalIdsExist(updateFromExpectedExternalIds, updateToOperationalExternalIds);
-                }
-
-                // DELETE
-                Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
-            }
-        }
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        testCRUDBridge("BridgeExternalIds", new SouthboundBridgeExternalIdsBuilder(),
+                new BridgeExternalIdsSouthboundHelper());
     }
 
     public static InstanceIdentifier<Node> createInstanceIdentifier(ConnectionInfo key,OvsdbBridgeName bridgeName) {
@@ -2307,4 +1860,97 @@ public class SouthboundIT extends AbstractMdsalTestBase {
 
         return testCases;
     }
+
+    private static class PortExternalIdsSouthboundHelper implements SouthboundTerminationPointHelper<PortExternalIds> {
+        @Override
+        public void writeValues(OvsdbTerminationPointAugmentationBuilder builder, List<PortExternalIds> values) {
+            builder.setPortExternalIds(values);
+        }
+
+        @Override
+        public List<PortExternalIds> readValues(OvsdbTerminationPointAugmentation augmentation) {
+            return augmentation.getPortExternalIds();
+        }
+    }
+
+    private static class InterfaceExternalIdsSouthboundHelper implements
+            SouthboundTerminationPointHelper<InterfaceExternalIds> {
+        @Override
+        public void writeValues(
+                OvsdbTerminationPointAugmentationBuilder builder, List<InterfaceExternalIds> values) {
+            builder.setInterfaceExternalIds(values);
+        }
+
+        @Override
+        public List<InterfaceExternalIds> readValues(OvsdbTerminationPointAugmentation augmentation) {
+            return augmentation.getInterfaceExternalIds();
+        }
+    }
+
+    private static class OptionsSouthboundHelper implements SouthboundTerminationPointHelper<Options> {
+        @Override
+        public void writeValues(
+                OvsdbTerminationPointAugmentationBuilder builder, List<Options> values) {
+            builder.setOptions(values);
+        }
+
+        @Override
+        public List<Options> readValues(OvsdbTerminationPointAugmentation augmentation) {
+            return augmentation.getOptions();
+        }
+    }
+
+    private static class InterfaceOtherConfigsSouthboundHelper implements
+            SouthboundTerminationPointHelper<InterfaceOtherConfigs> {
+        @Override
+        public void writeValues(
+                OvsdbTerminationPointAugmentationBuilder builder, List<InterfaceOtherConfigs> values) {
+            builder.setInterfaceOtherConfigs(values);
+        }
+
+        @Override
+        public List<InterfaceOtherConfigs> readValues(OvsdbTerminationPointAugmentation augmentation) {
+            return augmentation.getInterfaceOtherConfigs();
+        }
+    }
+
+    private static class PortOtherConfigsSouthboundHelper implements
+            SouthboundTerminationPointHelper<PortOtherConfigs> {
+        @Override
+        public void writeValues(
+                OvsdbTerminationPointAugmentationBuilder builder, List<PortOtherConfigs> values) {
+            builder.setPortOtherConfigs(values);
+        }
+
+        @Override
+        public List<PortOtherConfigs> readValues(OvsdbTerminationPointAugmentation augmentation) {
+            return augmentation.getPortOtherConfigs();
+        }
+    }
+
+    private static class BridgeExternalIdsSouthboundHelper implements SouthboundBridgeHelper<BridgeExternalIds> {
+        @Override
+        public void writeValues(
+                OvsdbBridgeAugmentationBuilder builder, List<BridgeExternalIds> values) {
+            builder.setBridgeExternalIds(values);
+        }
+
+        @Override
+        public List<BridgeExternalIds> readValues(OvsdbBridgeAugmentation augmentation) {
+            return augmentation.getBridgeExternalIds();
+        }
+    }
+
+    private static class BridgeOtherConfigsSouthboundHelper implements SouthboundBridgeHelper<BridgeOtherConfigs> {
+        @Override
+        public void writeValues(
+                OvsdbBridgeAugmentationBuilder builder, List<BridgeOtherConfigs> values) {
+            builder.setBridgeOtherConfigs(values);
+        }
+
+        @Override
+        public List<BridgeOtherConfigs> readValues(OvsdbBridgeAugmentation augmentation) {
+            return augmentation.getBridgeOtherConfigs();
+        }
+    }
 }
index bc983993b25890fee5ab410fd013d22c7b054dcc..474a582ebb221b7792a221bcc3688947e0768e0c 100644 (file)
@@ -94,6 +94,18 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   </dependencies>
   <build>
     <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.ovsdb.utils.mdsal.openflow
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
index ab85bf3170aa7dd06b5d367e36a6404e4af29e48..c3b878c593b0a00402facf842654f15d68438114 100644 (file)
@@ -31,6 +31,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.acti
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.field._case.SetFieldBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.dst.action._case.SetNwDstActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.src.action._case.SetNwSrcActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TunnelBuilder;
@@ -58,6 +59,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._4.grouping.NxSetNshc4Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.SrcChoice;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxArpShaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc1CaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc2CaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxRegCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIdCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIpv4DstCaseBuilder;
@@ -261,35 +264,27 @@ public final class ActionUtils {
 
     public static Action nxMoveRegTunIdAction(Class<? extends NxmNxReg> src,
                                               boolean groupBucket) {
-        return nxMoveRegAction(new SrcNxRegCaseBuilder()
-                                    .setNxReg(src).build(),
-                               new DstNxTunIdCaseBuilder()
-                                   .setNxTunId(Boolean.TRUE).build(),
+        return nxMoveRegAction(new SrcNxRegCaseBuilder().setNxReg(src).build(),
+                               new DstNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(),
                                31,
                                groupBucket);
     }
 
     public static Action nxMoveArpShaToArpThaAction() {
-        return nxMoveRegAction(new SrcNxArpShaCaseBuilder()
-                                   .setNxArpSha(Boolean.TRUE).build(),
-                               new DstNxArpThaCaseBuilder()
-                                   .setNxArpTha(Boolean.TRUE).build(),
+        return nxMoveRegAction(new SrcNxArpShaCaseBuilder().setNxArpSha(Boolean.TRUE).build(),
+                               new DstNxArpThaCaseBuilder().setNxArpTha(Boolean.TRUE).build(),
                                47, false);
     }
 
     public static Action nxMoveEthSrcToEthDstAction() {
-        return nxMoveRegAction(new SrcOfEthSrcCaseBuilder()
-                                   .setOfEthSrc(Boolean.TRUE).build(),
-                               new DstOfEthDstCaseBuilder()
-                                   .setOfEthDst(Boolean.TRUE).build(),
+        return nxMoveRegAction(new SrcOfEthSrcCaseBuilder().setOfEthSrc(Boolean.TRUE).build(),
+                               new DstOfEthDstCaseBuilder().setOfEthDst(Boolean.TRUE).build(),
                                47, false);
     }
 
     public static Action nxMoveArpSpaToArpTpaAction() {
-        return nxMoveRegAction(new SrcOfArpSpaCaseBuilder()
-                                   .setOfArpSpa(Boolean.TRUE).build(),
-                               new DstOfArpTpaCaseBuilder()
-                                   .setOfArpTpa(Boolean.TRUE).build());
+        return nxMoveRegAction(new SrcOfArpSpaCaseBuilder().setOfArpSpa(Boolean.TRUE).build(),
+                               new DstOfArpTpaCaseBuilder().setOfArpTpa(Boolean.TRUE).build());
     }
 
     public static Action nxOutputRegAction(SrcChoice srcChoice) {
@@ -359,13 +354,31 @@ public final class ActionUtils {
     }
 
     public static Action nxMoveRegTunDstToNshc1() {
-        return nxMoveRegAction(new SrcNxTunIpv4DstCaseBuilder().setNxTunIpv4Dst(Boolean.TRUE).build(),
-                new DstNxNshc1CaseBuilder().setNxNshc1Dst(Boolean.TRUE).build(), 31, false);
+        return nxMoveRegAction(
+                new SrcNxTunIpv4DstCaseBuilder().setNxTunIpv4Dst(Boolean.TRUE).build(),
+                new DstNxNshc1CaseBuilder().setNxNshc1Dst(Boolean.TRUE).build(),
+                31, false);
     }
 
     public static Action nxMoveTunIdtoNshc2() {
-        return nxMoveRegAction(new SrcNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(),
-                new DstNxNshc2CaseBuilder().setNxNshc2Dst(Boolean.TRUE).build(), 31, false);
+        return nxMoveRegAction(
+                new SrcNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(),
+                new DstNxNshc2CaseBuilder().setNxNshc2Dst(Boolean.TRUE).build(),
+                31, false);
+    }
+
+    public static Action nxMoveNshc1ToTunIpv4Dst() {
+        return nxMoveRegAction(
+                new SrcNxNshc1CaseBuilder().setNxNshc1Dst(Boolean.TRUE).build(),
+                new DstNxTunIpv4DstCaseBuilder().setNxTunIpv4Dst(Boolean.TRUE).build(),
+                31, false);
+    }
+
+    public static Action nxMoveNshc2ToTunId() {
+        return nxMoveRegAction(
+                new SrcNxNshc2CaseBuilder().setNxNshc2Dst(Boolean.TRUE).build(),
+                new DstNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(),
+                31, false);
     }
 
     public static Action nxLoadTunIdAction(BigInteger tunnelId, boolean groupBucket) {
diff --git a/utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/FlowUtils.java b/utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/FlowUtils.java
new file mode 100644 (file)
index 0000000..f916026
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015 Red Hat, 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.utils.mdsal.openflow;
+
+import com.google.common.base.Optional;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(FlowUtils.class);
+    private static final String OPENFLOW = "openflow";
+    public final static long REG_VALUE_FROM_LOCAL = 0x1L;
+    public final static long REG_VALUE_FROM_REMOTE = 0x2L;
+    public static final Class<? extends NxmNxReg> REG_FIELD = NxmNxReg0.class;
+    public static final int ARP_OP_REQUEST = 0x1;
+    public static final int ARP_OP_REPLY = 0x2;
+
+
+    public static String getNodeName(long dpidLong) {
+        return OPENFLOW + ":" + dpidLong;
+    }
+
+    public static NodeConnectorId getNodeConnectorId(long ofPort, String nodeName) {
+        return new NodeConnectorId(nodeName + ":" + ofPort);
+    }
+
+    public static NodeConnectorId getSpecialNodeConnectorId(long dpidLong, String portName) {
+        return new NodeConnectorId(getNodeName(dpidLong) + ":" + portName);
+    }
+
+    public static NodeConnectorId getNodeConnectorId(long dpidLong, long ofPort) {
+        return getNodeConnectorId(ofPort, getNodeName(dpidLong));
+    }
+
+    public static NodeBuilder createNodeBuilder(String nodeId) {
+        NodeBuilder builder = new NodeBuilder();
+        builder.setId(new NodeId(nodeId));
+        builder.setKey(new NodeKey(builder.getId()));
+        return builder;
+    }
+
+    public static NodeBuilder createNodeBuilder(long dpidLong) {
+        return createNodeBuilder(getNodeName(dpidLong));
+    }
+
+    public static InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        return InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeBuilder.getKey())
+                .augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(flowBuilder.getTableId()))
+                .child(Flow.class, flowBuilder.getKey()).build();
+    }
+
+    public static InstanceIdentifier<Node> createNodePath(NodeBuilder nodeBuilder) {
+        return InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeBuilder.getKey()).build();
+    }
+
+    public static Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder,
+                               ReadOnlyTransaction readTx, final LogicalDatastoreType store) {
+        try {
+            Optional<Flow> data = readTx.read(store, createFlowPath(flowBuilder, nodeBuilder)).get();
+            if (data.isPresent()) {
+                return data.get();
+            }
+        } catch (InterruptedException|ExecutionException e) {
+            LOG.error(e.getMessage(), e);
+        }
+
+        LOG.info("Cannot find data for Flow {} in {}", flowBuilder.getFlowName(), store);
+        return null;
+    }
+
+    public static FlowBuilder getPipelineFlow(short table, short gotoTable) {
+        FlowBuilder flowBuilder = new FlowBuilder();
+        flowBuilder.setMatch(new MatchBuilder().build());
+
+        String flowId = "DEFAULT_PIPELINE_FLOW_" + table;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(true);
+        flowBuilder.setBarrier(false);
+        flowBuilder.setTableId(table);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        flowBuilder.setPriority(0);
+        return flowBuilder;
+    }
+}
index 9d61386b8efba1be8e6610cd4e9ea1bd3630d0d3..4534e8efc6eeb0d8bec24a36f511b7a7f6e97d11 100644 (file)
@@ -144,6 +144,35 @@ public class InstructionUtils {
         return ib;
     }
 
+    /**
+     * Create LOCAL Reserved Port Instruction
+     *
+     * @param ib Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @return ib Map InstructionBuilder with instructions
+     */
+    public static InstructionBuilder createLocalInstructions(InstructionBuilder ib, long dpidLong) {
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        OutputActionBuilder output = new OutputActionBuilder();
+        output.setOutputNodeConnector(new NodeConnectorId("openflow:" + dpidLong + ":"
+                + OutputPortValues.LOCAL.toString()));
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(output.build()).build());
+        ab.setOrder(0);
+        ab.setKey(new ActionKey(0));
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+
+        // Wrap our Apply Action in an Instruction
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
     /**
      * Create Output Port Instruction
      *
index dd7222080a038e32243008a9970afb0902104088..930a1d507b8f25a70e7aee8f517819346630e24f 100644 (file)
@@ -81,6 +81,7 @@ public class MatchUtils {
     public static final String UDP = "udp";
     private static final int TCP_SYN = 0x0002;
     public static final String ICMP = "icmp";
+    public static final short ALL_ICMP = -1;
 
     /**
      * Create Ingress Port Match dpidLong, inPort
@@ -100,6 +101,17 @@ public class MatchUtils {
         return matchBuilder;
     }
 
+    public static MatchBuilder createInPortReservedMatch(MatchBuilder matchBuilder, Long dpidLong, String inPort) {
+
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + inPort);
+        LOG.debug("createInPortResrevedMatch() Node Connector ID is - Type=openflow: DPID={} inPort={} ",
+                dpidLong, inPort);
+        matchBuilder.setInPort(NodeConnectorId.getDefaultInstance(ncid.getValue()));
+        matchBuilder.setInPort(ncid);
+
+        return matchBuilder;
+    }
+
     /**
      * Create EtherType Match
      *
@@ -208,8 +220,10 @@ public class MatchUtils {
 
         // Build the ICMPv4 Match
         Icmpv4MatchBuilder icmpv4match = new Icmpv4MatchBuilder();
-        icmpv4match.setIcmpv4Type(type);
-        icmpv4match.setIcmpv4Code(code);
+        if (type != ALL_ICMP || code != ALL_ICMP) {
+            icmpv4match.setIcmpv4Type(type);
+            icmpv4match.setIcmpv4Code(code);
+        }
         matchBuilder.setIcmpv4Match(icmpv4match.build());
 
         return matchBuilder;
@@ -244,7 +258,8 @@ public class MatchUtils {
      */
     public static MatchBuilder createArpDstIpv4Match(MatchBuilder matchBuilder, Ipv4Prefix dstip) {
         ArpMatchBuilder arpDstMatch = new ArpMatchBuilder();
-        arpDstMatch.setArpTargetTransportAddress(dstip);
+        arpDstMatch.setArpTargetTransportAddress(dstip)
+                .setArpOp(FlowUtils.ARP_OP_REQUEST);
         matchBuilder.setLayer3Match(arpDstMatch.build());
 
         return matchBuilder;
@@ -1075,8 +1090,7 @@ public class MatchUtils {
         }
     }
 
-    public static void addNxRegMatch(MatchBuilder match,
-                                     RegMatch... matches) {
+    public static MatchBuilder addNxRegMatch(MatchBuilder matchBuilder, RegMatch... matches) {
         List<ExtensionList> extensions = new ArrayList<>();
         for (RegMatch rm : matches) {
             Class<? extends ExtensionKey> key;
@@ -1099,67 +1113,68 @@ public class MatchUtils {
             }
             NxAugMatchNodesNodeTableFlow am =
                     new NxAugMatchNodesNodeTableFlowBuilder()
-                .setNxmNxReg(new NxmNxRegBuilder()
-                    .setReg(rm.reg)
-                    .setValue(rm.value)
-                    .build())
-                .build();
+                            .setNxmNxReg(new NxmNxRegBuilder()
+                                    .setReg(rm.reg)
+                                    .setValue(rm.value)
+                                    .build())
+                            .build();
             extensions.add(new ExtensionListBuilder()
-                .setExtensionKey(key)
-                .setExtension(new ExtensionBuilder()
-                     .addAugmentation(NxAugMatchNodesNodeTableFlow.class, am)
-                     .build())
-                .build());
+                    .setExtensionKey(key)
+                    .setExtension(new ExtensionBuilder()
+                            .addAugmentation(NxAugMatchNodesNodeTableFlow.class, am)
+                            .build())
+                    .build());
         }
-        GeneralAugMatchNodesNodeTableFlow m =
-                new GeneralAugMatchNodesNodeTableFlowBuilder()
-            .setExtensionList(extensions)
-            .build();
-        match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+        GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(extensions)
+                .build();
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+        return matchBuilder;
     }
 
-    public static void addNxTunIdMatch(MatchBuilder match,
-                                       int tunId) {
-        NxAugMatchNodesNodeTableFlow am =
-               new NxAugMatchNodesNodeTableFlowBuilder()
-                   .setNxmNxTunId(new NxmNxTunIdBuilder()
-                       .setValue(BigInteger.valueOf(tunId))
-                       .build())
-                   .build();
+    public static MatchBuilder addNxTunIdMatch(MatchBuilder matchBuilder, int tunId) {
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder()
+                .setNxmNxTunId(new NxmNxTunIdBuilder()
+                        .setValue(BigInteger.valueOf(tunId))
+                        .build())
+                .build();
         GeneralAugMatchNodesNodeTableFlow m =
                 new GeneralAugMatchNodesNodeTableFlowBuilder()
-            .setExtensionList(ImmutableList.of(new ExtensionListBuilder()
-                .setExtensionKey(NxmNxTunIdKey.class)
-                .setExtension(new ExtensionBuilder()
-                    .addAugmentation(NxAugMatchNodesNodeTableFlow.class, am)
-                    .build())
-                .build()))
-            .build();
-        match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+                        .setExtensionList(ImmutableList.of(new ExtensionListBuilder()
+                                .setExtensionKey(NxmNxTunIdKey.class)
+                                .setExtension(new ExtensionBuilder()
+                                        .addAugmentation(NxAugMatchNodesNodeTableFlow.class, am)
+                                        .build())
+                                .build()))
+                        .build();
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+        return matchBuilder;
     }
 
-    public static void addNxNsp(MatchBuilder match, long nsp) {
-        org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow am =
-                new org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlowBuilder()
+    public static MatchBuilder addNxNspMatch(MatchBuilder matchBuilder, long nsp) {
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder()
                 .setNxmNxNsp(new NxmNxNspBuilder()
-                .setValue(nsp)
-                .build())
+                        .setValue(nsp)
+                        .build())
                 .build();
-        addExtension(match, NxmNxNspKey.class, am);
+        addExtension(matchBuilder, NxmNxNspKey.class, am);
+        return matchBuilder;
     }
 
-    public static void addNxNsi(MatchBuilder match, short nsi) {
-        org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow am =
-                new org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlowBuilder()
+    public static MatchBuilder addNxNsiMatch(MatchBuilder matchBuilder, short nsi) {
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder()
                 .setNxmNxNsi(new NxmNxNsiBuilder()
-                .setNsi(nsi)
-                .build())
+                        .setNsi(nsi)
+                        .build())
                 .build();
-        addExtension(match, NxmNxNsiKey.class, am);
+        addExtension(matchBuilder, NxmNxNsiKey.class, am);
+        return matchBuilder;
     }
 
-    private static void addExtension (MatchBuilder match, Class<? extends ExtensionKey> extensionKey, org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow am) {
-        GeneralAugMatchNodesNodeTableFlow existingAugmentations = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class);
+    private static void addExtension(MatchBuilder matchBuilder, Class<? extends ExtensionKey> extensionKey,
+                                     NxAugMatchNodesNodeTableFlow am) {
+        GeneralAugMatchNodesNodeTableFlow existingAugmentations =
+                matchBuilder.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class);
         List<ExtensionList> extensions = null;
         if (existingAugmentations != null ) {
             extensions = existingAugmentations.getExtensionList();
@@ -1169,16 +1184,16 @@ public class MatchUtils {
         }
 
         extensions.add(new ExtensionListBuilder()
-                           .setExtensionKey(extensionKey)
-                           .setExtension(new ExtensionBuilder()
-                           .addAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow.class, am)
-                           .build())
-                           .build());
+                .setExtensionKey(extensionKey)
+                .setExtension(new ExtensionBuilder()
+                        .addAugmentation(NxAugMatchNodesNodeTableFlow.class, am)
+                        .build())
+                .build());
 
         GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder()
-        .setExtensionList(extensions)
-        .build();
-        match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+                .setExtensionList(extensions)
+                .build();
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
     }
 
     public static EthernetMatch ethernetMatch(MacAddress srcMac,
index ffdb77d2bea3b71906a7743f02d1e8dcad8512d7..11ddb71dd893cf3145bbb52d631b1a3d5b43d3b0 100644 (file)
   <version>1.2.1-SNAPSHOT</version>
   <packaging>bundle</packaging>
 
+  <developers>
+    <developer>
+      <name>Anil Vishnoi</name>
+      <email>vishnoianil@gmail.com</email>
+      <url>https://github.com/vishnoianil</url>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/ovsdb.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/ovsdb.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+  </scm>
+
+  <properties>
+    <neutron.model.version>0.6.0-SNAPSHOT</neutron.model.version>
+  </properties>
+
   <dependencies>
     <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>mockito-all</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>model</artifactId>
+      <version>${neutron.model.version}</version>
+    </dependency>
   </dependencies>
 
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.ovsdb.utils.mdsal.utils
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 </project>
\ No newline at end of file
diff --git a/utils/mdsal-utils/src/main/java/org/opendaylight/ovsdb/utils/mdsal/utils/NeutronModelsDataStoreHelper.java b/utils/mdsal-utils/src/main/java/org/opendaylight/ovsdb/utils/mdsal/utils/NeutronModelsDataStoreHelper.java
new file mode 100644 (file)
index 0000000..e22b724
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015 Brocade 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.utils.mdsal.utils;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+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.neutron.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronModelsDataStoreHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MdsalUtils.class);
+    private DataBroker databroker = null;
+    private MdsalUtils mdsalClient = null;
+
+    /**
+     * Class constructor setting the data broker.
+     *
+     * @param dataBroker the {@link org.opendaylight.controller.md.sal.binding.api.DataBroker}
+     */
+    public NeutronModelsDataStoreHelper(DataBroker dataBroker) {
+        this.databroker = dataBroker;
+        this.mdsalClient = new MdsalUtils(this.databroker);
+    }
+
+    public Routers readAllNeutronRouters() {
+        Routers routers = this.mdsalClient.read(LogicalDatastoreType.CONFIGURATION, getNeutrounRoutersPath());
+        if(routers != null ) {
+            LOG.debug("{} routers present in data store", routers.getRouter()!=null? routers.getRouter().size():0);
+        }
+        return routers;
+    }
+
+    public Ports readAllNeutronPorts() {
+        Ports ports = this.mdsalClient.read(LogicalDatastoreType.CONFIGURATION, getNeutrounPortsPath());
+        if(ports != null ) {
+            LOG.debug("{} ports present in data store", ports.getPort()!=null? ports.getPort().size():0);
+        }
+        return ports;
+    }
+    public Port readNeutronPort(Uuid portId) {
+        Port mdsalPort = this.mdsalClient.read(LogicalDatastoreType.CONFIGURATION, getNeutronPortPath(portId));
+        if (mdsalPort != null) {
+            LOG.debug("Port {} fetched from config data store for router interface {}",mdsalPort, portId);
+        }
+        return mdsalPort;
+    }
+
+    private InstanceIdentifier<Routers> getNeutrounRoutersPath() {
+        return InstanceIdentifier
+                .create(Neutron.class)
+                .child(Routers.class);
+    }
+
+    private InstanceIdentifier<Ports> getNeutrounPortsPath() {
+        return InstanceIdentifier
+                .create(Neutron.class)
+                .child(Ports.class);
+    }
+
+    private InstanceIdentifier<Port> getNeutronPortPath(Uuid portId) {
+        return InstanceIdentifier
+                .create(Neutron.class)
+                .child(Ports.class)
+                .child(Port.class,new PortKey(portId));
+    }
+}
index 73da69da6b0cc0a8ee2460ec83ef91d84f6ad04f..f34a96dc1227db6a2ea95541e44ab393d29dddae 100644 (file)
@@ -95,6 +95,13 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
         <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.ovsdb.utils.servicehelper
+            </Export-Package>
+          </instructions>
+        </configuration>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
index 81ed0bdd76727b24e2327cf50239f8d4f880ca28..9111acc92e35f5b81e5b8e7873461039f6d52bfa 100644 (file)
@@ -14,6 +14,7 @@ import java.net.UnknownHostException;
 import java.util.ArrayList;
 
 import java.util.List;
+import java.util.Map;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
@@ -30,13 +31,24 @@ 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.bridge.attributes.ProtocolEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
 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.port._interface.attributes.InterfaceExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsKey;
 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.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -47,11 +59,31 @@ public class SouthboundUtils {
     private static final String DEFAULT_OPENFLOW_PORT = "6653";
     private static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
     private MdsalUtils mdsalUtils;
+    public static final TopologyId OVSDB_TOPOLOGY_ID = new TopologyId(new Uri("ovsdb:1"));
 
     public SouthboundUtils(MdsalUtils mdsalUtils) {
         this.mdsalUtils = mdsalUtils;
     }
 
+    public static final ImmutableBiMap<String, Class<? extends InterfaceTypeBase>> OVSDB_INTERFACE_TYPE_MAP
+            = new ImmutableBiMap.Builder<String, Class<? extends InterfaceTypeBase>>()
+            .put("internal", InterfaceTypeInternal.class)
+            .put("vxlan", InterfaceTypeVxlan.class)
+            .put("patch", InterfaceTypePatch.class)
+            .put("system", InterfaceTypeSystem.class)
+            .put("tap", InterfaceTypeTap.class)
+            .put("geneve", InterfaceTypeGeneve.class)
+            .put("gre", InterfaceTypeGre.class)
+            .put("ipsec_gre", InterfaceTypeIpsecGre.class)
+            .put("gre64", InterfaceTypeGre64.class)
+            .put("ipsec_gre64", InterfaceTypeIpsecGre64.class)
+            .put("lisp", InterfaceTypeLisp.class)
+            .put("dpdk", InterfaceTypeDpdk.class)
+            .put("dpdkr", InterfaceTypeDpdkr.class)
+            .put("dpdkvhost", InterfaceTypeDpdkvhost.class)
+            .put("dpdkvhostuser", InterfaceTypeDpdkvhostuser.class)
+            .build();
+
     public NodeId createNodeId(IpAddress ip, PortNumber port) {
         String uriString = SouthboundConstants.OVSDB_URI_PREFIX + "://"
                 + new String(ip.getValue()) + ":" + port.getValue();
@@ -89,6 +121,18 @@ public class SouthboundUtils {
         return SouthboundMapper.createInstanceIdentifier(createManagedNodeId(key, bridgeName));
     }
 
+    public InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(Node node, String portName){
+
+        InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
+                .child(Node.class,node.getKey())
+                .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
+
+        LOG.debug("Termination point InstanceIdentifier generated : {}",terminationPointPath);
+        return terminationPointPath;
+    }
+
     public NodeKey createNodeKey(IpAddress ip, PortNumber port) {
         return new NodeKey(createNodeId(ip, port));
     }
@@ -336,4 +380,61 @@ public class SouthboundUtils {
         InstanceIdentifier<Node> connectionNodePath = createInstanceIdentifier(connectionInfo);
         ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
     }
+
+    public Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName,
+                                       String type, Map<String, String> options,
+                                       Map<String, String> externalIds) {
+        InstanceIdentifier<TerminationPoint> tpIid = createTerminationPointInstanceIdentifier(bridgeNode, portName);
+        OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
+
+        tpAugmentationBuilder.setName(portName);
+        if (type != null) {
+            tpAugmentationBuilder.setInterfaceType(OVSDB_INTERFACE_TYPE_MAP.get(type));
+        }
+
+        if (options != null && options.size() > 0) {
+            List<Options> optionsList = new ArrayList<>();
+            for (Map.Entry<String, String> entry : options.entrySet()) {
+                OptionsBuilder optionsBuilder = new OptionsBuilder();
+                optionsBuilder.setKey(new OptionsKey(entry.getKey()));
+                optionsBuilder.setOption(entry.getKey());
+                optionsBuilder.setValue(entry.getValue());
+                optionsList.add(optionsBuilder.build());
+            }
+            tpAugmentationBuilder.setOptions(optionsList);
+        }
+
+        if (externalIds != null && externalIds.size() > 0) {
+            List<InterfaceExternalIds> externalIdsList = new ArrayList<>();
+            for (Map.Entry<String, String> entry : externalIds.entrySet()) {
+                InterfaceExternalIdsBuilder interfaceExternalIdsBuilder = new InterfaceExternalIdsBuilder();
+                interfaceExternalIdsBuilder.setKey(new InterfaceExternalIdsKey(entry.getKey()));
+                interfaceExternalIdsBuilder.setExternalIdKey(entry.getKey());
+                interfaceExternalIdsBuilder.setExternalIdValue(entry.getValue());
+                externalIdsList.add(interfaceExternalIdsBuilder.build());
+            }
+            tpAugmentationBuilder.setInterfaceExternalIds(externalIdsList);
+        }
+
+        TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
+        tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid));
+        tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
+        /* TODO SB_MIGRATION should this be merge or mdsalUtils.put */
+        return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build());
+    }
+
+    public TerminationPoint readTerminationPoint(Node bridgeNode, String bridgeName, String portName) {
+        InstanceIdentifier<TerminationPoint> tpIid = createTerminationPointInstanceIdentifier(
+                bridgeNode, portName);
+        return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, tpIid);
+    }
+
+    public Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName, String type) {
+        return addTerminationPoint(bridgeNode, bridgeName, portName, type, null, null);
+    }
+
+    public Boolean addTunnelTerminationPoint(Node bridgeNode, String bridgeName, String portName, String type,
+                                             Map<String, String> options) {
+        return addTerminationPoint(bridgeNode, bridgeName, portName, type, options, null);
+    }
 }