Merge "Security Groups: Added support for ICMP, ALL ICMP and Others protocol Change...
authorAnil Vishnoi <vishnoianil@gmail.com>
Fri, 13 Nov 2015 17:11:12 +0000 (17:11 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 13 Nov 2015 17:11:12 +0000 (17:11 +0000)
45 files changed:
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java
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-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/impl/pom.xml
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/INetvirtSfcOF13Provider.java
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/NetvirtSfcProvider.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/SfcUtils.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/standalone/openflow13/NetvirtSfcStandaloneOF13Provider.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/standalone/openflow13/services/SfcClassifierService.java
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/NetvirtSfcWorkaroundOF13Provider.java [deleted file]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/SfcClassifierService.java
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/AclUtils.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
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
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]
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
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/InstructionUtils.java
utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java

index bac5a71b763b33f4f6fc890bd08aac89dd146c4c..2d4f49b7d0b5115d331cbbcd19967f1cdf827874 100644 (file)
@@ -21,6 +21,7 @@ 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;
@@ -30,6 +31,8 @@ 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;
@@ -44,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;
@@ -53,6 +58,7 @@ 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 =
@@ -181,18 +187,50 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
         ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
         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 {
+        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);
index 19f933ab06c8fee596f7bdc39642a26748407f7c..8592e4286d1c76e01789d4318a7026aae5387f8b 100644 (file)
@@ -8,10 +8,16 @@
 
 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;
@@ -19,6 +25,7 @@ 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 {
@@ -77,4 +84,77 @@ public class HwvtepSouthboundUtil {
         }
         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;
+        // TODO: Add managed-by to hwvtep-logical-switch-attributes in
+        // hwvtep.yang
+        /*
+         * HwvtepGlobalRef ref = lNode.getManagedBy(); if (ref != null &&
+         * ref.getValue() != null) { result = getManagingNode(db, ref); } else {
+         * LOG.warn(
+         * "Cannot find client for LogicalSwitch without a specified ManagedBy {}"
+         * , pNode); return Optional.absent(); } if(!result.isPresent()) {
+         * LOG.warn("Failed to find managing node for PhysicalSwitch {}",
+         * pNode); } return result;
+         */
+        return Optional.absent(); // TODO: Delete this once yang is updated
+    }
+
+    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();
+        }
+    }
+
 }
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 fdd67e8dbf1ac99a1826fb63bb1af545cd8e815e..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);
index 1f3c7f42704851c70d47b2c7166ffb4ab6252657..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);
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 3bd7e21e281bd2e596bdbc28b6cdf25f711f93d8..27c3ab73097acb581025a68ff1aa9b0227f6262c 100644 (file)
@@ -48,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>
@@ -173,6 +178,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <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>
@@ -188,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 66fd2a362d10cc74279276efcc79929b2808d4e0..458216343b90908777eed2c4e8557de11cbcc702 100644 (file)
@@ -8,10 +8,12 @@
 
 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
@@ -40,4 +42,7 @@ public interface INetvirtSfcOF13Provider {
 
     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..806e7c6
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 programEgressClassifier2(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                  int tunnelOfPort, 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 0289d60eea94f71fa9ae0931a72375eac549394d..a77b8cf560f795bb44a5567279ec320160569cee 100644 (file)
@@ -19,7 +19,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.OF13Provide
 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.services.NetvirtSfcWorkaroundOF13Provider;
+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;
@@ -57,6 +57,7 @@ public class NetvirtSfcProvider implements BindingAwareProvider, AutoCloseable {
 
         MdsalUtils mdsalUtils = new MdsalUtils(dataBroker);
         SfcUtils sfcUtils = new SfcUtils(mdsalUtils);
+
         // Allocate provider based on config
         INetvirtSfcOF13Provider provider;
         if (of13Provider.equals("standalone")) {
@@ -67,7 +68,8 @@ public class NetvirtSfcProvider implements BindingAwareProvider, AutoCloseable {
         aclListener = new NetvirtSfcAclListener(provider, dataBroker);
         classifierListener = new NetvirtSfcClassifierListener(provider, dataBroker);
 
-        addToPipeline();
+        addToPipeline(provider);
+        provider.setDependencies(null);
     }
 
     @Override
@@ -77,13 +79,24 @@ public class NetvirtSfcProvider implements BindingAwareProvider, AutoCloseable {
         classifierListener.close();
     }
 
-    private void addToPipeline() {
-        SfcClassifierService sfcClassifierService = new SfcClassifierService();
-        registerService(bundleContext, SfcClassifierService.class.getName(),
-                        sfcClassifierService, Service.SFC_CLASSIFIER);
-        sfcClassifierService.setDependencies(bundleContext, null);
+    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);
@@ -96,7 +109,7 @@ public class NetvirtSfcProvider implements BindingAwareProvider, AutoCloseable {
         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);
+                new String[] {AbstractServiceInstance.class.getName(),interfaceClassName},
+                properties, impl);
     }
 }
index 4114b1f08bfa9c1bfa93ccbc00b00c68864b350a..40b8172393e41608418dae976913283d6b736b11 100644 (file)
@@ -10,17 +10,29 @@ 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) {
@@ -40,6 +52,15 @@ public class SfcUtils {
                 .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());
@@ -67,4 +88,65 @@ public class SfcUtils {
         }
         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();
+    }
 }
index 6343a8a3912f3482a6be5a2ccfaf920555217289..77ec178f65f50b943b8b98c53a8c5e1d588e3c64 100644 (file)
@@ -19,6 +19,7 @@ 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;
@@ -82,7 +83,7 @@ public class NetvirtSfcStandaloneOF13Provider implements INetvirtSfcOF13Provider
     public NetvirtSfcStandaloneOF13Provider(final DataBroker dataBroker) {
         Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
         mdsalUtils = new MdsalUtils(dataBroker);
-        this.setDependencies(null);
+        //this.setDependencies(null);
         sfcClassifier = new SfcClassifier(dataBroker, southbound, mdsalUtils);
     }
 
@@ -126,6 +127,11 @@ public class NetvirtSfcStandaloneOF13Provider implements INetvirtSfcOF13Provider
         }
     }
 
+    @Override
+    public void setSfcClassifierService(ISfcClassifierService sfcClassifierService) {
+
+    }
+
     @Override
     public void addClassifierRules(Bridge bridge, Acl acl) {
 
@@ -148,59 +154,16 @@ public class NetvirtSfcStandaloneOF13Provider implements INetvirtSfcOF13Provider
             return;
         }
 
-        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;
-        }
-
-        String sfcName = sfcRedirect.getRedirectSfc();
-        LOG.debug("Processing Redirect to SFC = {}", sfcRedirect.getRedirectSfc());
-        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;
-        }
-
-        LOG.debug("Processing Redirect to SFC = {}, SFP = {}", sfcRedirect.getRedirectSfc(), sfp);
-        // If RSP doesn't exist, create an RSP.
-        String sfpName = sfp.getName().getValue();
-        RenderedServicePath rsp = getRspforSfp(sfpName);
-        String rspName = sfp.getName().getValue() + "_rsp";
+        RenderedServicePath rsp = getRenderedServicePath(entry);
         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;
-            }
-
-            // 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,
-                                                             this.getRspId(rspNameRev));
-                if (rspReverse == null) {
-                    rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
-                    if (rspReverse == null) {
-                        LOG.warn("failed to add reverse RSP");
-                        return;
-                    }
-                }
-            }
+            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!!", sfpName);
+            LOG.warn("Service Path = {} has empty hops!!", rsp.getName());
             return;
         }
 
@@ -229,10 +192,10 @@ public class NetvirtSfcStandaloneOF13Provider implements INetvirtSfcOF13Provider
                 // 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(rspName));
+                        .readRenderedServicePathFirstHop(new RspName(rsp.getName()));
 
                 LOG.debug("First Hop IPAddress = {}, Port = {}", firstRspHop.getIp().getIpv4Address().getValue(),
-                        firstRspHop.getPort().getValue().intValue());
+                        firstRspHop.getPort().getValue());
 
                 NshUtils nshHeader = new NshUtils();
                 // C1 is the normal overlay dest ip and c2 is the vnid
@@ -293,6 +256,81 @@ public class NetvirtSfcStandaloneOF13Provider implements INetvirtSfcOF13Provider
         }
     }
 
+    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 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.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 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 = 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,
+                        getRspId(rspNameRev));
+                if (rspReverse == null) {
+                    rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
+                    if (rspReverse == null) {
+                        LOG.warn("failed to add reverse RSP");
+                        return null;
+                    }
+                }
+            }
+        }
+        return rsp;
+    }
+
     private void handleLocalEgressPort(long dataPathId, String s, long localOfPort, short writeTable,
                                        short gotoTable, boolean write) {
 
@@ -407,7 +445,8 @@ public class NetvirtSfcStandaloneOF13Provider implements INetvirtSfcOF13Provider
         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);
     }
index bc0140fa79893c8ba1279929a3a6bdbe5223cbb7..7ebdd6dfcd1b095490e0141d22d44c38852f6e25 100644 (file)
@@ -11,12 +11,16 @@ package org.opendaylight.ovsdb.openstack.netvirt.sfc.standalone.openflow13.servi
 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 {
+public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface, ISfcClassifierService {
     private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
 
     public SfcClassifierService(Service service) {
@@ -34,4 +38,39 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
 
     @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 programEgressClassifier2(long dataPathId, long vxGpeOfPort, long nsp, short nsi, int tunnelOfPort, 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..56aa8f7
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * 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;
+        }
+
+        handleRenderedServicePath2(rsp, entry);
+    }
+
+    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);
+
+        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.programEgressClassifier1(dataPathId, vxGpeOfPort, rsp.getPathId(),
+                    lastServiceindex, (int)sfOfPort, 0, (short)0, true);
+            sfcClassifierService.programEgressClassifier2(dataPathId, vxGpeOfPort, rsp.getPathId(),
+                    lastServiceindex, (int)sfOfPort, 0, true);
+
+            sfcClassifierService.programSfcTable(dataPathId, vxGpeOfPort, SFC_TABLE, true);
+        }
+    }
+
+    private void handleRenderedServicePath2(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) {
+                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) {
+            NshUtils nshHeader = new NshUtils();
+            nshHeader.setNshNsp(rsp.getPathId());
+            nshHeader.setNshNsi(firstHop.getServiceIndex());
+            if (isSffOnBridge(bridgeNode, serviceFunctionForwarder)) {
+                Ip ip = sfcUtils.getSfIp(serviceFunction);
+                nshHeader.setNshTunIpDst(ip.getIp().getIpv4Address());
+                nshHeader.setNshTunUdpPort(ip.getPort());
+            } else {
+                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) {
+            short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
+            String sfDplName = sfcUtils.getSfDplName(serviceFunction);
+            long sfOfPort = getSfPort(bridgeNode, sfDplName);
+            sfcClassifierService.programEgressClassifier1(dataPathId, vxGpeOfPort, rsp.getPathId(),
+                    lastServiceindex, (int)sfOfPort, 0, (short)0, true);
+            sfcClassifierService.programEgressClassifier2(dataPathId, vxGpeOfPort, rsp.getPathId(),
+                    lastServiceindex, (int)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)) {
+            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);
+            //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.extractTerminationPointAugmentation(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/NetvirtSfcWorkaroundOF13Provider.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/NetvirtSfcWorkaroundOF13Provider.java
deleted file mode 100644 (file)
index fa26ee5..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * 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.base.Preconditions;
-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.SfcUtils;
-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.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.paths.RenderedServicePath;
-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.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.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 MdsalUtils mdsalUtils;
-    private SfcUtils sfcUtils;
-    private SfcClassifierService sfcClassifierService;
-
-    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);
-    }
-
-    @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!");
-
-        for (Ace ace : acl.getAccessListEntries().getAce()) {
-            processAclEntry(ace, bridges);
-        }
-    }
-
-    @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("add: No Classifiers found");
-            return;
-        }
-
-        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) {
-
-    }
-
-    private void processAclEntry(Ace entry, Bridges bridges) {
-        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;
-        }
-
-        //handleIngressClassifier();
-        //handleEgressClassifier();
-        //handleSfLoopback();
-
-    }
-
-    // loop through sf's:
-    // - program arp responder
-    // - program sf to sff
-    // - program sff to sf
-    private void handleSfWorkaround(RenderedServicePath rsp) {
-
-    }
-
-    private RenderedServicePath getRenderedServicePath (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();
-        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 = {}", sfcRedirect.getRedirectSfc(), 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;
-    }
-
-    private void setDependencies(ServiceReference serviceReference) {
-        nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
-        southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
-        sfcClassifierService = (SfcClassifierService) ServiceHelper.getGlobalInstance(SfcClassifierService.class, this);
-    }
-}
index 59e4c6b658c7d40dfb56b0f456b7b676411a435d..04877504d6a87d22fe4f63e6aebea8da59d9f996 100644 (file)
@@ -8,13 +8,61 @@
 
 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.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;
+    private static int cookieCounter = 0;
+    private static final int FLOW_INGRESSCLASS = 1;
+    private static final int FLOW_SFINGRESS = 2;
+    private static final int FLOW_SFEGRESS = 3;
+    private static final int FLOW_SFARP = 4;
+    private static final int FLOW_EGRESSCLASS1 = 5;
+    private static final int FLOW_EGRESSCLASS2 = 6;
+    private static final int FLOW_SFCTABLE = 7;
 
-public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface {
     public SfcClassifierService(Service service) {
         super(service);
     }
@@ -25,9 +73,470 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
 
     @Override
     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
-        super.setDependencies(bundleContext.getServiceReference(SfcClassifierService.class.getName()), this);
+        super.setDependencies(bundleContext.getServiceReference(ISfcClassifierService.class.getName()), this);
     }
 
     @Override
     public void setDependencies(Object impl) {}
+
+    private BigInteger getCookie(int index) {
+        String indexString = new String().format("%02d0000000000%04d", index, cookieCounter++);
+        return new BigInteger(indexString, 16);
+    }
+
+    @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);
+        flowBuilder.setMatch(MatchUtils.addNxRegMatch(
+                matchBuilder,
+                new MatchUtils.RegMatch(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL)).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(FLOW_INGRESSCLASS)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(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();
+        flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort).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(FLOW_SFCTABLE)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(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);
+        flowBuilder.setMatch(MatchUtils.addNxNsiMatch(matchBuilder, nsi).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(FLOW_EGRESSCLASS1)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(FLOW_EGRESSCLASS1)));
+
+        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);
+        }
+    }
+
+    // add 3: same match, add in_port sf, priority=40k, move c2 to tun_id, reg0-1, nsp=0,nsi=0
+    @Override
+    public void programEgressClassifier2(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                         int tunnelOfPort, int tunnelId, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
+        MatchUtils.addNxRegMatch(matchBuilder,
+                new MatchUtils.RegMatch(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL)).build();
+        MatchUtils.addNxNspMatch(matchBuilder, nsp);
+        flowBuilder.setMatch(MatchUtils.addNxNsiMatch(matchBuilder, nsi).build());
+
+        String flowId = "sfcEgressClass2_" + vxGpeOfPort;
+        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(FLOW_EGRESSCLASS2)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(FLOW_EGRESSCLASS2)));
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            List<Action> actionList = Lists.newArrayList();
+
+            ActionBuilder ab = new ActionBuilder();
+
+            // don't do this, need it to match on the resubmit side and get past table 10 so it isn't reclassified
+            //ab.setAction(ActionUtils.nxSetNspAction((long)(0)));
+            //ab.setOrder(0);
+            //ab.setKey(new ActionKey(0));
+            //actionList.add(ab.build());
+
+            ab.setAction(ActionUtils.nxResubmitAction(tunnelOfPort, 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);
+        }
+    }
+
+    // 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);
+        flowBuilder.setMatch(MatchUtils.addNxRegMatch(
+                matchBuilder, new MatchUtils.RegMatch(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL)).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(FLOW_SFEGRESS)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(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));
+        flowBuilder.setMatch(MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort).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(FLOW_SFINGRESS)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(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.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(FLOW_SFARP)));
+        flowBuilder.setCookieMask(new FlowCookie(getCookie(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(0x02L)));
+            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 a53c1bbcb3989930600302206d3717af61c438f1..b11229488209acc704c7c528d2351760161da569 100644 (file)
@@ -25,9 +25,12 @@ import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configure
 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;
@@ -44,6 +47,8 @@ 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;
@@ -56,21 +61,22 @@ 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.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.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.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.Dpi;
+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;
@@ -128,6 +134,8 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     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;
@@ -146,6 +154,25 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     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";
+    private static final String SFF2IP = "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() {
@@ -212,6 +239,9 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
                         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()),
@@ -219,7 +249,10 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
                         "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc",
                         LogLevel.TRACE.name()),
                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
-                        "log4j.logger.org.opendaylight.ovsdb.sfc",
+                        "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());
     }
@@ -331,31 +364,33 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         assertTrue(true);
     }
 
-    private AccessListsBuilder setAccessLists () {
+    private AccessListsBuilder accessListsBuilder() {
         MatchesBuilder matchesBuilder = aclUtils.matchesBuilder(new MatchesBuilder(), 80);
-        ActionsBuilder actionsBuilder = aclUtils.actionsBuilder(new ActionsBuilder(), Boolean.TRUE);
-        AceBuilder accessListEntryBuilder = aclUtils.aceBuilder(
-                new AceBuilder(), "http", matchesBuilder, actionsBuilder);
-        AccessListEntriesBuilder accessListEntriesBuilder = aclUtils.accessListEntriesBuidler(
-                new AccessListEntriesBuilder(), accessListEntryBuilder);
-        AclBuilder accessListBuilder = aclUtils.aclBuilder(new AclBuilder(),
-                "http", accessListEntriesBuilder);
-        AccessListsBuilder accessListsBuilder = aclUtils.accessListsBuidler(new AccessListsBuilder(),
-                accessListBuilder);
+        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() throws InterruptedException {
-        testModel(setAccessLists(), AccessLists.class, 0);
+        testModel(accessListsBuilder(), AccessLists.class, 0);
     }
 
-    private ClassifiersBuilder setClassifiers() {
-        SffBuilder sffBuilder = classifierUtils.sffBuilder(new SffBuilder(), "sffname");
+    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);
+                "classifierName", ACLNAME, sffsBuilder);
         ClassifiersBuilder classifiersBuilder = classifierUtils.ClassifiersBuilder(new ClassifiersBuilder(),
                 classifierBuilder);
         LOG.info("Classifiers: {}", classifiersBuilder.build());
@@ -364,7 +399,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
 
     @Test
     public void testClassifiers() throws InterruptedException {
-        testModel(setClassifiers(), Classifiers.class, 0);
+        testModel(classifiersBuilder(), Classifiers.class, 0);
     }
 
     private SfcBuilder netvirtSfcBuilder() {
@@ -376,41 +411,55 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         testModel(netvirtSfcBuilder(), Sfc.class, 0);
     }
 
-    private <T extends DataObject> void testModel(Builder<T> builder, Class<T> clazz, long wait)
-            throws InterruptedException {
+    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);
-        Thread.sleep(wait);
+    }
+
+    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() {
-        SfDataPlaneLocatorBuilder sfDataPlaneLocator =
-                serviceFunctionUtils.sfDataPlaneLocatorBuilder(new SfDataPlaneLocatorBuilder(),
-                        "192.168.120.31", 6633, "testDpl1-1234-uuid", "testSff1");
-        List<SfDataPlaneLocator> sfDataPlaneLocatorList = serviceFunctionUtils.list(
-                new ArrayList<SfDataPlaneLocator>(), sfDataPlaneLocator);
+        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.serviceFunctionBuidler(new ServiceFunctionBuilder(),
-                        "192.168.120.31", "testSf", sfDataPlaneLocatorList, Firewall.class);
+                serviceFunctionUtils.serviceFunctionBuilder(sf1Ip, port, sf1DplName, sff1Name, sf1Name);
         List<ServiceFunction> serviceFunctionList = serviceFunctionUtils.list(
                 new ArrayList<ServiceFunction>(), serviceFunctionBuilder);
 
-        sfDataPlaneLocator =
-                serviceFunctionUtils.sfDataPlaneLocatorBuilder(new SfDataPlaneLocatorBuilder(),
-                        "192.168.120.32", 6633, "testDpl2-1234-uuid", "testSff2");
-        sfDataPlaneLocatorList = serviceFunctionUtils.list(
-                new ArrayList<SfDataPlaneLocator>(), sfDataPlaneLocator);
-        serviceFunctionBuilder =
-                serviceFunctionUtils.serviceFunctionBuidler(new ServiceFunctionBuilder(),
-                        "192.168.120.32", "testSf2", sfDataPlaneLocatorList, Dpi.class);
-        serviceFunctionList = serviceFunctionUtils.list(
-                serviceFunctionList, serviceFunctionBuilder);
+        //serviceFunctionBuilder =
+        //        serviceFunctionUtils.serviceFunctionBuilder(sf2Ip, port, sffDpl2Name, sff2Name, sf2Name);
+        //serviceFunctionList = serviceFunctionUtils.list(
+        //        serviceFunctionList, serviceFunctionBuilder);
 
         ServiceFunctionsBuilder serviceFunctionsBuilder =
                 serviceFunctionUtils.serviceFunctionsBuilder(new ServiceFunctionsBuilder(),
@@ -420,39 +469,35 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     }
 
     private ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder() {
-        String sf1Name = "firewall-72";
-        String sff1Ip = "192.168.120.31";
-        String sff1Name = "SFF1";
-        String sffDpl1Name = "sfc-tun2";
-        String sn1Name = "OVSDB2";
-        String bridge1Name= "sw2";
-        int port = 6633;
-
-        DataPlaneLocatorBuilder dataPlaneLocatorBuilder =
-                serviceFunctionForwarderUtils.dataPlaneLocatorBuilder(
-                        new DataPlaneLocatorBuilder(), sff1Ip, port);
-        SffDataPlaneLocatorBuilder sffDataPlaneLocatorBuilder =
-                serviceFunctionForwarderUtils.sffDataPlaneLocatorBuilder(
-                        new SffDataPlaneLocatorBuilder(), dataPlaneLocatorBuilder, sffDpl1Name);
-        List<SffDataPlaneLocator> sffDataPlaneLocatorList = serviceFunctionForwarderUtils.list(
-                new ArrayList<SffDataPlaneLocator>(), sffDataPlaneLocatorBuilder);
-
-        SffSfDataPlaneLocatorBuilder sffSfDataPlaneLocatorBuilder =
-                serviceFunctionForwarderUtils.sffSfDataPlaneLocatorBuilder(
-                        new SffSfDataPlaneLocatorBuilder(), sff1Ip, port);
-        ServiceFunctionDictionaryBuilder serviceFunctionDictionaryBuilder =
-                serviceFunctionForwarderUtils.serviceFunctionDictionaryBuilder(
-                        new ServiceFunctionDictionaryBuilder(), sf1Name, Firewall.class,
-                        sffSfDataPlaneLocatorBuilder);
-        List<ServiceFunctionDictionary> serviceFunctionDictionaryList = serviceFunctionForwarderUtils.list(
-                new ArrayList<ServiceFunctionDictionary>(), serviceFunctionDictionaryBuilder);
+        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(
-                        new ServiceFunctionForwarderBuilder(), sff1Name, sn1Name, bridge1Name,
-                        sffDataPlaneLocatorList, serviceFunctionDictionaryList);
+                        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);
@@ -460,10 +505,107 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         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));
     }
 
     /*
@@ -662,17 +804,36 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         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);
+                LOG.info("getFlow: flow: {}: {}", store, flow);
                 break;
             }
             Thread.sleep(1000);
         }
         return flow;
     }
+
+    private void readwait() {
+        try {
+            System.in.read();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
 }
index bae8a7261bd355da8b155113a7ff4e39b621bec6..7657f2eee31f6ee07089e16679a761ba7d4d3544 100644 (file)
@@ -23,6 +23,8 @@ 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.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 extends AbstractUtils {
     public MatchesBuilder matchesBuilder(MatchesBuilder matchesBuilder, int destPort) {
@@ -43,6 +45,12 @@ public class AclUtils extends AbstractUtils {
         return actionsBuilder.setPacketHandling(new PermitBuilder().setPermit(permit).build());
     }
 
+    public ActionsBuilder actionsBuilder(ActionsBuilder actionsBuilder, String sfcName) {
+        RedirectToSfcBuilder redirectToSfcBuilder = new RedirectToSfcBuilder().setSfcName(sfcName);
+
+        return actionsBuilder.addAugmentation(RedirectToSfc.class, redirectToSfcBuilder.build());
+    }
+
     public AceBuilder aceBuilder(AceBuilder accessListEntryBuilder,
                                  String ruleName,
                                  MatchesBuilder matchesBuilder,
@@ -54,27 +62,26 @@ public class AclUtils extends AbstractUtils {
     }
 
     public AccessListEntriesBuilder accessListEntriesBuidler(AccessListEntriesBuilder accessListEntriesBuilder,
-                                                             AceBuilder accessListEntryBuilder) {
-        List<Ace> accessListEntriesList = new ArrayList<>();
-        accessListEntriesList.add(accessListEntryBuilder.build());
+                                                             AceBuilder aceBuilder) {
+        List<Ace> aceList = new ArrayList<>();
+        aceList.add(aceBuilder.build());
 
-        return accessListEntriesBuilder;
+        return accessListEntriesBuilder.setAce(aceList);
     }
 
-    public AclBuilder aclBuilder(AclBuilder accessListBuilder,
+    public AclBuilder aclBuilder(AclBuilder aclBuilder,
                                  String aclName,
                                  AccessListEntriesBuilder accessListEntriesBuilder) {
-        return accessListBuilder
+        return aclBuilder
                 .setAclName(aclName)
                 .setAccessListEntries(accessListEntriesBuilder.build());
     }
 
-    public AccessListsBuilder accessListsBuidler(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);
     }
 }
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);
+    }
+}
index 0d92935b2732496e390241d4a0d47afeba6a81d2..79f3a69d7dec8cfeb9146b3e730445a7e8ebd7bd 100644 (file)
@@ -8,13 +8,17 @@
 
 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;
@@ -27,6 +31,8 @@ import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev1407
 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) {
@@ -76,17 +82,25 @@ public class ServiceFunctionForwarderUtils extends AbstractUtils {
                 .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);
+                .setSffDataPlaneLocator(sffDataPlaneLocatorList)
+                .addAugmentation(SffOvsBridgeAugmentation.class, sffOvsBridgeAugmentationBuilder.build());
     }
 
     public ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder(
@@ -94,4 +108,31 @@ public class ServiceFunctionForwarderUtils extends AbstractUtils {
             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);
+    }
+}
index 6c70675d01bf709529ecff4bd57189f8bf6f17ce..39f38387b85915e824f68947fd188b64186619ee 100644 (file)
@@ -8,6 +8,7 @@
 
 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;
@@ -17,6 +18,7 @@ import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev14070
 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;
@@ -31,7 +33,7 @@ public class ServiceFunctionUtils extends AbstractUtils {
                 .setServiceFunctionForwarder(new SffName(sffName));
     }
 
-    public ServiceFunctionBuilder serviceFunctionBuidler(ServiceFunctionBuilder serviceFunctionBuilder,
+    public ServiceFunctionBuilder serviceFunctionBuilder(ServiceFunctionBuilder serviceFunctionBuilder,
                                                          String ip, String sfName,
                                                          List<SfDataPlaneLocator> sfDataPlaneLocatorList,
                                                          Class<? extends ServiceFunctionTypeIdentity> type) {
@@ -47,4 +49,16 @@ public class ServiceFunctionUtils extends AbstractUtils {
                                                            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 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 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) {
index 2ab09e90799eb2e192a4360a4a32ae9434e32c99..c11a620a5ee6d2e23eaea3c940fe4af3e4fdbb96 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta
 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;
@@ -26,6 +27,8 @@ 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;
@@ -33,6 +36,9 @@ 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 String getNodeName(long dpidLong) {
         return OPENFLOW + ":" + dpidLong;
@@ -42,6 +48,10 @@ public class FlowUtils {
         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));
     }
@@ -80,7 +90,7 @@ public class FlowUtils {
             LOG.error(e.getMessage(), e);
         }
 
-        LOG.info("Cannot find data for Flow {}", flowBuilder.getFlowName());
+        LOG.info("Cannot find data for Flow {} in {}", flowBuilder.getFlowName(), store);
         return null;
     }
 
index 9d61386b8efba1be8e6610cd4e9ea1bd3630d0d3..1bfde3e21f20e8897f2354d8d9b03d8843a626ba 100644 (file)
@@ -113,7 +113,7 @@ public class InstructionUtils {
     }
 
     /**
-     * Create NORMAL Reserved Port Instruction (packet_in)
+     * Create LOCAL Reserved Port Instruction
      *
      * @param nodeName Uri Prefix, containing nodeConnectorType and dpId (aka NodeId)
      * @param ib Map InstructionBuilder without any instructions
@@ -144,6 +144,35 @@ public class InstructionUtils {
         return ib;
     }
 
+    /**
+     * Create NORMAL Reserved Port Instruction (packet_in)
+     *
+     * @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 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);
+    }
 }