Merge "Use ClusteredDataTreeListener in hwvtepsb"
authorSam Hague <shague@redhat.com>
Wed, 13 Jan 2016 00:23:23 +0000 (00:23 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 13 Jan 2016 00:23:23 +0000 (00:23 +0000)
48 files changed:
features/pom.xml
features/src/main/features/features.xml
karaf/pom.xml
openstack/net-virt-it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/it/NetvirtIT.java
openstack/net-virt-providers/pom.xml
openstack/net-virt-providers/src/main/config/default-config.xml
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/ConfigActivator.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/NetvirtProvidersConfigImpl.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/NetvirtProvidersProvider.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/AbstractServiceInstance.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/OF13Provider.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/PipelineOrchestrator.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/PipelineOrchestratorImpl.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/ClassifierService.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/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/providers/impl/rev150513/NetvirtProvidersImplModule.java
openstack/net-virt-providers/src/main/yang/netvirt-providers-config.yang [new file with mode: 0644]
openstack/net-virt-providers/src/main/yang/netvirt-providers-impl.yang
openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/NetvirtProvidersProviderTest.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/AbstractServiceInstanceTest.java
openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/PipelineOrchestratorImplTest.java
openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/IngressAclServiceTest.java
openstack/net-virt-sfc/impl/pom.xml
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/NetvirtSfcWorkaroundOF13Provider.java
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/pom.xml
openstack/net-virt/src/main/config/default-config.xml
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/ClusterAwareMdsalUtils.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/ConfigActivator.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NetvirtProvider.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/ClassifierProvider.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/Constants.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/IngressAclProvider.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/SecurityServicesManager.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/OvsdbInventoryServiceImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SecurityServicesImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SouthboundImpl.java
openstack/net-virt/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/impl/rev150513/NetvirtImplModule.java
openstack/net-virt/src/main/yang/netvirt-impl.yang
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterfaceTest.java [new file with mode: 0644]
utils/config/pom.xml
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/ActionUtils.java
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/MatchUtils.java
utils/servicehelper/pom.xml

index e85dcea5750b73a3b8050142460d2d164bb59edd..8b00cff0d62bd26a9c5d55d226840583210c058e 100644 (file)
@@ -237,6 +237,23 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <classifier>features</classifier>
       <type>xml</type>
     </dependency>
+
+    <!-- openflowplugin dependencies for net-virt clustering-->
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>features-openflowplugin-li</artifactId>
+      <version>${openflowplugin.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>features-openflowplugin-extension-li</artifactId>
+      <version>${openflowplugin.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+
     <!-- project specific dependencies -->
     <dependency>
       <groupId>${project.groupId}</groupId>
index 466fecd57822e921e09aa6d77fed6209bddc4772..84371f2fb542a3e4b2f32ba623bc32b46a24b62a 100644 (file)
@@ -4,6 +4,8 @@
           xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
   <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension/{{VERSION}}/xml/features</repository>
   <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension-li/{{VERSION}}/xml/features</repository>
+  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin-li/{{VERSION}}/xml/features</repository>
   <repository>mvn:org.opendaylight.neutron/features-neutron/{{VERSION}}/xml/features</repository>
   <repository>mvn:org.opendaylight.ovsdb/southbound-features/1.2.1-SNAPSHOT/xml/features</repository>
   <repository>mvn:org.opendaylight.controller/features-mdsal/{{VERSION}}/xml/features</repository>
     <configfile finalname="etc/opendaylight/karaf/netvirt-impl-default-config.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt/{{VERSION}}/xml/config</configfile>
     <configfile finalname="etc/opendaylight/karaf/netvirt-providers-impl-default-config.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt-providers/{{VERSION}}/xml/config</configfile>
   </feature>
+
+  <feature name="odl-ovsdb-openstack-clusteraware" description="OpenDaylight :: OVSDB :: OpenStack Network Virtualization - Cluster Aware"
+           version='${project.version}'>
+    <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-nsf-model-li</feature>
+    <feature version="${neutron.version}">odl-neutron-service</feature>
+    <feature version="${project.version}">odl-ovsdb-southbound-impl-ui</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services-li</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-nxm-extensions-li</feature>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.servicehelper/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.neutron-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.southbound-utils/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-providers/{{VERSION}}</bundle>
+    <bundle>mvn:org.opendaylight.neutron/dummyprovider/{{VERSION}}</bundle>
+    <configfile finalname="etc/opendaylight/karaf/netvirt-impl-default-config.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt/{{VERSION}}/xml/config</configfile>
+    <configfile finalname="etc/opendaylight/karaf/netvirt-providers-impl-default-config.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt-providers/{{VERSION}}/xml/config</configfile>
+  </feature>
+
   <feature name="odl-ovsdb-ui" description="OpenDaylight :: OVSDB :: DLUX Integration Plugin" version='${project.version}'>
     <feature version="${dlux.version}">odl-dlux-core</feature>
     <bundle>mvn:org.opendaylight.ovsdb/ovsdb-ui-bundle/{{VERSION}}</bundle>
index 536535cd2f049625fa91546fba964bf6915f862c..f1248e80967deacc794f6470d88d89b05e4ff920 100644 (file)
@@ -26,7 +26,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   </prerequisites>
   <properties>
     <!-- uncomment the next line if you want karaf to automatically load the feature -->
-    <karaf.localFeature>odl-ovsdb-openstack</karaf.localFeature>
+    <!-- <karaf.localFeature>odl-ovsdb-openstack</karaf.localFeature> -->
   </properties>
   <description>The OVSDB Plugin integration project is a project for OpenDaylight that will implement the Open vSwitch Database RFC 7047 management protocol allowing the Southbound configuration of vSwitches and a network virtualization implementation.</description>
   <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
index 2bef4e5279ad4908b3ee27f83c5e8a43d9152d26..f35a1f1050bf00ab939202334a62db51f43c0f19 100644 (file)
@@ -26,11 +26,7 @@ import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRunti
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.UnknownHostException;
 import java.util.ArrayList;
-import java.util.Enumeration;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -56,12 +52,10 @@ import org.opendaylight.neutron.spi.NeutronSubnet;
 import org.opendaylight.ovsdb.lib.notation.Version;
 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
-import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.NetvirtProvidersProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
-import org.opendaylight.ovsdb.southbound.SouthboundMapper;
-import org.opendaylight.ovsdb.utils.config.ConfigProperties;
 import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
@@ -72,19 +66,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
 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.InterfaceTypeEntryBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
 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.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.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.Option;
@@ -105,7 +92,6 @@ import org.slf4j.LoggerFactory;
 @ExamReactorStrategy(PerClass.class)
 public class NetvirtIT extends AbstractMdsalTestBase {
     private static final Logger LOG = LoggerFactory.getLogger(NetvirtIT.class);
-    private static final int OVSDB_UPDATE_TIMEOUT = 1000;
     private static DataBroker dataBroker = null;
     private static String addressStr;
     private static String portStr;
@@ -114,6 +100,7 @@ public class NetvirtIT extends AbstractMdsalTestBase {
     private static AtomicBoolean setup = new AtomicBoolean(false);
     private static MdsalUtils mdsalUtils = null;
     private static Southbound southbound = null;
+    private static PipelineOrchestrator pipelineOrchestrator = null;
     private static SouthboundUtils southboundUtils;
     private static NeutronUtils neutronUtils = new NeutronUtils();
     private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
@@ -258,6 +245,9 @@ public class NetvirtIT extends AbstractMdsalTestBase {
         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
         assertNotNull("southbound should not be null", southbound);
         southboundUtils = new SouthboundUtils(mdsalUtils);
+        pipelineOrchestrator =
+                (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
+        assertNotNull("pipelineOrchestrator should not be null", pipelineOrchestrator);
         setup.set(true);
     }
 
@@ -348,11 +338,15 @@ public class NetvirtIT extends AbstractMdsalTestBase {
         return true;
     }
 
+    // This is an extra test for local testing and testNetVirt covers this is more detail
+    @Ignore
     @Test
     public void testAddDeleteOvsdbNode() throws InterruptedException {
         LOG.info("testAddDeleteOvsdbNode enter");
         ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
-        connectOvsdbNode(connectionInfo);
+        Node ovsdbNode = connectOvsdbNode(connectionInfo);
+        assertNotNull("connection failed", ovsdbNode);
+        LOG.info("testNetVirt: should be connected: {}", ovsdbNode.getNodeId());
 
         assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
                 + " is not connected", isControllerConnected(connectionInfo));
@@ -363,6 +357,51 @@ public class NetvirtIT extends AbstractMdsalTestBase {
         LOG.info("testAddDeleteOvsdbNode exit");
     }
 
+    // TODO add tests for when L3 is enabled and check for br-ex
+
+    // This is an extra test for local testing and testNetVirt covers this is more detail
+    @Ignore
+    @Test
+    public void testAddDeleteOvsdbNodeWithTableOffset() throws InterruptedException {
+        LOG.info("testAddDeleteOvsdbNodeWithTableOffset enter");
+        NetvirtProvidersProvider.setTableOffset((short)1);
+        ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
+        Node ovsdbNode = connectOvsdbNode(connectionInfo);
+        assertNotNull("connection failed", ovsdbNode);
+        LOG.info("testNetVirt: should be connected: {}", ovsdbNode.getNodeId());
+
+        assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
+                + " is not connected", isControllerConnected(connectionInfo));
+
+        // Verify the pipeline flows were installed
+        Node bridgeNode = southbound.getBridgeNode(ovsdbNode, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
+        assertNotNull("bridge " + NetvirtITConstants.INTEGRATION_BRIDGE_NAME + " was not found", bridgeNode);
+        long datapathId = southbound.getDataPathId(bridgeNode);
+        String datapathIdString = southbound.getDatapathId(bridgeNode);
+        LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
+        assertNotEquals("datapathId was not found", datapathId, 0);
+
+        List<Service> staticPipeline = pipelineOrchestrator.getStaticPipeline();
+        List<Service> staticPipelineFound = Lists.newArrayList();
+        for (Service service : pipelineOrchestrator.getServiceRegistry().keySet()) {
+            if (staticPipeline.contains(service)) {
+                staticPipelineFound.add(service);
+            }
+            String flowId = "DEFAULT_PIPELINE_FLOW_" + pipelineOrchestrator.getTable(service);
+            verifyFlow(datapathId, flowId, service);
+        }
+        assertEquals("did not find all expected flows in static pipeline",
+                staticPipeline.size(), staticPipelineFound.size());
+
+        String flowId = "TableOffset_" + pipelineOrchestrator.getTable(Service.CLASSIFIER);
+        verifyFlow(datapathId, flowId, Service.CLASSIFIER.getTable());
+
+        Assert.assertTrue(southboundUtils.deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
+        Thread.sleep(1000);
+        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+        LOG.info("testAddDeleteOvsdbNodeWithTableOffset exit");
+    }
+
     private boolean isControllerConnected(ConnectionInfo connectionInfo) throws InterruptedException {
         LOG.info("isControllerConnected enter");
         Boolean connected = false;
@@ -372,7 +411,7 @@ public class NetvirtIT extends AbstractMdsalTestBase {
 
         BridgeConfigurationManager bridgeConfigurationManager =
                 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
-        assertNotNull("Could not find PipelineOrchestrator Service", bridgeConfigurationManager);
+        assertNotNull("Could not find BridgeConfigurationManager Service", bridgeConfigurationManager);
         String controllerTarget = bridgeConfigurationManager.getControllersFromOvsdbNode(ovsdbNode).get(0);
         Assert.assertNotNull("Failed to get controller target", controllerTarget);
 
@@ -434,20 +473,19 @@ public class NetvirtIT extends AbstractMdsalTestBase {
         LOG.info("testNetVirt: starting test");
         ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
         Node ovsdbNode = connectOvsdbNode(connectionInfo);
-        LOG.info("testNetVirt: should be connected");
+        assertNotNull("connection failed", ovsdbNode);
+        LOG.info("testNetVirt: should be connected: {}", ovsdbNode.getNodeId());
 
         //TODO use controller value rather that ovsdb connectionInfo or change log
         assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
                 + " is not connected", isControllerConnected(connectionInfo));
 
         // Verify the pipeline flows were installed
-        PipelineOrchestrator pipelineOrchestrator =
-                (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
-        assertNotNull("Could not find PipelineOrchestrator Service", pipelineOrchestrator);
         Node bridgeNode = southbound.getBridgeNode(ovsdbNode, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
         assertNotNull("bridge " + NetvirtITConstants.INTEGRATION_BRIDGE_NAME + " was not found", bridgeNode);
-        LOG.info("testNetVirt: bridgeNode: {}", bridgeNode);
         long datapathId = southbound.getDataPathId(bridgeNode);
+        String datapathIdString = southbound.getDatapathId(bridgeNode);
+        LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
         assertNotEquals("datapathId was not found", datapathId, 0);
 
         List<Service> staticPipeline = pipelineOrchestrator.getStaticPipeline();
@@ -456,8 +494,8 @@ public class NetvirtIT extends AbstractMdsalTestBase {
             if (staticPipeline.contains(service)) {
                 staticPipelineFound.add(service);
             }
-            String flowId = "DEFAULT_PIPELINE_FLOW_" + service.getTable();
-            verifyFlow(datapathId, flowId, service.getTable());
+            String flowId = "DEFAULT_PIPELINE_FLOW_" + pipelineOrchestrator.getTable(service);
+            verifyFlow(datapathId, flowId, service);
         }
         assertEquals("did not find all expected flows in static pipeline",
                 staticPipeline.size(), staticPipelineFound.size());
@@ -467,7 +505,6 @@ public class NetvirtIT extends AbstractMdsalTestBase {
         OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
                 southbound.getTerminationPointOfBridge(bridgeNode, NetvirtITConstants.PORT_NAME);
         Assert.assertNotNull("Did not find " + NetvirtITConstants.PORT_NAME, ovsdbTerminationPointAugmentation);
-        Thread.sleep(1000);
         Assert.assertTrue(southboundUtils.deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
         Thread.sleep(1000);
         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
@@ -484,9 +521,9 @@ public class NetvirtIT extends AbstractMdsalTestBase {
         final String dhcpPortId ="521e29d6-67b8-4b3c-8633-027d21195115";
 
         ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
-        assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
         Node ovsdbNode = connectOvsdbNode(connectionInfo);
-        assertNotNull("node is not connected", ovsdbNode);
+        assertNotNull("connection failed", ovsdbNode);
+        LOG.info("testNetVirtFixedSG: should be connected: {}", ovsdbNode.getNodeId());
 
         // Verify the minimum version required for this test
         OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
@@ -509,6 +546,8 @@ public class NetvirtIT extends AbstractMdsalTestBase {
         Node bridgeNode = southbound.getBridgeNode(ovsdbNode, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
         assertNotNull("bridge " + NetvirtITConstants.INTEGRATION_BRIDGE_NAME + " was not found", bridgeNode);
         long datapathId = southbound.getDataPathId(bridgeNode);
+        String datapathIdString = southbound.getDatapathId(bridgeNode);
+        LOG.info("testNetVirtFixedSG: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
         assertNotEquals("datapathId was not found", datapathId, 0);
 
         NeutronNetwork nn = neutronUtils.createNeutronNetwork(networkId, tenantId,
@@ -533,7 +572,7 @@ public class NetvirtIT extends AbstractMdsalTestBase {
         Thread.sleep(1000);
 
         String flowId = "Egress_DHCP_Client"  + "_Permit_";
-        verifyFlow(datapathId, flowId, Service.EGRESS_ACL.getTable());
+        verifyFlow(datapathId, flowId, Service.EGRESS_ACL);
 
         testDefaultSG(nport, datapathId, nn, tenantId, portId);
         Thread.sleep(1000);
@@ -596,10 +635,10 @@ public class NetvirtIT extends AbstractMdsalTestBase {
 
         Thread.sleep(10000);
         String flowId = "Egress_IP" + nn.getProviderSegmentationID() + "_" + nport.getMacAddress() + "_Permit_";
-        verifyFlow(datapathId, flowId, Service.EGRESS_ACL.getTable());
+        verifyFlow(datapathId, flowId, Service.EGRESS_ACL);
 
         flowId = "Ingress_IP" + nn.getProviderSegmentationID() + "_" + nport.getMacAddress() + "_Permit_";
-        verifyFlow(datapathId, flowId, Service.INGRESS_ACL.getTable());
+        verifyFlow(datapathId, flowId, Service.INGRESS_ACL);
     }
 
     private Flow getFlow (
@@ -629,6 +668,11 @@ public class NetvirtIT extends AbstractMdsalTestBase {
         Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
         assertNotNull("Could not find flow in config: " + flowBuilder.build() + "--" + nodeBuilder.build(), flow);
         flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
-        assertNotNull("Could not find flow in operational: " + flowBuilder.build() + "--" + nodeBuilder.build(), flow);
+        assertNotNull("Could not find flow in operational: " + flowBuilder.build() + "--" + nodeBuilder.build(),
+                flow);
+    }
+
+    private void verifyFlow(long datapathId, String flowId, Service service) throws InterruptedException {
+        verifyFlow(datapathId, flowId, pipelineOrchestrator.getTable(service));
     }
 }
index 2d7a664cfcd42835b5988c365ceb1c4bb89f2dd5..034fb03eac9dff79be2f5143b5c1936f713c1215 100644 (file)
@@ -46,7 +46,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <properties>
     <liblldp.version>0.10.0-SNAPSHOT</liblldp.version>
     <openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
-    <powermock.version>1.5.2</powermock.version>
+    <powermock.version>1.6.4</powermock.version>
     <sonar.jacoco.itReportPath>../net-virt-it/target/jacoco-it.exec</sonar.jacoco.itReportPath>
   </properties>
 
@@ -149,6 +149,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
+      <version>1.10.19</version>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -220,6 +221,24 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           </properties>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-instrument</id>
+            <goals>
+              <goal>instrument</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-restore-instrumented-classes</id>
+            <goals>
+              <goal>restore-instrumented-classes</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>
index cdbbec28ac687f3d52eb39724e73005604262ecc..50c4d778ff8743f9411b1e3020c3f528a0101731 100644 (file)
@@ -13,6 +13,7 @@
         <module>
           <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:netvirt:providers:impl">prefix:netvirt-providers-impl</type>
           <name>netvirt-providers-default</name>
+          <table-offset>0</table-offset>
           <broker>
             <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
             <name>binding-osgi-broker</name>
index 9da80ffdfbe041867f56fc465ad19bb7808633d1..690fee05227767f054af06379c5c814ef7caa10d 100644 (file)
@@ -8,6 +8,12 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.providers;
 
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.ovsdb.openstack.netvirt.api.ArpProvider;
@@ -53,11 +59,6 @@ import org.osgi.util.tracker.ServiceTracker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.List;
-
 public class ConfigActivator implements BundleActivator {
     private static final Logger LOG = LoggerFactory.getLogger(ConfigActivator.class);
     private List<ServiceRegistration<?>> registrations = new ArrayList<>();
@@ -71,6 +72,13 @@ public class ConfigActivator implements BundleActivator {
     public void start(BundleContext context) throws Exception {
         LOG.info("ConfigActivator start:");
 
+        NetvirtProvidersConfigImpl netvirtProvidersConfig =
+                new NetvirtProvidersConfigImpl(providerContext.getSALService(DataBroker.class),
+                        NetvirtProvidersProvider.getTableOffset());
+        registerService(context,
+                new String[] {NetvirtProvidersConfigImpl.class.getName()},
+                null, netvirtProvidersConfig);
+
         PipelineOrchestratorImpl pipelineOrchestrator = new PipelineOrchestratorImpl();
         registerService(context,
                 new String[] {PipelineOrchestrator.class.getName(),NodeCacheListener.class.getName()},
@@ -133,7 +141,7 @@ public class ConfigActivator implements BundleActivator {
                 gatewayMacResolverService, Service.GATEWAY_RESOLVER);
         getNotificationProviderService().registerNotificationListener(gatewayMacResolverService);
 
-
+        netvirtProvidersConfig.setDependencies(context, null);
         pipelineOrchestrator.setDependencies(context, null);
         outboundNatService.setDependencies(context, null);
         egressAclService.setDependencies(context, null);
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/NetvirtProvidersConfigImpl.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/NetvirtProvidersConfigImpl.java
new file mode 100644 (file)
index 0000000..d2536b6
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016 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.providers;
+
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
+import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbInventoryListener;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.providers.config.rev160109.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetvirtProvidersConfigImpl implements AutoCloseable, ConfigInterface, DataChangeListener {
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtProvidersConfigImpl.class);
+    private final DataBroker dataBroker;
+    private final ListenerRegistration<DataChangeListener> registration;
+    private final ExecutorService executorService = Executors.newFixedThreadPool(1);
+    private final MdsalUtils mdsalUtils;
+
+    public NetvirtProvidersConfigImpl(final DataBroker dataBroker, final short tableOffset) {
+        this.dataBroker = dataBroker;
+        mdsalUtils = new MdsalUtils(dataBroker);
+
+        InstanceIdentifier<NetvirtProvidersConfig> path =
+                InstanceIdentifier.builder(NetvirtProvidersConfig.class).build();
+        registration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this,
+                AsyncDataBroker.DataChangeScope.SUBTREE);
+
+        NetvirtProvidersConfigBuilder netvirtProvidersConfigBuilder = new NetvirtProvidersConfigBuilder();
+        NetvirtProvidersConfig netvirtProvidersConfig =
+                mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
+        if (netvirtProvidersConfig != null) {
+            netvirtProvidersConfigBuilder = new NetvirtProvidersConfigBuilder(netvirtProvidersConfig);
+        }
+        if (netvirtProvidersConfigBuilder.getTableOffset() == null) {
+            netvirtProvidersConfigBuilder.setTableOffset(tableOffset);
+        }
+        boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, path,
+                netvirtProvidersConfigBuilder.build());
+
+        LOG.info("NetvirtProvidersConfigImpl: dataBroker= {}, registration= {}, tableOffset= {}, result= {}",
+                dataBroker, registration, tableOffset, result);
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+        executorService.shutdown();
+    }
+
+    @Override
+    public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent) {
+        executorService.submit(new Runnable() {
+
+            @Override
+            public void run() {
+                LOG.info("onDataChanged: {}", asyncDataChangeEvent);
+                processConfigCreate(asyncDataChangeEvent);
+                processConfigUpdate(asyncDataChangeEvent);
+            }
+        });
+    }
+
+    private void processConfigCreate(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> entry : changes.getCreatedData().entrySet()) {
+            if (entry.getValue() instanceof NetvirtProvidersConfig) {
+                NetvirtProvidersConfig netvirtProvidersConfig = (NetvirtProvidersConfig) entry.getValue();
+                applyConfig(netvirtProvidersConfig);
+            }
+        }
+    }
+
+    private void processConfigUpdate(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> entry : changes.getUpdatedData().entrySet()) {
+            if (entry.getValue() instanceof NetvirtProvidersConfig) {
+                LOG.info("processConfigUpdate: {}", entry);
+                NetvirtProvidersConfig netvirtProvidersConfig = (NetvirtProvidersConfig) entry.getValue();
+                applyConfig(netvirtProvidersConfig);
+            }
+        }
+    }
+
+    private void applyConfig(NetvirtProvidersConfig netvirtProvidersConfig) {
+        LOG.info("processConfigUpdate: {}", netvirtProvidersConfig);
+        if (netvirtProvidersConfig.getTableOffset() != null) {
+            NetvirtProvidersProvider.setTableOffset(netvirtProvidersConfig.getTableOffset());
+        }
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
+
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+
+    }
+}
index 86556f6d4873efda77b757f1cfe0630b5796cb9a..e370ed142c8d0aa2962224ebee2f1b0dd891d10d 100644 (file)
@@ -20,6 +20,8 @@ import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipL
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId;
 import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,11 +41,14 @@ public class NetvirtProvidersProvider implements BindingAwareProvider, AutoClose
     private static EntityOwnershipService entityOwnershipService;
     private ProviderEntityListener providerEntityListener = null;
     private static AtomicBoolean hasProviderEntityOwnership = new AtomicBoolean(false);
+    private static short tableOffset;
+    private NetvirtProvidersConfigImpl netvirtProvidersConfig = null;
 
-    public NetvirtProvidersProvider(BundleContext bundleContext, EntityOwnershipService eos) {
+    public NetvirtProvidersProvider(BundleContext bundleContext, EntityOwnershipService eos, short tableOffset) {
         LOG.info("NetvirtProvidersProvider: bundleContext: {}", bundleContext);
         this.bundleContext = bundleContext;
-        entityOwnershipService = eos;
+            entityOwnershipService = eos;
+        setTableOffset(tableOffset);
     }
 
     public static DataBroker getDataBroker() {
@@ -58,6 +63,23 @@ public class NetvirtProvidersProvider implements BindingAwareProvider, AutoClose
         return hasProviderEntityOwnership.get();
     }
 
+    public static void setTableOffset(short tableOffset) {
+        try {
+            new TableId((short) (tableOffset + Service.L2_FORWARDING.getTable()));
+        } catch (IllegalArgumentException e) {
+            LOG.warn("Invalid table offset: {}", tableOffset, e);
+            return;
+        }
+
+        LOG.info("setTableOffset: changing from {} to {}",
+                NetvirtProvidersProvider.tableOffset, tableOffset);
+        NetvirtProvidersProvider.tableOffset = tableOffset;
+    }
+
+    public static short getTableOffset() {
+        return tableOffset;
+    }
+
     @Override
     public void close() throws Exception {
         LOG.info("NetvirtProvidersProvider closed");
index 0727f3e0bfc74ed57068e068d69ebac270a8164c..3835bed28d42acacf7bc3c3e3710c05363276491 100644 (file)
@@ -86,8 +86,21 @@ public abstract class AbstractServiceInstance {
         return bridgeName != null && Constants.INTEGRATION_BRIDGE.equals(bridgeName);
     }
 
+    /**
+     * Return the offset adjusted table for this {@link Service}
+     * @return The table id
+     */
     public short getTable() {
-        return service.getTable();
+        return (short)(orchestrator.getTableOffset() + service.getTable());
+    }
+
+    /**
+     * Return the offset adjusted table for the given {@link Service}
+     * @param service Identifies the openflow {@link Service}
+     * @return The table id
+     */
+    public short getTable(Service service) {
+        return (short)(orchestrator.getTableOffset() + service.getTable());
     }
 
     public Service getService() {
@@ -132,7 +145,8 @@ public abstract class AbstractServiceInstance {
     protected final InstructionBuilder getMutablePipelineInstructionBuilder() {
         Service nextService = orchestrator.getNextServiceInPipeline(service);
         if (nextService != null) {
-            return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
+            return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(),
+                    orchestrator.getTable(nextService));
         } else {
             return InstructionUtils.createDropInstructions(new InstructionBuilder());
         }
@@ -140,19 +154,14 @@ public abstract class AbstractServiceInstance {
 
     protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
         if (NetvirtProvidersProvider.isMasterProviderInstance()) {
-            LOG.debug("writeFlow 3: flowBuilder: {}, nodeBuilder: {}",
+            LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
                     flowBuilder.build(), nodeBuilder.build());
             WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
-            LOG.debug("writeFlow: about to put nodePath for Flow {}, nodePath: {}",
-                    flowBuilder.getFlowName(), createNodePath(nodeBuilder));
             modification.put(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder),
                     nodeBuilder.build(), true /*createMissingParents*/);
-            LOG.debug("writeFlow: about to put Flow {}", flowBuilder.getFlowName());
             modification.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder),
                     flowBuilder.build(), true /*createMissingParents*/);
-            LOG.debug("writeFlow: about to submit Flow {}", flowBuilder.getFlowName());
             CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
-            LOG.debug("writeFlow: checking status of Flow {}", flowBuilder.getFlowName());
             try {
                 commitFuture.checkedGet();  // TODO: Make it async (See bug 1362)
                 LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
@@ -259,13 +268,13 @@ public abstract class AbstractServiceInstance {
         // Add InstructionsBuilder to FlowBuilder
         flowBuilder.setInstructions(isb.build());
 
-        String flowId = "DEFAULT_PIPELINE_FLOW_"+service.getTable();
+        String flowId = "DEFAULT_PIPELINE_FLOW_" + getTable();
         flowBuilder.setId(new FlowId(flowId));
         FlowKey key = new FlowKey(new FlowId(flowId));
         flowBuilder.setMatch(matchBuilder.build());
         flowBuilder.setPriority(0);
         flowBuilder.setBarrier(false);
-        flowBuilder.setTableId(service.getTable());
+        flowBuilder.setTableId(getTable());
         flowBuilder.setKey(key);
         flowBuilder.setFlowName(flowId);
         flowBuilder.setHardTimeout(0);
index c46211f46ccac21fa96edbdb725cd3d8c4c6fd31..55271c54eac3f010177d4bc924dd54597d00031f 100644 (file)
@@ -1022,7 +1022,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
                 }
             }
             ingressAclProvider.programFixedSecurityGroup(dpid, segmentationId, dhcpPort.getMacAddress(), localPort,
-                                                       isLastPortinSubnet, isComputePort, write);
+                                                       isLastPortinSubnet, isComputePort, attachedMac, write);
             egressAclProvider.programFixedSecurityGroup(dpid, segmentationId, attachedMac, localPort,
                                                       srcAddressList, isLastPortinBridge, isComputePort,write);
             /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
@@ -1259,6 +1259,11 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
 
         writeLLDPRule(dpid);
 
+        if (bridgeName.equals(configurationService.getIntegrationBridgeName()) &&
+                NetvirtProvidersProvider.getTableOffset() != 0) {
+            classifierProvider.programGotoTable(dpid,true);
+        }
+
         if (bridgeName.equals(configurationService.getExternalBridgeName())) {
             writeNormalRule(dpid);
         }
@@ -1286,7 +1291,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
         FlowBuilder flowBuilder = new FlowBuilder();
         String flowName = "NORMAL";
-        FlowUtils.initFlowBuilder(flowBuilder, flowName, (short)0).setPriority(0);
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable()).setPriority(0);
         MatchBuilder matchBuilder = new MatchBuilder();
         flowBuilder.setMatch(matchBuilder.build());
 
index 6f8a19728298cec71d23d9fdeb0e77af6ad60d2d..327f45ecb85c97f5c69f507596d05e1ac9cbec9c 100644 (file)
@@ -24,6 +24,8 @@ public interface PipelineOrchestrator {
     Service getNextServiceInPipeline(Service service);
     AbstractServiceInstance getServiceInstance(Service service);
     Map<Service, AbstractServiceInstance> getServiceRegistry();
+    short getTableOffset();
+    short getTable(Service service);
     List<Service> getStaticPipeline();
     void enqueue(Node node);
     void registerService(final ServiceReference ref, AbstractServiceInstance serviceInstance);
index 299ab21a08b76f4261a5fceee18f5e49cf8c7046..47ddf3329cf06bd1c435e833ab36add43132cda3 100644 (file)
@@ -21,6 +21,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheListener;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.NetvirtProvidersProvider;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.osgi.framework.BundleContext;
@@ -34,6 +35,25 @@ import com.google.common.collect.Maps;
 public class PipelineOrchestratorImpl implements ConfigInterface, NodeCacheListener, PipelineOrchestrator {
     private static final Logger LOG = LoggerFactory.getLogger(PipelineOrchestratorImpl.class);
 
+    /**
+     * Return the current table offset
+     * @return The table offset
+     */
+    @Override
+    public short getTableOffset() {
+        return NetvirtProvidersProvider.getTableOffset();
+    }
+
+    /**
+     * Return the offset adjusted table for the given {@link Service}
+     * @param service Identifies the openflow {@link Service}
+     * @return The table id
+     */
+    @Override
+    public short getTable(Service service) {
+        return (short)(getTableOffset() + service.getTable());
+    }
+
     public List<Service> getStaticPipeline() {
         return staticPipeline;
     }
@@ -119,11 +139,14 @@ public class PipelineOrchestratorImpl implements ConfigInterface, NodeCacheListe
                     while (true) {
                         Node node = queue.take();
                         LOG.info(">>>>> dequeue: {}", node);
-                        for (Service service : staticPipeline) {
-                            AbstractServiceInstance serviceInstance = getServiceInstance(service);
-                            if (serviceInstance != null && southbound.getBridge(node) != null) {
-                                serviceInstance.programDefaultPipelineRule(node);
+                        if (southbound.getBridge(node) != null) {
+                            for (Service service : staticPipeline) {
+                                AbstractServiceInstance serviceInstance = getServiceInstance(service);
+                                if (serviceInstance != null) {
+                                    serviceInstance.programDefaultPipelineRule(node);
+                                }
                             }
+                            // TODO: might need a flow to go from table 0 to the pipeline
                         }
                     }
                 } catch (Exception e) {
index 385628fa9408958403f5168b274baccd1f9bc7b1..b0b84209e33310883fa56df11458d8355d6261c5 100644 (file)
@@ -334,7 +334,7 @@ public class ClassifierService extends AbstractServiceInstance implements Classi
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
         FlowBuilder flowBuilder = new FlowBuilder();
         String flowName = "LLDP";
-        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable());
 
         MatchBuilder matchBuilder = new MatchBuilder();
         MatchUtils.createEtherTypeMatch(matchBuilder, new EtherType(0x88CCL));
@@ -362,6 +362,34 @@ public class ClassifierService extends AbstractServiceInstance implements Classi
         writeFlow(flowBuilder, nodeBuilder);
     }
 
+    @Override
+    public void programGotoTable(Long dpidLong, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        String flowName = "TableOffset_" + getTable();
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable())
+                .setPriority(0);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        flowBuilder.setMatch(matchBuilder.build());
+
+        if (write) {
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionBuilder ib =
+                    InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), getTable());
+            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 setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
         super.setDependencies(bundleContext.getServiceReference(ClassifierProvider.class.getName()), this);
index 710995ba285eef591bb0d3b36b5acbc963a3f749..a3f1d0f5c0f6ea45a5970fbb2400873120ddc4fe 100644 (file)
@@ -20,6 +20,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+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;
@@ -29,13 +30,25 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 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.inet.types.rev100924.PortNumber;
 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.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.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.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.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpSourceHardwareAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
@@ -228,7 +241,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
         }
         flowId = flowId + "_Permit";
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
-        syncFlow(flowId, nodeBuilder, matchBuilder, priority, write, false);
+        syncFlow(flowId, nodeBuilder, matchBuilder, priority, write, false, securityServicesManager.isConntrackEnabled());
     }
 
     @Override
@@ -236,10 +249,14 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                                         long localPort, List<Neutron_IPs> srcAddressList,
                                         boolean isLastPortinBridge, boolean isComputePort ,boolean write) {
         // If it is the only port in the bridge add the rule to allow any DHCP client traffic
-        if (isLastPortinBridge) {
+        //if (isLastPortinBridge) {
             egressAclDhcpAllowClientTrafficFromVm(dpid, write, Constants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY);
-        }
+       // }
         if (isComputePort) {
+            programArpRule(dpid, segmentationId, localPort, attachedMac, write);
+            if (securityServicesManager.isConntrackEnabled()) {
+                programEgressAclFixedConntrackRule(dpid, segmentationId, localPort, attachedMac, write);
+            }
             // add rule to drop the DHCP server traffic originating from the vm.
             egressAclDhcpDropServerTrafficfromVm(dpid, localPort, write,
                                                  Constants.PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP);
@@ -262,6 +279,135 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
         }
     }
 
+    private void programArpRule(Long dpid, String segmentationId, long localPort, String attachedMac, boolean write) {
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        String flowId = "Egress_ARP_" + segmentationId + "_" + localPort + "_";
+
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0806L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+
+        ArpMatchBuilder arpDstMatch = new ArpMatchBuilder();
+        ArpSourceHardwareAddressBuilder arpSrc = new ArpSourceHardwareAddressBuilder();
+        arpSrc.setAddress(new MacAddress(attachedMac));
+        arpDstMatch.setArpSourceHardwareAddress(arpSrc.build());
+        matchBuilder.setLayer3Match(arpDstMatch.build());
+
+        syncFlow(flowId, nodeBuilder, matchBuilder, Constants.PROTO_MATCH_PRIORITY, write, false, false);
+    }
+
+    private void programEgressAclFixedConntrackRule(Long dpid,
+            String segmentationId, long localPort, String attachMac, boolean write) {
+         try {
+             String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
+             programConntrackUntrackRule(nodeName, segmentationId, localPort,attachMac,
+                                         Constants.CT_STATE_UNTRACKED_PRIORITY, write );
+             programConntrackTrackedPlusEstRule(nodeName, dpid, segmentationId, localPort,
+                                         Constants.CT_STATE_TRACKED_EST_PRIORITY, write );
+             programConntrackNewDropRule(nodeName, dpid, segmentationId, localPort,
+                                              Constants.CT_STATE_NEW_PRIORITY_DROP, write );
+             LOG.info("programEgressAclFixedConntrackRule :  default connection tracking rule are added.");
+         } catch (Exception e) {
+             LOG.error("Failed to add default conntrack rules : " , e);
+         }
+     }
+
+     private void programConntrackUntrackRule(String nodeName, String segmentationId,
+                                              long localPort, String attachMac, Integer priority, boolean write) {
+         MatchBuilder matchBuilder = new MatchBuilder();
+         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+         String flowName = "Egress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
+         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder, attachMac, null);
+         matchBuilder = MatchUtils.addCtState(matchBuilder,0x00,0X80);
+         FlowBuilder flowBuilder = new FlowBuilder();
+         flowBuilder.setMatch(matchBuilder.build());
+         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
+         if (write) {
+             InstructionBuilder ib = new InstructionBuilder();
+             List<Instruction> instructionsList = Lists.newArrayList();
+             InstructionsBuilder isb = new InstructionsBuilder();
+             ActionBuilder ab = new ActionBuilder();
+             ab.setAction(ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0));
+             // 0xff means no table, 0x0 is table = 0
+             ab.setOrder(0);
+             ab.setKey(new ActionKey(0));
+             List<Action> actionList = Lists.newArrayList();
+             actionList.add(ab.build());
+             ApplyActionsBuilder aab = new ApplyActionsBuilder();
+             aab.setAction(actionList);
+             ib.setOrder(0);
+             ib.setKey(new InstructionKey(0));
+             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+             instructionsList.add(ib.build());
+             isb.setInstruction(instructionsList);
+             flowBuilder.setInstructions(isb.build());
+             writeFlow(flowBuilder, nodeBuilder);
+             LOG.info("EGRESS:default programConntrackUntrackRule() flows are written");
+         } else {
+             removeFlow(flowBuilder, nodeBuilder);
+         }
+     }
+
+     private void programConntrackTrackedPlusEstRule(String nodeName, Long dpid, String segmentationId,
+                                                   long localPort,Integer priority, boolean write) {
+         MatchBuilder matchBuilder = new MatchBuilder();
+         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+         String flowName = "Egress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
+         matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpid, localPort);
+         matchBuilder = MatchUtils.addCtState(matchBuilder,0x82, 0x82);
+         FlowBuilder flowBuilder = new FlowBuilder();
+         flowBuilder.setMatch(matchBuilder.build());
+         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
+         if (write) {
+             InstructionBuilder ib = new InstructionBuilder();
+             List<Instruction> instructionsList = Lists.newArrayList();
+             InstructionsBuilder isb = new InstructionsBuilder();
+             // got to next table instruction
+             ib = this.getMutablePipelineInstructionBuilder();
+             ib.setOrder(0);
+             ib.setKey(new InstructionKey(0));
+             instructionsList.add(ib.build());
+             isb.setInstruction(instructionsList);
+             flowBuilder.setInstructions(isb.build());
+             writeFlow(flowBuilder, nodeBuilder);
+             LOG.info("EGRESS:default programConntrackTrackedPlusEstRule() flows are written");
+         } else {
+             removeFlow(flowBuilder, nodeBuilder);
+         }
+     }
+
+     private void programConntrackNewDropRule(String nodeName, Long dpid, String segmentationId,
+                                              long localPort, Integer priority, boolean write) {
+         MatchBuilder matchBuilder = new MatchBuilder();
+         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+         String flowName = "Egress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
+         matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpid, localPort);
+         matchBuilder = MatchUtils.addCtState(matchBuilder,0x01, 0x01);
+         FlowBuilder flowBuilder = new FlowBuilder();
+         flowBuilder.setMatch(matchBuilder.build());
+         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
+         if (write) {
+             InstructionBuilder ib = new InstructionBuilder();
+             InstructionsBuilder isb = new InstructionsBuilder();
+             List<Instruction> instructions = Lists.newArrayList();
+             InstructionUtils.createDropInstructions(ib);
+             ib.setOrder(0);
+             ib.setKey(new InstructionKey(0));
+             instructions.add(ib.build());
+             isb.setInstruction(instructions);
+             LOG.debug("Instructions contain: {}", ib.getInstruction());
+             flowBuilder.setInstructions(isb.build());
+             writeFlow(flowBuilder, nodeBuilder);
+             LOG.info("EGRESS:default programConntrackNewDropRule() flows are written");
+         } else {
+             removeFlow(flowBuilder, nodeBuilder);
+         }
+     }
+
     /**
      * Allows IPv4 packet egress from the src mac address.
      * @param dpidLong the dpid
@@ -276,7 +422,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
         MatchBuilder matchBuilder = new MatchBuilder();
         String flowId = "Egress_IP" + segmentationId + "_" + srcMac + "_Permit_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
-        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, false);
     }
 
     /**
@@ -335,11 +481,11 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                 rangeflowId = rangeflowId + "_Permit";
                 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
                                                   0, port, portMaskMap.get(port));
-                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
             }
         } else {
             flowId = flowId + "_Permit";
-            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
         }
     }
 
@@ -381,12 +527,14 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                     MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
-            matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
+            if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
                     new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
+            }
         }
         flowId = flowId + "_Permit";
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
-        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
     }
 
     /**
@@ -445,11 +593,11 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                 rangeflowId = rangeflowId + "_Permit";
                 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
                                                   0, port, portMaskMap.get(port));
-                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
             }
         } else {
             flowId = flowId + "_Permit";
-            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
         }
     }
 
@@ -625,7 +773,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
         String flowName = "Egress_DHCP_Client"  + "_Permit_";
         MatchBuilder matchBuilder = new MatchBuilder();
         MatchUtils.createDhcpMatch(matchBuilder, DHCP_DESTINATION_PORT, DHCP_SOURCE_PORT);
-        syncFlow(flowName, nodeBuilder, matchBuilder, priority, write, false);
+        syncFlow(flowName, nodeBuilder, matchBuilder, priority, write, false, false);
     }
 
     /**
@@ -644,7 +792,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
         MatchBuilder matchBuilder = new MatchBuilder();
         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
         MatchUtils.createDhcpMatch(matchBuilder, DHCP_SOURCE_PORT, DHCP_DESTINATION_PORT);
-        syncFlow(flowName, nodeBuilder, matchBuilder, priority, write, true);
+        syncFlow(flowName, nodeBuilder, matchBuilder, priority, write, true, false);
     }
 
     /**
@@ -666,7 +814,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
         MatchUtils.createSrcL3Ipv4MatchWithMac(matchBuilder, new Ipv4Prefix(srcIp),new MacAddress(attachedMac));
         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
         LOG.debug("egressAclAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", matchBuilder);
-        syncFlow(flowName, nodeBuilder, matchBuilder, priority, write, false);
+        syncFlow(flowName, nodeBuilder, matchBuilder, priority, write, false, false);
     }
 
     /**
@@ -678,16 +826,24 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
      * @param priority the protocol priority
      * @param write whether it is a write
      * @param drop whether it is a drop or forward
+     * @param isCtCommit commit the connection or CT to track
      */
     private void syncFlow(String flowName, NodeBuilder nodeBuilder,
                           MatchBuilder matchBuilder, Integer priority,
-                          boolean write, boolean drop) {
+                          boolean write, boolean drop, boolean isCtCommit) {
+        MatchBuilder matchBuilder1 = matchBuilder;
+        if (isCtCommit) {
+            matchBuilder1 = MatchUtils.addCtState(matchBuilder1,0x81, 0x81);
+        }
         FlowBuilder flowBuilder = new FlowBuilder();
-        flowBuilder.setMatch(matchBuilder.build());
+        flowBuilder.setMatch(matchBuilder1.build());
         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
 
         if (write) {
             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
+            InstructionBuilder ib1 = new InstructionBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
             if (drop) {
                 InstructionUtils.createDropInstructions(ib);
             }
@@ -696,6 +852,19 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
             InstructionsBuilder isb = new InstructionsBuilder();
             List<Instruction> instructionsList = Lists.newArrayList();
             instructionsList.add(ib.build());
+            if (isCtCommit) {
+                LOG.info("Adding Conntarck rule, flowname = " + flowName);
+                ab.setAction(ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff));
+                ab.setOrder(0);
+                ab.setKey(new ActionKey(0));
+                List<Action> actionList = Lists.newArrayList();
+                actionList.add(ab.build());
+                aab.setAction(actionList);
+                ib1.setOrder(1);
+                ib1.setKey(new InstructionKey(1));
+                ib1.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+                instructionsList.add(ib1.build());
+            }
             isb.setInstruction(instructionsList);
             flowBuilder.setInstructions(isb.build());
             writeFlow(flowBuilder, nodeBuilder);
index 0a31568f188cd8bb21a216473e8571c0401476ca..e5d0a4c7d754c6a2e7ee92ad361d8c94e6c0c628 100644 (file)
@@ -20,6 +20,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+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;
@@ -29,6 +30,9 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 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.inet.types.rev100924.PortNumber;
 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;
@@ -37,7 +41,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.M
 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.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.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
@@ -218,18 +229,161 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
           }
           NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
           flowId = flowId + "_Permit";
-          syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+          syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
     }
 
     @Override
     public void programFixedSecurityGroup(Long dpid, String segmentationId, String dhcpMacAddress,
                                         long localPort, boolean isLastPortinSubnet,
-                                        boolean isComputePort, boolean write) {
+                                        boolean isComputePort, String attachMac, boolean write) {
         //If this port is the only port in the compute node add the DHCP server rule.
         if (isLastPortinSubnet && isComputePort ) {
             ingressAclDhcpAllowServerTraffic(dpid, segmentationId,dhcpMacAddress,
                                              write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
         }
+        if (isComputePort) {
+            if (securityServicesManager.isConntrackEnabled()) {
+                programIngressAclFixedConntrackRule(dpid, segmentationId, attachMac, localPort, write);
+            }
+            programArpRule(dpid, segmentationId, localPort, attachMac, write);
+        }
+    }
+
+    private void programArpRule(Long dpid, String segmentationId, long localPort, String attachMac, boolean write) {
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        String flowId = "Ingress_ARP_" + segmentationId + "_" + localPort + "_";
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0806L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+
+        ArpMatchBuilder arpDstMatch = new ArpMatchBuilder();
+        ArpTargetHardwareAddressBuilder arpDst = new ArpTargetHardwareAddressBuilder();
+        arpDst.setAddress(new MacAddress(attachMac));
+        arpDstMatch.setArpTargetHardwareAddress(arpDst.build());
+        matchBuilder.setLayer3Match(arpDstMatch.build());
+        syncFlow(flowId, nodeBuilder, matchBuilder, Constants.PROTO_MATCH_PRIORITY, write, false, securityServicesManager.isConntrackEnabled());
+    }
+
+    private void programIngressAclFixedConntrackRule(Long dpid,
+           String segmentationId, String attachMac, long localPort, boolean write) {
+        try {
+            String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
+            programConntrackUntrackRule(nodeName, segmentationId, localPort, attachMac,
+                                        Constants.CT_STATE_UNTRACKED_PRIORITY, write );
+            programConntrackTrackedPlusEstRule(nodeName, segmentationId, localPort, attachMac,
+                                        Constants.CT_STATE_TRACKED_EST_PRIORITY, write );
+            programConntrackNewDropRule(nodeName, segmentationId, localPort, attachMac,
+                                             Constants.CT_STATE_NEW_PRIORITY_DROP, write );
+            LOG.info("programIngressAclFixedConntrackRule :  default connection tracking rule are added.");
+        } catch (Exception e) {
+            LOG.error("Failed to add default conntrack rules : " , e);
+        }
+    }
+
+    private void programConntrackUntrackRule(String nodeName, String segmentationId,
+                                             long localPort, String attachMac, Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        String flowName = "Ingress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,attachMac);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,0x00, 0x80);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        flowBuilder.setMatch(matchBuilder.build());
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
+        if (write) {
+            InstructionBuilder ib = new InstructionBuilder();
+            List<Instruction> instructionsList = Lists.newArrayList();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            ab.setAction(ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0));
+            // 0xff means no table, 0x0 is table = 0
+            // nxConntrackAction(Integer flags, Long zoneSrc,Integer conntrackZone, Short recircTable)
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            List<Action> actionList = Lists.newArrayList();
+            actionList.add(ab.build());
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            aab.setAction(actionList);
+
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            instructionsList.add(ib.build());
+            isb.setInstruction(instructionsList);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+            LOG.info("INGRESS:default programConntrackUntrackRule() flows are written");
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    private void programConntrackTrackedPlusEstRule(String nodeName, String segmentationId,
+                                                  long localPort, String attachMac,Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        String flowName = "Ingress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,attachMac);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,0x82, 0x82);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        flowBuilder.setMatch(matchBuilder.build());
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
+        if (write) {
+            InstructionBuilder ib = new InstructionBuilder();
+            List<Instruction> instructionsList = Lists.newArrayList();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructionsList.add(ib.build());
+             isb.setInstruction(instructionsList);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+            LOG.info("INGRESS:default programConntrackTrackedPlusEstRule() flows are written");
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    private void programConntrackNewDropRule(String nodeName, String segmentationId,
+                                             long localPort, String attachMac, Integer priority, boolean write) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        String flowName = "Ingress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
+        matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,attachMac);
+        matchBuilder = MatchUtils.addCtState(matchBuilder,0x01, 0x01);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        flowBuilder.setMatch(matchBuilder.build());
+        FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = Lists.newArrayList();
+
+            // Set the Output Port/Iface
+            InstructionUtils.createDropInstructions(ib);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+            LOG.debug("Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+            LOG.info("INGRESS:default programConntrackNewDropRule flows are written");
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
     }
 
     /**
@@ -246,7 +400,7 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
         MatchBuilder matchBuilder = new MatchBuilder();
         String flowId = "Ingress_IP" + segmentationId + "_" + dstMac + "_Permit_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
-        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
 
     }
     /**
@@ -306,11 +460,11 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                 rangeflowId = rangeflowId + "_Permit";
                 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
                                                   0, port, portMaskMap.get(port));
-                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
             }
         } else {
             flowId = flowId + "_Permit";
-            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
         }
     }
 
@@ -371,11 +525,11 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                 rangeflowId = rangeflowId + "_Permit";
                 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
                                                    0, port, portMaskMap.get(port));
-                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
             }
         } else {
             flowId = flowId + "_Permit";
-            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
         }
     }
 
@@ -418,13 +572,14 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                                                         MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
-            matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
-                                                        new Ipv4Prefix(portSecurityRule
-                                                                       .getSecurityRuleRemoteIpPrefix()),null);
+            if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
+                matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
+                                         new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
+            }
         }
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
         flowId = flowId + "_Permit";
-        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
     }
 
 
@@ -696,7 +851,7 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
         MatchBuilder matchBuilder = new MatchBuilder();
         MatchUtils.createDhcpServerMatch(matchBuilder, dhcpMacAddress, 67, 68).build();
         String flowId = "Ingress_DHCP_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
-        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, false);
     }
 
     /**
@@ -708,16 +863,24 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
      * @param priority the protocol priority
      * @param write whether it is a write
      * @param drop whether it is a drop or forward
+     * @param isCtCommit commit the connection or CT to track
      */
     private void syncFlow(String flowName, NodeBuilder nodeBuilder,
                           MatchBuilder matchBuilder, Integer priority,
-                          boolean write, boolean drop) {
+                          boolean write, boolean drop, boolean isCtCommit) {
+        MatchBuilder matchBuilder1 = matchBuilder;
+        if (isCtCommit) {
+            matchBuilder1 = MatchUtils.addCtState(matchBuilder1,0x81, 0x81);
+        }
         FlowBuilder flowBuilder = new FlowBuilder();
-        flowBuilder.setMatch(matchBuilder.build());
+        flowBuilder.setMatch(matchBuilder1.build());
         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
 
         if (write) {
             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
+            InstructionBuilder ib1 = new InstructionBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
             if (drop) {
                 InstructionUtils.createDropInstructions(ib);
             }
@@ -726,6 +889,19 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
             List<Instruction> instructionsList = Lists.newArrayList();
             ib.setKey(new InstructionKey(0));
             instructionsList.add(ib.build());
+            if (isCtCommit) {
+                LOG.info("Adding Conntarck rule, flowname = " + flowName);
+                ab.setAction(ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff));
+                ab.setOrder(0);
+                ab.setKey(new ActionKey(0));
+                List<Action> actionList = Lists.newArrayList();
+                actionList.add(ab.build());
+                aab.setAction(actionList);
+                ib1.setOrder(1);
+                ib1.setKey(new InstructionKey(1));
+                ib1.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+                instructionsList.add(ib1.build());
+            }
             isb.setInstruction(instructionsList);
             flowBuilder.setInstructions(isb.build());
             writeFlow(flowBuilder, nodeBuilder);
index be01ac5a0cb6668a369d0890575fac2e958ef27a..af75afb5da777d40349a261cf96cfdf94d9314a1 100644 (file)
@@ -93,7 +93,6 @@ public class GatewayMacResolverService extends AbstractServiceInstance
                                         implements ConfigInterface, GatewayMacResolver,PacketProcessingListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(GatewayMacResolverService.class);
-    private static final short TABLE_FOR_ARP_FLOW = 0;
     private static final String ARP_REPLY_TO_CONTROLLER_FLOW_NAME = "GatewayArpReplyRouter";
     private static final int ARP_REPLY_TO_CONTROLLER_FLOW_PRIORITY = 10000;
     private static final Instruction SEND_TO_CONTROLLER_INSTRUCTION;
@@ -151,7 +150,8 @@ public class GatewayMacResolverService extends AbstractServiceInstance
                         for(final Entry<Ipv4Address, ArpResolverMetadata> gatewayToArpMetadataEntry : gatewayToArpMetadataMap.entrySet()){
                             final Ipv4Address gatewayIp = gatewayToArpMetadataEntry.getKey();
                             final ArpResolverMetadata gatewayMetaData =
-                                    checkAndGetExternalBridgeDpid(gatewayToArpMetadataEntry.getValue());
+                                    checkAndGetExternalBridgeDpid(
+                                            resetFlowToRemove(gatewayIp, gatewayToArpMetadataEntry.getValue()));
                             gatewayMacRefresherPool.schedule(new Runnable(){
 
                                 @Override
@@ -370,6 +370,7 @@ public class GatewayMacResolverService extends AbstractServiceInstance
                     ArpResolverMetadata arpResolverMetadata = gatewayToArpMetadataMap.get(gatewayIp);
                     if(arpResolverMetadata != null && arpResolverMetadata.getGatewayMacAddress() != null){
                         if(!arpResolverMetadata.isPeriodicRefresh()){
+                            resetFlowToRemove(gatewayIp, arpResolverMetadata);
                             return gatewayToArpMetadataMap.remove(gatewayIp).getGatewayMacAddress();
                         }
                         return arpResolverMetadata.getGatewayMacAddress();
@@ -383,7 +384,7 @@ public class GatewayMacResolverService extends AbstractServiceInstance
     private Flow createArpReplyToControllerFlow(final ArpMessageAddress senderAddress, final Ipv4Address ipForRequestedMac) {
         checkNotNull(senderAddress);
         checkNotNull(ipForRequestedMac);
-        FlowBuilder arpFlow = new FlowBuilder().setTableId(TABLE_FOR_ARP_FLOW)
+        FlowBuilder arpFlow = new FlowBuilder().setTableId(Service.CLASSIFIER.getTable())
             .setFlowName(ARP_REPLY_TO_CONTROLLER_FLOW_NAME)
             .setPriority(ARP_REPLY_TO_CONTROLLER_FLOW_PRIORITY)
             .setBufferId(OFConstants.OFP_NO_BUFFER)
@@ -453,7 +454,7 @@ public class GatewayMacResolverService extends AbstractServiceInstance
             if(candidateGatewayIp != null){
                 LOG.debug("Resolved MAC for Gateway Ip {} is {}",gatewayIpAddress.getValue(),gatewayMacAddress.getValue());
                 candidateGatewayIp.setGatewayMacAddress(gatewayMacAddress);
-                flowService.removeFlow(candidateGatewayIp.getFlowToRemove());
+                resetFlowToRemove(gatewayIpAddress, candidateGatewayIp);
             }
         }
     }
@@ -477,7 +478,25 @@ public class GatewayMacResolverService extends AbstractServiceInstance
     @Override
     public void stopPeriodicRefresh(Ipv4Address gatewayIp) {
         init();
+        resetFlowToRemove(gatewayIp, null);
         gatewayToArpMetadataMap.remove(gatewayIp);
     }
 
+    private ArpResolverMetadata resetFlowToRemove(
+            final Ipv4Address gatewayIp, ArpResolverMetadata gatewayArpMetadata) {
+        checkNotNull(gatewayIp);
+
+        // If gatewayArpMetadata was not provided, look it up
+        if (gatewayArpMetadata == null) {
+            gatewayArpMetadata = gatewayToArpMetadataMap.get(gatewayIp);
+        }
+        if (gatewayArpMetadata != null && gatewayArpMetadata.getFlowToRemove() != null) {
+            LOG.debug("Flow to route ARP Reply to Controller from {} being removed from node {}",
+                    gatewayIp, gatewayArpMetadata.getFlowToRemove().getNode());
+            flowService.removeFlow(gatewayArpMetadata.getFlowToRemove());
+            gatewayArpMetadata.setFlowToRemove(null);
+        }
+        return gatewayArpMetadata;
+    }
+
 }
index eaed95c249fc32ccf425bca6f0a632c00f43cb2c..cd0a23c0966a9e9ba32bb5e76c4d666088eb1dd6 100644 (file)
@@ -22,7 +22,8 @@ public class NetvirtProvidersImplModule extends org.opendaylight.yang.gen.v1.urn
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        NetvirtProvidersProvider provider = new NetvirtProvidersProvider(bundleContext, getClusteringEntityOwnershipServiceDependency());
+        NetvirtProvidersProvider provider = new NetvirtProvidersProvider(bundleContext,
+                getClusteringEntityOwnershipServiceDependency(), getTableOffset());
         BindingAwareBroker localBroker = getBrokerDependency();
         localBroker.registerProvider(provider);
         return provider;
diff --git a/openstack/net-virt-providers/src/main/yang/netvirt-providers-config.yang b/openstack/net-virt-providers/src/main/yang/netvirt-providers-config.yang
new file mode 100644 (file)
index 0000000..780b020
--- /dev/null
@@ -0,0 +1,20 @@
+module netvirt-providers-config {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:netvirt:providers:config";
+    prefix "netvirt-providers-config";
+
+    revision "2016-01-09" {
+        description "Initial revision of the netvirt providers config";
+    }
+
+    container netvirt-providers-config {
+        description "Configuration for NetvirtProviders";
+
+        config true;
+
+        leaf table-offset {
+            description "The table-offset is used to set the starting table for the netvirt pipeline";
+            type uint8;
+        }
+    }
+}
index a784a4b6f1ab06140087ddf84af1579ff2302846..b02b37e2ad03baf4828aa6d352c0c4cd636805d4 100644 (file)
@@ -31,6 +31,7 @@ module netvirt-providers-impl {
                     }
                 }
             }
+
             container clustering-entity-ownership-service {
                 uses config:service-ref {
                     refine type {
@@ -39,6 +40,11 @@ module netvirt-providers-impl {
                     }
                 }
             }
+
+            leaf table-offset {
+                description "The table-offset is used to set the starting table for the netvirt pipeline";
+                type uint8;
+            }
         }
     }
 }
diff --git a/openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/NetvirtProvidersProviderTest.java b/openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/NetvirtProvidersProviderTest.java
new file mode 100644 (file)
index 0000000..32d2f72
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016 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.providers;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestratorImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Unit tests for {@link NetvirtProvidersProvider}
+ */
+public class NetvirtProvidersProviderTest {
+
+    /**
+     * Test for {@link NetvirtProvidersProvider#getTableOffset()}
+     */
+    @Test
+    public void testGetTableOffset() {
+        short tableOffset = 10;
+        NetvirtProvidersProvider netvirtProvidersProvider = new NetvirtProvidersProvider(null, null, tableOffset);
+        assertEquals("Table offset was not set", tableOffset, NetvirtProvidersProvider.getTableOffset());
+    }
+
+    /**
+     * Test for method {@link NetvirtProvidersProvider#setTableOffset(short)}
+     */
+    @Test
+    public void testSetTableOffset() {
+        // verify a good value can be set
+        short tableOffset = 0;
+        NetvirtProvidersProvider netvirtProvidersProvider = new NetvirtProvidersProvider(null, null, tableOffset);
+
+        tableOffset = 10;
+        NetvirtProvidersProvider.setTableOffset(tableOffset);
+        assertEquals("tableOffset was not set", tableOffset, NetvirtProvidersProvider.getTableOffset());
+    }
+
+    /**
+     * Negative test for method {@link NetvirtProvidersProvider#setTableOffset(short)}
+     */
+    @Test
+    public void testTableOffsetNegative() {
+        // verify an out of range value is not set
+        short tableOffset = 0;
+        NetvirtProvidersProvider netvirtProvidersProvider = new NetvirtProvidersProvider(null, null, tableOffset);
+
+        short tableOffsetBad = (short)(256 - Service.L2_FORWARDING.getTable());
+        NetvirtProvidersProvider.setTableOffset(tableOffsetBad);
+        assertEquals("tableOffset should not be set", 0, NetvirtProvidersProvider.getTableOffset());
+    }
+}
index 50727a188ef68bb345204058a87a84ad8e1d3205..bf5bed238397861f365a337443ebe4e0ece7ea3f 100644 (file)
@@ -75,7 +75,7 @@ public class AbstractServiceInstanceTest {
     private final String NODE_ID = Constants.INTEGRATION_BRIDGE + ":" +  ID;
 
     /**
-     * Test method {@link AbstractServiceInstance#isBridgeInPipeline(String)}
+     * Test method {@link AbstractServiceInstance#isBridgeInPipeline(Node)}
      */
     @Test
     public void testIsBridgeInPipeline() {
@@ -89,7 +89,23 @@ public class AbstractServiceInstanceTest {
     @Test
     public void testGetTable() {
         abstractServiceInstance.setService(service);
-        assertEquals("Error, getTable() did not return the correct value", 70, abstractServiceInstance.getTable());
+        assertEquals("Error, getTable() did not return the correct value",
+                service.getTable(), abstractServiceInstance.getTable());
+
+        when(orchestrator.getTableOffset()).thenReturn(Service.DIRECTOR.getTable());
+        assertEquals("Error, getTable() did not return the correct value",
+                (short)(Service.DIRECTOR.getTable() + service.getTable()), abstractServiceInstance.getTable());
+    }
+
+    /**
+     * Test method {@link AbstractServiceInstance@getTable(Service}
+     */
+    @Test
+    public void testGetTableWithService() {
+        when(orchestrator.getTableOffset()).thenReturn((short)0);
+        abstractServiceInstance.setService(service);
+        assertEquals("Error, getTables(service) did not return the correct value",
+                Service.L2_FORWARDING.getTable(), abstractServiceInstance.getTable(Service.L2_FORWARDING));
     }
 
     @Test
@@ -203,7 +219,7 @@ public class AbstractServiceInstanceTest {
     }
 
     /**
-     * Test method {@link AbstractServiceInstance#programDefaultPipelineRule(String)}
+     * Test method {@link AbstractServiceInstance#programDefaultPipelineRule(Node)}
      */
     @Test
     public void testProgramDefaultPipelineRule() {
index 947cde3338f196755598c4a8c8619c1ab41af1ba..98d6c97b7dde4a50a65a5cdcdf934425d2467af3 100644 (file)
@@ -41,6 +41,24 @@ public class PipelineOrchestratorImplTest {
     @Mock private ExecutorService eventHandler;
     @Mock private Southbound southbound;
 
+    /**
+     * Test for method {@link PipelineOrchestratorImpl#getTableOffset()}
+     */
+    @Test
+    public void testGetTableOffset() {
+        short tableOffset = 0;
+        assertEquals("tableOffset was not set", tableOffset, orchestrator.getTableOffset());
+    }
+
+    /**
+     * Test for {@link PipelineOrchestratorImpl#getTable(Service)}
+     */
+    @Test
+    public void testGetTableOffsetWithService() {
+        assertEquals("tableOffset was not set", Service.CLASSIFIER.getTable(),
+                orchestrator.getTable(Service.CLASSIFIER));
+    }
+
     /***
      * Registers a mock service and verifies the registration by asking the
      * pipeline orchestrator to return the associated service from its internal
@@ -65,7 +83,7 @@ public class PipelineOrchestratorImplTest {
 
     /**
      * Test method
-     * {@link PipelineOrchestratorImplr#getNextServiceInPipeline(Service)}
+     * {@link PipelineOrchestratorImpl#getNextServiceInPipeline(Service)}
      */
     @Test
     public void testGetNextServiceInPipeline() {
index e2b41f68bcdb995d3d02cb121a023a36e94802af..8bd7184f285dcc20791961bcd4f5d2badbc3e1ca 100644 (file)
@@ -969,7 +969,7 @@ public class IngressAclServiceTest {
      */
     @Test
     public void testProgramFixedSecurityACLAdd1() throws Exception {
-        ingressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 1, false, false, true);
+        ingressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 1, false, false, null, true);
 
         verify(writeTransaction, times(0)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
         verify(writeTransaction, times(0)).submit();
@@ -981,7 +981,7 @@ public class IngressAclServiceTest {
     @Test
     public void testProgramFixedSecurityACLRemove1() throws Exception {
 
-        ingressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 1, false, false, false);
+        ingressAclServiceSpy.programFixedSecurityGroup(Long.valueOf(1554), "2", MAC_ADDRESS, 1, false, false, null, false);
 
         verify(writeTransaction, times(0)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
         verify(writeTransaction, times(0)).submit();
index e3b09a1a0eaf24b1c67960dbd8780c92161d128e..44eee54066fa76395c40b1d30e939fe96dd434fd 100644 (file)
@@ -26,7 +26,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
 
   <properties>
     <openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
-    <powermock.version>1.5.2</powermock.version>
+    <powermock.version>1.6.4</powermock.version>
     <sfc.version>0.2.0-SNAPSHOT</sfc.version>
     <sonar.jacoco.itReportPath>../it/target/jacoco-it.exec</sonar.jacoco.itReportPath>
   </properties>
@@ -135,6 +135,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-all</artifactId>
+      <version>1.10.19</version>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -185,6 +186,24 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           </properties>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-instrument</id>
+            <goals>
+              <goal>instrument</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-restore-instrumented-classes</id>
+            <goals>
+              <goal>restore-instrumented-classes</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>
index 0fa03982b4f2bf7920f754ae69b28736cef0bb9d..43f0e4a1774f79766ef1d60c08f72bf8cc3b0ac5 100644 (file)
@@ -269,6 +269,9 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
             sfcClassifierService.program_sfEgress(dataPathId, sfIpPort, true);
             sfcClassifierService.program_sfIngress(dataPathId, sfIpPort, sfOfPort, sfIpAddr, sfDplName, true);
             sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpAddr, true);
+        } else {
+            LOG.info("handleSf: sf and bridge are not on the same node: {} - {}, do nothing",
+            bridgeNode.getNodeId(), serviceFunction.getName());
         }
     }
 
@@ -276,14 +279,26 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
         String localIp = "";
         Ip ip = sfcUtils.getSffIp(serviceFunctionForwarder);
         Node ovsdbNode = southbound.readOvsdbNode(bridgeNode);
+        if (ovsdbNode != null) {
+            localIp = getLocalip(ovsdbNode);
+        }
+        return localIp.equals(String.valueOf(ip.getIp().getValue()));
+    }
+
+    private String getLocalip(Node ovsdbNode) {
+        Preconditions.checkNotNull("The ovsdbNode was null", ovsdbNode);
+        String localIp = null;
         if (ovsdbNode != null) {
             OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
             if (ovsdbNodeAugmentation != null && ovsdbNodeAugmentation.getOpenvswitchOtherConfigs() != null) {
                 localIp = southbound.getOtherConfig(ovsdbNode, OvsdbTables.OPENVSWITCH, TUNNEL_ENDPOINT_KEY);
             }
-
         }
-        return localIp.equals(String.valueOf(ip.getIp().getValue()));
+        if (localIp == null) {
+            LOG.warn("local_ip was not found for node: {}", ovsdbNode);
+            localIp = "";
+        }
+        return localIp;
     }
 
     private boolean isSfOnBridge(Node bridgeNode, ServiceFunction serviceFunction) {
@@ -386,6 +401,7 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
                     port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
                     if (port != null) {
                         ofPort = southbound.getOFPort(port);
+                        LOG.info("found ofPort {} - {}, try: {}", portName, ofPort, i);
                         break;
                     }
                 }
index 3055544ad9569c6008e2d712ce49cae7122eddb9..1f06202b07e907733a22d8eeceda7f6bf8d77160 100644 (file)
@@ -53,7 +53,6 @@ import org.slf4j.LoggerFactory;
 
 public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface, ISfcClassifierService {
     private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
-    private static final short TABLE_0 = 0;
     private static final short UDP_SHORT = 17;
     static int cookieIndex = 0;
 
@@ -161,7 +160,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         flowBuilder.setId(new FlowId(flowId));
         FlowKey key = new FlowKey(new FlowId(flowId));
         flowBuilder.setBarrier(true);
-        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setTableId(getTable(Service.CLASSIFIER));
         flowBuilder.setKey(key);
         flowBuilder.setFlowName(flowId);
         flowBuilder.setHardTimeout(0);
@@ -203,7 +202,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         flowBuilder.setId(new FlowId(flowId));
         FlowKey key = new FlowKey(new FlowId(flowId));
         flowBuilder.setBarrier(true);
-        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setTableId(getTable(Service.CLASSIFIER));
         flowBuilder.setKey(key);
         flowBuilder.setFlowName(flowId);
         flowBuilder.setHardTimeout(0);
@@ -244,7 +243,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         flowBuilder.setId(new FlowId(flowId));
         FlowKey key = new FlowKey(new FlowId(flowId));
         flowBuilder.setBarrier(true);
-        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setTableId(getTable(Service.CLASSIFIER));
         flowBuilder.setKey(key);
         flowBuilder.setFlowName(flowId);
         flowBuilder.setHardTimeout(0);
@@ -271,7 +270,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
             ab.setKey(new ActionKey(actionList.size()));
             actionList.add(ab.build());
 
-            ab.setAction(ActionUtils.nxResubmitAction((int)sfOfPort, TABLE_0));
+            ab.setAction(ActionUtils.nxResubmitAction((int)sfOfPort, Service.CLASSIFIER.getTable()));
             ab.setOrder(actionList.size());
             ab.setKey(new ActionKey(actionList.size()));
             actionList.add(ab.build());
@@ -306,7 +305,8 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
         String flowName = "sfcEgressClassBypass_" + nsp + "_" + + nsi + "_"  + sfOfPort;
-        initFlowBuilder(flowBuilder, flowName, TABLE_0, FlowID.FLOW_EGRESSCLASSBYPASS).setPriority(40000);
+        initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable(),
+                FlowID.FLOW_EGRESSCLASSBYPASS).setPriority(40000);
 
         MatchBuilder matchBuilder = new MatchBuilder();
         MatchUtils.createInPortMatch(matchBuilder, dataPathId, sfOfPort);
@@ -373,7 +373,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
         String flowName = "sfIngress_" + dstPort + "_" + ipAddress;
-        initFlowBuilder(flowBuilder, flowName, TABLE_0, FlowID.FLOW_SFINGRESS);
+        initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable(), FlowID.FLOW_SFINGRESS);
 
         MatchBuilder matchBuilder = new MatchBuilder();
         MatchUtils.createIpProtocolMatch(matchBuilder, UDP_SHORT);
@@ -406,7 +406,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
         String flowName = "ArpResponder_" + ipAddress;
-        initFlowBuilder(flowBuilder, flowName, TABLE_0, FlowID.FLOW_SFARP).setPriority(1024);
+        initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable(), FlowID.FLOW_SFARP).setPriority(1024);
 
         MacAddress macAddress = new MacAddress(macAddressStr);
 
index 1870c1a46792e181b5150e98891a79eea7c1901f..771921a7681d9237f55964f32d1c854b9ac522a3 100644 (file)
@@ -8,7 +8,7 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.sfc;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -26,7 +26,6 @@ import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfi
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
 
 import java.io.IOException;
-import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -42,7 +41,9 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
 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;
@@ -53,9 +54,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionPathUti
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionUtils;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcUtils;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
-import org.opendaylight.ovsdb.southbound.SouthboundUtil;
 import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
-import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
@@ -84,17 +83,12 @@ 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.AccessListEntriesBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.ClassifiersBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.ClassifierBuilder;
@@ -103,6 +97,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.Sfc;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.SfcBuilder;
 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.OvsdbTerminationPointAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
@@ -110,6 +105,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 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.node.TerminationPoint;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -143,7 +139,10 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     private static String addressStr;
     private static String portStr;
     private static String connectionType;
+    private static String controllerStr;
     private static boolean ovsdb_wait = false;
+    private static String userSpaceEnabled = "no";
+    private static PipelineOrchestrator pipelineOrchestrator;
     private static Southbound southbound;
     private static DataBroker dataBroker;
     public static final String CONTROLLER_IPADDRESS = "ovsdb.controller.address";
@@ -153,6 +152,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     public static final String CONNECTION_TYPE_ACTIVE = "active";
     public static final String CONNECTION_TYPE_PASSIVE = "passive";
     public static final String DEFAULT_SERVER_PORT = "6640";
+    public static final String USERSPACE_ENABLED = "ovsdb.userspace.enabled";
     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";
@@ -179,7 +179,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     private static final String SFCPATH = "SFC-Path";
     private static final String SFCSF1NAME = "firewall-abstract";
     private static final SftType SFCSF1TYPE = new SftType("firewall");
-    private static final int GPEPORT = 6633;
+    private static final int GPEUDPPORT = 6633;
 
     @Override
     public String getModuleName() {
@@ -235,7 +235,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     public Option[] getPropertiesOptions() {
         return new Option[] {
                 propagateSystemProperties(SERVER_IPADDRESS, SERVER_PORT, CONNECTION_TYPE,
-                        CONTROLLER_IPADDRESS, OVSDB_TRACE, OVSDB_WAIT),
+                        CONTROLLER_IPADDRESS, OVSDB_TRACE, OVSDB_WAIT, USERSPACE_ENABLED),
         };
     }
 
@@ -255,9 +255,9 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
                         "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc",
                         LogLevel.TRACE.name()),
-                //editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
-                //        "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13",
-                //        LogLevel.TRACE.name()),
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13",
+                        LogLevel.TRACE.name()),
                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
                         "log4j.logger.org.opendaylight.sfc",
                         LogLevel.TRACE.name()),
@@ -275,8 +275,11 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         addressStr = props.getProperty(SERVER_IPADDRESS);
         portStr = props.getProperty(SERVER_PORT, DEFAULT_SERVER_PORT);
         connectionType = props.getProperty(CONNECTION_TYPE, "active");
-        LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}",
-                connectionType, addressStr, portStr);
+        controllerStr = props.getProperty(CONTROLLER_IPADDRESS, "0.0.0.0");
+        userSpaceEnabled = props.getProperty(USERSPACE_ENABLED, "no");
+        LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}, controller ip: {}, " +
+                        "userspace.enabled: {}",
+                connectionType, addressStr, portStr, controllerStr, userSpaceEnabled);
         if (connectionType.equalsIgnoreCase(CONNECTION_TYPE_ACTIVE)) {
             if (addressStr == null) {
                 fail(usage());
@@ -284,7 +287,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         }
         LOG.info("getProperties {}: {}", OVSDB_TRACE, props.getProperty(OVSDB_TRACE));
         LOG.info("getProperties {}: {}", OVSDB_WAIT, props.getProperty(OVSDB_WAIT));
-        if (props.getProperty(OVSDB_WAIT).equals("true")) {
+        if (props.getProperty(OVSDB_WAIT) != null && props.getProperty(OVSDB_WAIT).equals("true")) {
             ovsdb_wait = true;
         }
     }
@@ -313,6 +316,9 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
         assertNotNull("southbound should not be null", southbound);
+        pipelineOrchestrator =
+                (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
+        assertNotNull("pipelineOrchestrator should not be null", pipelineOrchestrator);
         setup.set(true);
     }
 
@@ -446,6 +452,13 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         testModelDelete(builder, clazz);
     }
 
+    private <T extends DataObject> void testModel(Builder<T> builder, Class<T> clazz)
+            throws InterruptedException {
+        testModelPut(builder, clazz);
+        Thread.sleep(1000);
+        testModelDelete(builder, clazz);
+    }
+
     private ServiceFunctionsBuilder serviceFunctionsBuilder() {
         String sf1Name = SF1NAME;
         String sf1Ip = SF1IP;
@@ -461,7 +474,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         String sf2DplName = SF2DPLNAME;
         String sn2Name = SN2NAME;
         String bridge2Name= BRIDGE2NAME;
-        int port = GPEPORT;
+        int port = GPEUDPPORT;
 
         ServiceFunctionBuilder serviceFunctionBuilder =
                 serviceFunctionUtils.serviceFunctionBuilder(sf1Ip, port, sf1DplName, sff1Name, sf1Name);
@@ -497,7 +510,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         String sn2Name = SN2NAME;
         String bridge2Name= BRIDGE2NAME;
         String aclName = ACLNAME;
-        int port = GPEPORT;
+        int port = GPEUDPPORT;
 
         ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder =
                 serviceFunctionForwarderUtils.serviceFunctionForwarderBuilder(
@@ -562,24 +575,84 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
 
     @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);
+        int timeout = 1000;
+        testModel(serviceFunctionsBuilder(), ServiceFunctions.class, timeout);
+        testModel(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class, timeout);
+        testModel(serviceFunctionChainsBuilder(), ServiceFunctionChains.class, timeout);
+        testModel(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class, timeout);
     }
 
     @Test
     public void testSfcModels() throws InterruptedException {
+        testModel(serviceFunctionsBuilder(), ServiceFunctions.class);
+        testModel(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class);
+        testModel(serviceFunctionChainsBuilder(), ServiceFunctionChains.class);
+        testModel(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class);
+
+        testModel(accessListsBuilder(), AccessLists.class);
+        testModel(classifiersBuilder(), Classifiers.class);
+    }
+
+    /**
+     * Test that the NetvirtSfc SfcClassifierService is added to the Netvirt pipeline.
+     * @throws InterruptedException
+     */
+    @Test
+    public void testNetvirtSfcPipeline() throws InterruptedException {
         String bridgeName = INTEGRATION_BRIDGE_NAME;
-        ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(addressStr, portStr);
+        ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
+        assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
+        Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
+        assertNotNull("node is not connected", ovsdbNode);
+
+        assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
+                + " is not connected", isControllerConnected(connectionInfo));
+
+        Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
+        assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
+        long datapathId = southbound.getDataPathId(bridgeNode);
+        String datapathIdString = southbound.getDatapathId(bridgeNode);
+        LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
+        assertNotEquals("datapathId was not found", datapathId, 0);
+
+        String flowId = "DEFAULT_PIPELINE_FLOW_" + Service.SFC_CLASSIFIER.getTable();
+        verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
+
+        assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
+        Thread.sleep(1000);
+        assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
+    }
+
+    /**
+     * Test the full NetvirtSfc functionality by creating everything needed to realize a chain and
+     * then verify all flows have been created.
+     * NOTE: This test requires an OVS with the NSH v8 patch, otherwise it will fail miserably.
+     * @throws InterruptedException
+     */
+    @Test
+    public void testNetvirtSfcAll() throws InterruptedException {
+        if (userSpaceEnabled.equals("yes")) {
+            LOG.info("testNetvirtSfcAll: skipping test because userSpaceEnabled {}", userSpaceEnabled);
+            return;
+        }
+        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);
+        assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
+                + " is not connected", isControllerConnected(connectionInfo));
+
         Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
         assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
         long datapathId = southbound.getDataPathId(bridgeNode);
+        String datapathIdString = southbound.getDatapathId(bridgeNode);
+        LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
+        assertNotEquals("datapathId was not found", datapathId, 0);
+
+        String flowId = "DEFAULT_PIPELINE_FLOW_" + Service.SFC_CLASSIFIER.getTable();
+        verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
 
         Map<String, String> externalIds = Maps.newHashMap();
         externalIds.put("attached-mac", "f6:00:00:0f:00:01");
@@ -588,86 +661,50 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         southboundUtils.addTerminationPoint(bridgeNode, "vm2", "internal");
         Map<String, String> options = Maps.newHashMap();
         options.put("key", "flow");
+        options.put("dst_port", String.valueOf(GPEUDPPORT));
+        options.put("remote_ip", "flow");
+        options.put("nshc1", "flow");
+        options.put("nshc2", "flow");
+        options.put("nsp", "flow");
+        options.put("nsi", "flow");
+        southboundUtils.addTerminationPoint(bridgeNode, "vxgpe", "vxlan", options, null);
+        options.clear();
+        options.put("key", "flow");
         options.put("remote_ip", "192.168.120.32");
         southboundUtils.addTerminationPoint(bridgeNode, "vx", "vxlan", options, null);
-        Thread.sleep(1000);
+        long vxGpeOfPort = getOFPort(bridgeNode, "vxgpe");
 
         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);
-
         readwait();
 
-        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);
+        flowId = "sfcIngressClass_" + "httpRule";
+        verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
+        flowId = "sfcTable_" + vxGpeOfPort;
+        verifyFlow(datapathId, flowId, Service.CLASSIFIER);
+        flowId = "sfEgress_" + GPEUDPPORT;
+        verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
+        flowId = "sfIngress_" + GPEUDPPORT + "_" + SF1IP;
+        verifyFlow(datapathId, flowId, Service.CLASSIFIER);
+        flowId = "ArpResponder_" + SF1IP;
+        verifyFlow(datapathId, flowId, Service.CLASSIFIER);
 
         assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
         Thread.sleep(1000);
         assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
     }
 
-    /*
-     * Connect to an ovsdb node. Netvirt should add br-int, add the controller address
-     * and program the pipeline flows.
+    /**
+     * Test the standalone NetvirtSfc implementation
+     * NOTE: This test requires an OVS with the NSH v8 patch, otherwise it will fail miserably.
+     * @throws InterruptedException
      */
-    @Test
-    public void testNetvirtSfc() 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);
-        ControllerEntry controllerEntry;
-        // Loop 10s checking if the controller was added
-        for (int i = 0; i < 10; i++) {
-            ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
-            assertNotNull("ovsdb node not found", ovsdbNode);
-            String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
-            assertNotNull("Failed to get controller target", controllerTarget);
-            OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, bridgeName);
-            if (bridge != null) {
-                assertNotNull("Failed to read bridge", bridge);
-                assertNotNull("Failed to extract controllerEntry", bridge.getControllerEntry());
-                controllerEntry = bridge.getControllerEntry().iterator().next();
-                assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
-                if (controllerEntry.isIsConnected()) {
-                    Assert.assertTrue("switch is not connected to the controller", controllerEntry.isIsConnected());
-                    break;
-                }
-            }
-            Thread.sleep(1000);
-        }
-
-        Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
-        assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
-        long datapathId = southbound.getDataPathId(bridgeNode);
-
-        //Thread.sleep(10000);
-
-        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
-        FlowBuilder flowBuilder = FlowUtils.getPipelineFlow(Service.SFC_CLASSIFIER.getTable(), (short)0);
-        Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
-        assertNotNull("Could not find flow in config", flow);
-        flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
-        assertNotNull("Could not find flow in operational", flow);
-
-        assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
-        Thread.sleep(1000);
-        assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
-    }
-
     @Ignore
     @Test
     public void testStandalone() throws InterruptedException {
@@ -676,31 +713,21 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
         Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
         assertNotNull("node is not connected", ovsdbNode);
+
         String controllerTarget = "tcp:192.168.50.1:6653";
         List<ControllerEntry> setControllerEntry = southboundUtils.createControllerEntry(controllerTarget);
         Assert.assertTrue(southboundUtils.addBridge(connectionInfo, null, bridgeName, null, true,
                 SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
                 setControllerEntry, null, "00:00:00:00:00:00:00:01"));
-        // Loop 10s checking if the controller was added
-        for (int i = 0; i < 10; i++) {
-            ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
-            assertNotNull("ovsdb node not found", ovsdbNode);
-            assertNotNull("Failed to get controller target", controllerTarget);
-            OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, bridgeName);
-            assertNotNull(bridge);
-            assertNotNull(bridge.getControllerEntry());
-            ControllerEntry controllerEntry = bridge.getControllerEntry().iterator().next();
-            assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
-            if (controllerEntry.isIsConnected()) {
-                Assert.assertTrue(controllerEntry.isIsConnected());
-                break;
-            }
-            Thread.sleep(1000);
-        }
+        assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
+                + " is not connected", isControllerConnected(connectionInfo));
 
         Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
         assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
         long datapathId = southbound.getDataPathId(bridgeNode);
+        String datapathIdString = southbound.getDatapathId(bridgeNode);
+        LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
+        assertNotEquals("datapathId was not found", datapathId, 0);
 
         SfcClassifier sfcClassifier = new SfcClassifier(dataBroker, southbound, mdsalUtils);
         //sfcClassifier.programLocalInPort(datapathId, "4096", (long)1, (short)0, (short)50, true);
@@ -711,7 +738,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         sfcClassifier.programSfcClassiferFlows(datapathId, (short)0, "test", matchesBuilder.build(),
                 nshUtils, (long)2, true);
 
-        nshUtils = new NshUtils(null, null, (long)10, (short)253, 0, 0);
+        //nshUtils = new NshUtils(null, null, (long)10, (short)253, 0, 0);
         //sfcClassifier.programEgressSfcClassiferFlows(datapathId, (short)0, "test", null,
         //        nshUtils, (long)2, (long)3, true);
 
@@ -722,23 +749,27 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         //}
 
         //NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
-        //FlowBuilder flowBuilder = getLocalInPortFlow(datapathId, "4096", (long) 1, (short) 0);
+        //FlowBuilder flowBuilder = getLocalInPortFlow(datapathId, "4096", (long) 1,
+        //                                             pipelineOrchestrator.getTable(Service.CLASSIFIER));
         //Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
         //assertNotNull("Could not find flow in config", flow);
         //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
         //assertNotNull("Could not find flow in operational", flow);
 
-        MatchBuilder matchBuilder = sfcClassifier.buildMatch(matchesBuilder.build());
-        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
-        FlowBuilder flowBuilder = getSfcClassifierFlow(datapathId, (short) 0, "test", null,
-                nshUtils, (long) 2, matchBuilder);
-        Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
-        assertNotNull("Could not find flow in config", flow);
-        flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
-        assertNotNull("Could not find flow in operational", flow);
+        //MatchBuilder matchBuilder = sfcClassifier.buildMatch(matchesBuilder.build());
+        //NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
+        //FlowBuilder flowBuilder = getSfcClassifierFlow(datapathId,
+        //        pipelineOrchestrator.getTable(Service.CLASSIFIER), "test", null,
+        //        nshUtils, (long) 2, matchBuilder);
+        //Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+        //assertNotNull("Could not find flow in config", flow);
+        //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+        //assertNotNull("Could not find flow in operational", flow);
 
         //nodeBuilder = FlowUtils.createNodeBuilder(datapathId);
-        //flowBuilder = getEgressSfcClassifierFlow(datapathId, (short) 0, "test", nshUtils, (long) 2);
+        //flowBuilder = getEgressSfcClassifierFlow(datapathId,
+                                                   //pipelineOrchestrator.getTable(Service.CLASSIFIER),
+                                                   //"test", nshUtils, (long) 2);
         //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
         //assertNotNull("Could not find flow in config", flow);
         //flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
@@ -753,85 +784,18 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
     }
 
-    private FlowBuilder getLocalInPortFlow(long dpidLong, String segmentationId, long inPort, short writeTable) {
-        MatchBuilder matchBuilder = new MatchBuilder();
-
-        FlowBuilder flowBuilder = new FlowBuilder();
-
-        flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort).build());
-        String flowId = "sfcIngress_" + segmentationId + "_" + inPort;
-        flowBuilder.setId(new FlowId(flowId));
-        FlowKey key = new FlowKey(new FlowId(flowId));
-        flowBuilder.setStrict(true);
-        flowBuilder.setBarrier(false);
-        flowBuilder.setTableId(writeTable);
-        flowBuilder.setKey(key);
-        flowBuilder.setFlowName(flowId);
-        flowBuilder.setHardTimeout(0);
-        flowBuilder.setIdleTimeout(0);
-        return flowBuilder;
-    }
-
-    public FlowBuilder getSfcClassifierFlow(long dpidLong, short writeTable, String ruleName, Matches match,
-                                             NshUtils nshHeader, long tunnelOfPort, MatchBuilder matchBuilder) {
-        FlowBuilder flowBuilder = new FlowBuilder();
-
-        flowBuilder.setMatch(matchBuilder.build());
-
-        String flowId = "sfcClass_" + ruleName + "_" + nshHeader.getNshNsp();
-        flowBuilder.setId(new FlowId(flowId));
-        FlowKey key = new FlowKey(new FlowId(flowId));
-        flowBuilder.setBarrier(true);
-        flowBuilder.setTableId(writeTable);
-        flowBuilder.setKey(key);
-        flowBuilder.setFlowName(flowId);
-        flowBuilder.setHardTimeout(0);
-        flowBuilder.setIdleTimeout(0);
-        return flowBuilder;
-    }
-
-    private FlowBuilder getEgressSfcClassifierFlow(long dpidLong, short writeTable, String ruleName,
-                                                   NshUtils nshHeader, long tunnelOfPort) {
-        FlowBuilder flowBuilder = new FlowBuilder();
-
-        MatchBuilder matchBuilder = new MatchBuilder();
-        flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, tunnelOfPort).build());
-        flowBuilder.setMatch(
-                MatchUtils.createTunnelIDMatch(matchBuilder, BigInteger.valueOf(nshHeader.getNshNsp())).build());
-        flowBuilder.setMatch(MatchUtils.addNxNspMatch(matchBuilder, nshHeader.getNshNsp()).build());
-        flowBuilder.setMatch(MatchUtils.addNxNsiMatch(matchBuilder, nshHeader.getNshNsi()).build());
-
-        String flowId = "egressSfcClass_" + ruleName + "_" + nshHeader.getNshNsp() + "_" + nshHeader.getNshNsi();
-        flowBuilder.setId(new FlowId(flowId));
-        FlowKey key = new FlowKey(new FlowId(flowId));
-        flowBuilder.setStrict(true);
-        flowBuilder.setBarrier(false);
-        flowBuilder.setTableId(writeTable);
-        flowBuilder.setKey(key);
-        flowBuilder.setFlowName(flowId);
-        flowBuilder.setHardTimeout(0);
-        flowBuilder.setIdleTimeout(0);
-        return flowBuilder;
-    }
-
-    private FlowBuilder getSfcIngressClassifierFlowBuilder() {
-        FlowBuilder flowBuilder = new FlowBuilder();
-        String flowId = "sfcIngressClass_" + "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 {
+    private Flow getFlow (
+            FlowBuilder flowBuilder,
+            org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder,
+            LogicalDatastoreType store) throws InterruptedException {
+
         Flow flow = null;
         for (int i = 0; i < 10; i++) {
+            LOG.info("getFlow try {} from {}: looking for flow: {}, node: {}",
+                    i, store, flowBuilder.build(), nodeBuilder.build());
             flow = FlowUtils.getFlow(flowBuilder, nodeBuilder, dataBroker.newReadOnlyTransaction(), store);
             if (flow != null) {
-                LOG.info("getFlow: flow: {}: {}", store, flow);
+                LOG.info("getFlow try {} from {}: found flow: {}", i, store, flow);
                 break;
             }
             Thread.sleep(1000);
@@ -839,6 +803,17 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         return flow;
     }
 
+    private void verifyFlow(long datapathId, String flowId, Service service) throws InterruptedException {
+        org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
+                FlowUtils.createNodeBuilder(datapathId);
+        FlowBuilder flowBuilder =
+                FlowUtils.initFlowBuilder(new FlowBuilder(), flowId, pipelineOrchestrator.getTable(service));
+        Flow flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.CONFIGURATION);
+        assertNotNull("Could not find flow in config: " + flowBuilder.build() + "--" + nodeBuilder.build(), flow);
+        flow = getFlow(flowBuilder, nodeBuilder, LogicalDatastoreType.OPERATIONAL);
+        assertNotNull("Could not find flow in operational: " + flowBuilder.build() + "--" + nodeBuilder.build(), flow);
+    }
+
     private void readwait() {
         if (ovsdb_wait) {
             LOG.warn("Waiting, kill with ps -ef | grep java, kill xxx... ");
@@ -849,4 +824,65 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
             }
         }
     }
+
+    private boolean isControllerConnected(ConnectionInfo connectionInfo) throws InterruptedException {
+        LOG.info("isControllerConnected enter");
+        Boolean connected = false;
+        ControllerEntry controllerEntry;
+        Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
+        assertNotNull("ovsdb node not found", ovsdbNode);
+
+        BridgeConfigurationManager bridgeConfigurationManager =
+                (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
+        assertNotNull("Could not find BridgeConfigurationManager Service", bridgeConfigurationManager);
+        String controllerTarget = bridgeConfigurationManager.getControllersFromOvsdbNode(ovsdbNode).get(0);
+        Assert.assertNotNull("Failed to get controller target", controllerTarget);
+
+        for (int i = 0; i < 10; i++) {
+            LOG.info("isControllerConnected try {}: looking for controller: {}", i, controllerTarget);
+            OvsdbBridgeAugmentation bridge =
+                    southboundUtils.getBridge(connectionInfo, INTEGRATION_BRIDGE_NAME);
+            Assert.assertNotNull(bridge);
+            Assert.assertNotNull(bridge.getControllerEntry());
+            controllerEntry = bridge.getControllerEntry().iterator().next();
+            Assert.assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
+            if (controllerEntry.isIsConnected()) {
+                Assert.assertTrue("Controller is not connected", controllerEntry.isIsConnected());
+                connected = true;
+                break;
+            }
+            Thread.sleep(1000);
+        }
+        LOG.info("isControllerConnected exit: {} - {}", connected, controllerTarget);
+        return connected;
+    }
+
+    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 < 10; i++) {
+                LOG.info("Looking for ofPort {}, try: {}", portName, i);
+                TerminationPoint tp = southbound.readTerminationPoint(bridgeNode, null, portName);
+                if (tp != null) {
+                    port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                    if (port != null) {
+                        ofPort = southbound.getOFPort(port);
+                        LOG.info("found ofPort {} - {}, try: {}", portName, ofPort, i);
+                        break;
+                    }
+                }
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException e) {
+                    LOG.error("Interrupted while waiting for ofPort {}", portName, e);
+                }
+            }
+        }
+        return ofPort;
+    }
 }
index 7657f2eee31f6ee07089e16679a761ba7d4d3544..85eb8295e8c220119595a066411d5d41b904589c 100644 (file)
@@ -23,17 +23,24 @@ 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.ietf.params.xml.ns.yang.ietf.packet.fields.rev150611.acl.transport.header.fields.SourcePortRange;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev150611.acl.transport.header.fields.SourcePortRangeBuilder;
 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) {
+        SourcePortRangeBuilder sourcePortRangeBuilder = new SourcePortRangeBuilder()
+                .setLowerPort(PortNumber.getDefaultInstance("0"))
+                .setUpperPort(PortNumber.getDefaultInstance("0"));
+
         PortNumber portNumber = new PortNumber(destPort);
         DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder()
                 .setLowerPort(portNumber)
                 .setUpperPort(portNumber);
 
         AceIpBuilder aceIpBuilder = new AceIpBuilder()
+                .setSourcePortRange(sourcePortRangeBuilder.build())
                 .setDestinationPortRange(destinationPortRangeBuilder.build())
                 .setProtocol((short)6)
                 .setAceIpVersion(new AceIpv4Builder().build());
index 90823bd410dcdd080af0c2e73547e8859d3b1a20..b42dcedc1f6a9eb2978d8430820f622e2f5c5a8e 100644 (file)
@@ -46,7 +46,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
 
   <properties>
     <neutron.model.version>0.6.0-SNAPSHOT</neutron.model.version>
-    <powermock.version>1.5.2</powermock.version>
+    <powermock.version>1.6.4</powermock.version>
     <sonar.jacoco.itReportPath>../net-virt-it/target/jacoco-it.exec</sonar.jacoco.itReportPath>
   </properties>
 
@@ -124,6 +124,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
+      <version>1.10.19</version>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -192,6 +193,24 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           </properties>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-instrument</id>
+            <goals>
+              <goal>instrument</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-restore-instrumented-classes</id>
+            <goals>
+              <goal>restore-instrumented-classes</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>
index e99fbca132a7f3d64aafebfba0a5702ecb40437f..819fb3ee3c1bcee458d355a145a4c064365b1292 100644 (file)
@@ -12,6 +12,7 @@
         <module>
           <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:netvirt:impl">prefix:netvirt-impl</type>
           <name>netvirt-default</name>
+          <conntrack-enabled>false</conntrack-enabled>
           <broker>
             <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
             <name>binding-osgi-broker</name>
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/ClusterAwareMdsalUtils.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/ClusterAwareMdsalUtils.java
new file mode 100644 (file)
index 0000000..e892eaa
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.openstack.netvirt;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/**
+ * Class is a wrapper for MdsalUtils.java class. It wrap all the methods
+ * from MdsalUtils and call it only when *this* instance is net-virt master
+ * instances.
+ *
+ * Created by vishnoianil on 1/11/16.
+ */
+
+public class ClusterAwareMdsalUtils {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClusterAwareMdsalUtils.class);
+    private final MdsalUtils mdsalUtils;
+
+    /**
+     * Class constructor setting the MdsalUtils instance.
+     *
+     * @param dataBroker the {@link org.opendaylight.controller.md.sal.binding.api.DataBroker}
+     */
+    public ClusterAwareMdsalUtils(DataBroker dataBroker) {
+        mdsalUtils = new MdsalUtils(dataBroker);
+    }
+
+    /**
+     * Wrapper method to executes delete as a blocking transaction.
+     *
+     * @param store {@link LogicalDatastoreType} which should be modified
+     * @param path {@link InstanceIdentifier} to read from
+     * @param <D> the data object type
+     * @return the result of the request
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean delete(
+            final LogicalDatastoreType store, final InstanceIdentifier<D> path)  {
+        if (NetvirtProvider.isMasterProviderInstance()) {
+            return mdsalUtils.delete(store,path);
+        }
+        return true;
+    }
+
+    /**
+     * Wrapper method to executes merge as a blocking transaction.
+     *
+     * @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
+     * @param path {@link InstanceIdentifier} for path to read
+     * @param data object of type D
+     * @return the result of the request
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean merge(
+            final LogicalDatastoreType logicalDatastoreType, final InstanceIdentifier<D> path, D data) {
+        if (NetvirtProvider.isMasterProviderInstance()) {
+            return mdsalUtils.merge(logicalDatastoreType,path, data);
+        }
+        return true;
+    }
+
+    /**
+     * Wrapper method to executes put as a blocking transaction.
+     *
+     * @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
+     * @param path {@link InstanceIdentifier} for path to read
+     * @param data object of type D
+     * @return the result of the request
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean put(
+            final LogicalDatastoreType logicalDatastoreType, final InstanceIdentifier<D> path, D data) {
+        if (NetvirtProvider.isMasterProviderInstance()) {
+            return mdsalUtils.put(logicalDatastoreType,path, data);
+        }
+        return true;
+    }
+
+    /**
+     * Wrapper method to executes read as a blocking transaction.
+     * Read is open for all instances to execute their normal
+     * control flow. Because with current implementation all the
+     * net-virt instances execute in similar way, because they want
+     * to build their local caches so that all the instances has same
+     * state of internal cache.
+     *
+     * @param store {@link LogicalDatastoreType} to read
+     * @param path {@link InstanceIdentifier} for path to read
+     * @param <D> the data object type
+     * @return the result as the data object requested
+     */
+    public <D extends org.opendaylight.yangtools.yang.binding.DataObject> D read(
+            final LogicalDatastoreType store, final InstanceIdentifier<D> path)  {
+        return mdsalUtils.read(store,path);
+    }
+}
index 504202cc15f00e7e38e5eb2d8d2166cc42a31bf3..94b0f5a25f763072a17b98654a15190e70b5a101 100644 (file)
@@ -102,6 +102,7 @@ public class ConfigActivator implements BundleActivator {
     private List<ServiceRegistration<?>> translatorCRUDRegistrations = new ArrayList<>();
     private List<Pair<Object, ServiceRegistration>> servicesAndRegistrations = new ArrayList<>();
     private ProviderContext providerContext;
+    private boolean conntrackEnabled = false;
 
     public ConfigActivator(ProviderContext providerContext) {
         this.providerContext = providerContext;
@@ -169,7 +170,7 @@ public class ConfigActivator implements BundleActivator {
                 new Class[] {INeutronSecurityRuleAware.class, INeutronSecurityGroupAware.class},
                 AbstractEvent.HandlerType.NEUTRON_PORT_SECURITY, portSecurityHandler);
 
-        final SecurityServicesImpl securityServices = new SecurityServicesImpl();
+        final SecurityServicesImpl securityServices = new SecurityServicesImpl(conntrackEnabled);
         registerService(context,
                 new String[]{SecurityServicesManager.class.getName()}, null, securityServices);
 
@@ -327,4 +328,8 @@ public class ConfigActivator implements BundleActivator {
         servicesAndRegistrations.add(Pair.of(impl, serviceRegistration));
         return serviceRegistration;
     }
+
+    public void setConntrackEnabled(boolean conntrackEnabled) {
+        this.conntrackEnabled = conntrackEnabled;
+    }
 }
index a6367872f8c41d0dcfbd6025d521032e2ba8f03d..1542cec28c794e51ad38161daeeb443c2061c53f 100644 (file)
@@ -31,6 +31,7 @@ public class NetvirtProvider implements BindingAwareProvider, AutoCloseable {
     private static EntityOwnershipService entityOwnershipService;
     private static final Entity ownerInstanceEntity = new Entity(
             Constants.NETVIRT_OWNER_ENTITY_TYPE, Constants.NETVIRT_OWNER_ENTITY_TYPE);
+    private boolean conntrackEnabled = false;
 
     public NetvirtProvider(BundleContext bundleContext, EntityOwnershipService eos) {
         LOG.info("NetvirtProvider: bundleContext: {}", bundleContext);
@@ -56,11 +57,21 @@ public class NetvirtProvider implements BindingAwareProvider, AutoCloseable {
     public void onSessionInitiated(ProviderContext providerContext) {
         dataBroker = providerContext.getSALService(DataBroker.class);
         LOG.info("NetvirtProvider: onSessionInitiated dataBroker: {}", dataBroker);
+        LOG.info("NetvirtProvider: onSessionInitiated isConntrackEnabled: {}", this.conntrackEnabled);
         this.activator = new ConfigActivator(providerContext);
+        activator.setConntrackEnabled(this.conntrackEnabled);
         try {
             activator.start(bundleContext);
         } catch (Exception e) {
             LOG.warn("Failed to start Netvirt: ", e);
         }
     }
+
+    public boolean isConntrackEnabled() {
+        return conntrackEnabled;
+    }
+
+    public void setConntrackEnabled(boolean conntackEnabled) {
+        this.conntrackEnabled = conntackEnabled;
+    }
 }
index 27611fb228c8cfb6bf6b802f633605b9ffd173aa..d2805c30c641e604970c1a20ae6a89dfa8a4e166 100644 (file)
@@ -19,4 +19,5 @@ public interface ClassifierProvider {
     void programTunnelIn(Long dpidLong, String segmentationId, Long ofPort, boolean write);
     void programVlanIn(Long dpidLong, String segmentationId, Long ethPort, boolean write);
     void programLLDPPuntRule(Long dpidLong);
+    void programGotoTable(Long dpidLong, boolean write);
 }
index 2c9858f2ca3ba440448220bf8c9c6fb9f430cd16..ccdf55bab6cf4f871b39e7f777141baef010cdb9 100644 (file)
@@ -82,7 +82,6 @@ public final class Constants {
     public static final Integer PREFIX_MATCH_PRIORITY_DROP = 36004;
     public static final Integer PROTO_PREFIX_MATCH_PRIORITY_DROP = 36003;
     public static final Integer PREFIX_PORT_MATCH_PRIORITY_DROP = 36002;
-    public static final Integer PROTO_PORT_PREFIX_MATCH_PRIORITY_DROP = 36001;
 
     public static final Integer PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY = 61012;
     public static final Integer PROTO_MATCH_PRIORITY = 61010;
@@ -92,6 +91,10 @@ public final class Constants {
     public static final Integer PROTO_PORT_PREFIX_MATCH_PRIORITY = 61007;
     public static final Integer PROTO_DHCP_SERVER_MATCH_PRIORITY = 61006;
     public static final Integer PROTO_VM_IP_MAC_MATCH_PRIORITY = 36001;
+    public static final Integer CT_STATE_UNTRACKED_PRIORITY = 62030;
+    public static final Integer CT_STATE_TRACKED_EST_PRIORITY = 62020;
+    public static final Integer CT_STATE_TRACKED_NEW_PRIORITY = 62010;
+    public static final Integer CT_STATE_NEW_PRIORITY_DROP = 36007;
 
     public static final int TCP_SYN = 0x002;
     public static final short INGRESS_ACL = 40; // Flows Destined to the VM Port go here
index 6121adaf1b7e48d9608996f902e1572b8c9ee6a3..bb4e7593152959023ba53518e5f7eb6637392dcb 100644 (file)
@@ -50,12 +50,13 @@ public interface IngressAclProvider {
      * *
      * @param dpid the dpid
      * @param segmentationId the segmentation id
-     * @param attachedMac the attached mac
+     * @param attachedMac the dhcp mac
      * @param localPort the local port
      * @param isLastPortinSubnet is this the last port in the subnet
      * @param isComputePort indicates whether this port is a compute port or not
+     * @param attachedMac2 the src mac
      * @param write is this flow writing or deleting
      */
     void programFixedSecurityGroup(Long dpid, String segmentationId, String attachedMac, long localPort,
-                                  boolean isLastPortinSubnet, boolean isComputePort, boolean write);
+                                  boolean isLastPortinSubnet, boolean isComputePort, String attachedMac2, boolean write);
 }
\ No newline at end of file
index f6dcea1a857e373585a926764eb709ca5c4f5c4a..843116c9173f1455c739a76f5ae2bc3903eab7a3 100644 (file)
@@ -104,4 +104,9 @@ public interface SecurityServicesManager {
      * @param write whether to add/delete flow.
      */
     void syncSecurityRule(NeutronPort port, NeutronSecurityRule securityRule,Neutron_IPs vmIp, boolean write);
+    /**
+     * Is connection tracking enabled or not by the user (default is false).
+     * @return whether connection tracking enabled.
+     */
+    boolean isConntrackEnabled();
 }
\ No newline at end of file
index 481da49b4fa2f78a30b24265b81c85b9e12e077f..120e3ce938ddd46ada19f0c78e944fb6d2f15f93 100644 (file)
@@ -14,6 +14,7 @@ import java.util.Set;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.ClusterAwareMdsalUtils;
 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbInventoryService;
@@ -26,7 +27,6 @@ import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronSe
 import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronSubnetChangeListener;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronLoadBalancerPoolChangeListener;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronLoadBalancerPoolMemberChangeListener;
-import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
 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.TopologyId;
@@ -48,13 +48,13 @@ public class OvsdbInventoryServiceImpl implements ConfigInterface, OvsdbInventor
     private static DataBroker dataBroker = null;
     private static Set<OvsdbInventoryListener> ovsdbInventoryListeners = Sets.newCopyOnWriteArraySet();
     private OvsdbDataChangeListener ovsdbDataChangeListener = null;
-    private static MdsalUtils mdsalUtils = null;
+    private static ClusterAwareMdsalUtils mdsalUtils = null;
 
     public OvsdbInventoryServiceImpl(ProviderContext providerContext) {
         dataBroker = providerContext.getSALService(DataBroker.class);
         LOG.info("OvsdbInventoryServiceImpl initialized");
         ovsdbDataChangeListener = new OvsdbDataChangeListener(dataBroker);
-        mdsalUtils = new MdsalUtils(dataBroker);
+        mdsalUtils = new ClusterAwareMdsalUtils(dataBroker);
     }
 
     @Override
index f59980e36fdf2ae475f790dfd96fd478b2e593cc..dc482a130b4ce757acde47f6ded896a38281ccf1 100644 (file)
@@ -36,6 +36,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 public class SecurityServicesImpl implements ConfigInterface, SecurityServicesManager {
+
     private static final Logger LOG = LoggerFactory.getLogger(TenantNetworkManagerImpl.class);
     private volatile INeutronPortCRUD neutronPortCache;
     private volatile INeutronSubnetCRUD neutronSubnetCache;
@@ -44,6 +45,16 @@ public class SecurityServicesImpl implements ConfigInterface, SecurityServicesMa
     private volatile ConfigurationService configurationService;
     private volatile IngressAclProvider ingressAclProvider;
     private volatile EgressAclProvider egressAclProvider;
+    private boolean isConntrackEnabled = false;
+
+    public SecurityServicesImpl() {
+        super();
+    }
+
+    public SecurityServicesImpl(boolean isConntrack) {
+        super();
+        this.isConntrackEnabled = isConntrack;
+    }
 
     @Override
     public boolean isPortSecurityReady(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
@@ -507,4 +518,9 @@ public class SecurityServicesImpl implements ConfigInterface, SecurityServicesMa
             egressAclProvider = (EgressAclProvider) impl;
         }
     }
+
+    @Override
+    public boolean isConntrackEnabled() {
+        return isConntrackEnabled;
+    }
 }
index e280edeb77dd45cf2f7e443cd62247e71df0b64c..a926b93316430b9dd8c0fcfca6d9e1e8d1fe8453 100644 (file)
@@ -16,11 +16,11 @@ import java.util.Map;
 
 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.ClusterAwareMdsalUtils;
 import org.opendaylight.ovsdb.openstack.netvirt.MdsalHelper;
 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
 import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbTables;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
-import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIds;
@@ -65,7 +65,7 @@ public class SouthboundImpl implements Southbound {
     private static final Logger LOG = LoggerFactory.getLogger(SouthboundImpl.class);
     private final DataBroker databroker;
     private static final String PATCH_PORT_TYPE = "patch";
-    private final MdsalUtils mdsalUtils;
+    private final ClusterAwareMdsalUtils mdsalUtils;
 
     /**
      * Class constructor setting the data broker.
@@ -74,7 +74,7 @@ public class SouthboundImpl implements Southbound {
      */
     public SouthboundImpl(DataBroker dataBroker) {
         this.databroker = dataBroker;
-        mdsalUtils = new MdsalUtils(dataBroker);
+        mdsalUtils = new ClusterAwareMdsalUtils(dataBroker);
     }
 
     public DataBroker getDatabroker() {
index 8a43c9c8596b19c2450a9a9012abab4470842dd8..cd5dac96dacc9d7183469ed35ba36d4c4feb0f07 100644 (file)
@@ -23,6 +23,7 @@ public class NetvirtImplModule extends org.opendaylight.yang.gen.v1.urn.opendayl
     @Override
     public java.lang.AutoCloseable createInstance() {
         NetvirtProvider provider = new NetvirtProvider(bundleContext, getClusteringEntityOwnershipServiceDependency());
+        provider.setConntrackEnabled(getConntrackEnabled());
         BindingAwareBroker localBroker = getBrokerDependency();
         localBroker.registerProvider(provider);
         return provider;
index 73042641c2297da4000b751f3daaffacf5a8d404..20572577205066daf3d1525ec0efeaac77e84f75 100644 (file)
@@ -39,6 +39,9 @@ module netvirt-impl {
                     }
                 }
             }
+            leaf conntrack-enabled {
+                type boolean;
+            }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterfaceTest.java b/openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterfaceTest.java
new file mode 100644 (file)
index 0000000..8a812a4
--- /dev/null
@@ -0,0 +1,337 @@
+/**
+ * Copyright (c) 2015 NEC Corporation and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+
+import static org.powermock.api.mockito.PowerMockito.mockStatic;
+import static org.powermock.api.mockito.PowerMockito.mock;
+import static org.powermock.api.mockito.PowerMockito.spy;
+import static org.powermock.api.mockito.PowerMockito.verifyStatic;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFloatingIPCRUD;
+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.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.FloatingipBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Unit test for {@link NeutronFloatingIPInterface}
+ */
+@PrepareForTest({NeutronFloatingIPInterface.class})
+@RunWith(PowerMockRunner.class)
+public class NeutronFloatingIPInterfaceTest {
+    /**
+     * UUID_VALUE used for testing different scenarios.
+     */
+    private static final String UUID_VALUE = "b9a13232-525e-4d8c-be21-cd65e3436034";
+    /**
+     * FIXED_IP_ADDRESS used for testing different scenarios.
+     */
+    private static final String FIXED_IP_ADDRESS = "10.0.0.3";
+    /**
+     * FLOATING_IP_ADDRESS used for testing different scenarios.
+     */
+    private static final String FLOATING_IP_ADDRESS = "172.24.4.228";
+    /**
+     * STATUS used for testing different scenarios.
+     */
+    private static final String STATUS = "ACTIVE";
+    /**
+     * Floatingip object reference for unit testing.
+     */
+    private Floatingip floatingip = new FloatingipBuilder().setUuid(new Uuid(UUID_VALUE)).build();
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#floatingIPExists} is called
+     * and then checks that floating Ip exists or not.
+     */
+    @Test
+    public void testFloatingIPExists() throws Exception {
+        ProviderContext providerContext = mock(ProviderContext.class);
+        DataBroker broker = mock(DataBroker.class);
+        when(providerContext.getSALService(DataBroker.class)).thenReturn(broker);
+        ReadOnlyTransaction readOnlyTransaction = mock(ReadOnlyTransaction.class);
+        when(broker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+        NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+        // First case: floatingIPExists() is expected to return true because the datastore contains a matching floating IP.
+        CheckedFuture succeedingFuture = mock(CheckedFuture.class);
+        when(succeedingFuture.checkedGet()).thenReturn(Optional.of(floatingip));
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(succeedingFuture);
+        assertTrue("Should return true, when floatingIPExists success.", neutronFloatingIPInterface.floatingIPExists(UUID_VALUE));
+        // Second case: the datastore has no matching floating IP, expect false
+        CheckedFuture failingFuture = mock(CheckedFuture.class);
+        when(failingFuture.checkedGet()).thenReturn(Optional.absent());
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(failingFuture);
+        assertFalse("Should return false for negative case.", neutronFloatingIPInterface.floatingIPExists(UUID_VALUE));
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#getFloatingIP} is called
+     * and then checks that it gets floating Ip or not.
+     */
+    @Test
+    public void testGetFloatingIP() throws Exception {
+        ProviderContext providerContext = mock(ProviderContext.class);
+        DataBroker broker = mock(DataBroker.class);
+        when(providerContext.getSALService(DataBroker.class)).thenReturn(broker);
+        ReadOnlyTransaction readOnlyTransaction = mock(ReadOnlyTransaction.class);
+        when(broker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+        NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+        // First case: getFloatingIP is expected to return a valid object.
+        CheckedFuture succeedingFuture = mock(CheckedFuture.class);
+        when(succeedingFuture.checkedGet()).thenReturn(Optional.of(floatingip));
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(succeedingFuture);
+        NeutronFloatingIP neutronFloatingIPReceived = neutronFloatingIPInterface.getFloatingIP(UUID_VALUE);
+        assertEquals("UUID mismatch", UUID_VALUE, neutronFloatingIPReceived.getID());
+        // Second case: getFloatingIP returns null object.
+        CheckedFuture failingFuture = mock(CheckedFuture.class);
+        when(failingFuture.checkedGet()).thenReturn(Optional.absent());
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(failingFuture);
+        assertNull("Should be null for negative case.", neutronFloatingIPInterface.getFloatingIP(UUID_VALUE));
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#getAllFloatingIPs} is called
+     * and then checks that it gets all floating Ips in a list or not.
+     */
+    @Test
+    public void testGetAllFloatingIPs() throws Exception {
+        ProviderContext providerContext = mock(ProviderContext.class);
+        DataBroker broker = mock(DataBroker.class);
+        when(providerContext.getSALService(DataBroker.class)).thenReturn(broker);
+        ReadOnlyTransaction readOnlyTransaction = mock(ReadOnlyTransaction.class);
+        when(broker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+        NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+        // First case: getAllFloatingIPs returns a list of valid objects.
+        CheckedFuture succeedingFuture = mock(CheckedFuture.class);
+        List<Floatingip> floatingipList = new ArrayList<>();
+        floatingipList.add(floatingip);
+        Floatingips floatingips = mock(Floatingips.class);
+        NeutronFloatingIP neutronFloatingIP = mock(NeutronFloatingIP.class);
+        when(floatingips.getFloatingip()).thenReturn(floatingipList);
+        when(succeedingFuture.checkedGet()).thenReturn(Optional.of(floatingips));
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(succeedingFuture);
+        List<NeutronFloatingIP> actualFloatingIps = neutronFloatingIPInterface.getAllFloatingIPs();
+        assertEquals("There should be one floating IP", 1, actualFloatingIps.size());
+        assertEquals("UUID mismatch", UUID_VALUE, actualFloatingIps.get(0).getID());
+        // Second case: getAllFloatingIPs not returns a list of valid objects.
+        CheckedFuture failingFuture = mock(CheckedFuture.class);
+        when(failingFuture.checkedGet()).thenReturn(Optional.absent());
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(failingFuture);
+        assertTrue("Non-empty list of floating IPs", neutronFloatingIPInterface.getAllFloatingIPs().isEmpty());
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#addFloatingIP} is called
+     * and then verifies whether floating Ip already exists in datastore if not then
+     * ensures floating ip addition by invoking MD-SAL add.
+     */
+    @Test
+    public void testAddFloatingIP() throws Exception {
+        ProviderContext providerContext = mock(ProviderContext.class);
+        DataBroker broker = mock(DataBroker.class);
+        WriteTransaction writeTransaction = mock(WriteTransaction.class);
+        NeutronFloatingIP neutronFloatingIP = mock(NeutronFloatingIP.class);
+        when(providerContext.getSALService(DataBroker.class)).thenReturn(broker);
+        ReadOnlyTransaction readOnlyTransaction = mock(ReadOnlyTransaction.class);
+        when(broker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+        NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+        when(neutronFloatingIP.getID()).thenReturn(UUID_VALUE);
+        //First case: addFloatingIP returns false, the datastore has a matching floating IP.
+        CheckedFuture succeedingFuture = mock(CheckedFuture.class);
+        when(succeedingFuture.checkedGet()).thenReturn(Optional.of(floatingip));
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(succeedingFuture);
+        assertFalse("Should return false, floating Ip already exists.", neutronFloatingIPInterface.addFloatingIP(neutronFloatingIP));
+        //Second case: addFloatingIP returns true, the datastore has no matching floating IP, so invokes addMd() to write on datastore.
+        CheckedFuture failingFuture = mock(CheckedFuture.class);
+        when(broker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+        when(failingFuture.checkedGet()).thenReturn(Optional.absent());
+        when(writeTransaction.submit()).thenReturn(failingFuture);
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(failingFuture);
+        assertTrue("Should return true for addFloatingIP success.", neutronFloatingIPInterface.addFloatingIP(neutronFloatingIP));
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#removeFloatingIP} is called
+     * and then verifies by reading floating ip from datastore and ensures floating ip
+     * removal by invoking MD-SAL remove.
+     */
+    @Test
+    public void testRemoveFloatingIP() throws Exception {
+        ProviderContext providerContext = mock(ProviderContext.class);
+        DataBroker broker = mock(DataBroker.class);
+        WriteTransaction writeTransaction = mock(WriteTransaction.class);
+        NeutronFloatingIP neutronFloatingIP = mock(NeutronFloatingIP.class);
+        when(providerContext.getSALService(DataBroker.class)).thenReturn(broker);
+        ReadOnlyTransaction readOnlyTransaction = mock(ReadOnlyTransaction.class);
+        when(broker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+        NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+        when(neutronFloatingIP.getID()).thenReturn(UUID_VALUE);
+        //First case: removeFloatingIP returns true by ensuring floating ip removal in datastore.
+        CheckedFuture succeedingFuture = mock(CheckedFuture.class);
+        when(succeedingFuture.checkedGet()).thenReturn(Optional.of(floatingip));
+        when(writeTransaction.submit()).thenReturn(succeedingFuture);
+        when(broker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(succeedingFuture);
+        assertTrue("Should return true for removeFloatingIP success.", neutronFloatingIPInterface.removeFloatingIP(UUID_VALUE));
+        // Second case: removeFloatingIP returns false for negative case.
+        CheckedFuture failingFuture = mock(CheckedFuture.class);
+        when(broker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+        when(failingFuture.checkedGet()).thenReturn(Optional.absent());
+        when(writeTransaction.submit()).thenReturn(failingFuture);
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(failingFuture);
+        assertFalse("Should return false for negative case.", neutronFloatingIPInterface.removeFloatingIP(UUID_VALUE));
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#updateFloatingIP} is called
+     * and then verifies by reading floating ip from datastore and ensures floating ip
+     * updation by invoking MD-SAL update.
+     */
+    @Test
+    public void testUpdateFloatingIP() throws Exception {
+        ProviderContext providerContext = mock(ProviderContext.class);
+        DataBroker broker = mock(DataBroker.class);
+        WriteTransaction writeTransaction = mock(WriteTransaction.class);
+        NeutronFloatingIP neutronFloatingIP = mock(NeutronFloatingIP.class);
+        when(providerContext.getSALService(DataBroker.class)).thenReturn(broker);
+        ReadOnlyTransaction readOnlyTransaction = mock(ReadOnlyTransaction.class);
+        when(broker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+        NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+        when(neutronFloatingIP.getID()).thenReturn(UUID_VALUE);
+        //First case: updateFloatingIP returns true by ensuring floating ip updation in datastore.
+        CheckedFuture succeedingFuture = mock(CheckedFuture.class);
+        when(succeedingFuture.checkedGet()).thenReturn(Optional.of(floatingip));
+        when(writeTransaction.submit()).thenReturn(succeedingFuture);
+        when(broker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(succeedingFuture);
+        assertTrue("Should return true for updateFloatingIP success.", neutronFloatingIPInterface.updateFloatingIP(UUID_VALUE, neutronFloatingIP));
+        //Second case: updateFloatingIP returns false for negative case.
+        CheckedFuture failingFuture = mock(CheckedFuture.class);
+        when(broker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+        when(failingFuture.checkedGet()).thenReturn(Optional.absent());
+        when(writeTransaction.submit()).thenReturn(failingFuture);
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))).thenReturn(failingFuture);
+        assertFalse("Should return false for negative case.", neutronFloatingIPInterface.updateFloatingIP(UUID_VALUE, neutronFloatingIP));
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#toMd} is called
+     * and then checks that it sets vales into floating Ip.
+     */
+    @Test
+    public void testToMd() throws Exception {
+        ProviderContext providerContext = mock(ProviderContext.class);
+        DataBroker broker = mock(DataBroker.class);
+        when(providerContext.getSALService(DataBroker.class)).thenReturn(broker);
+        NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+        NeutronFloatingIP neutronFloatingIP = new NeutronFloatingIP();
+        neutronFloatingIP.setID(UUID_VALUE);
+        neutronFloatingIP.setFloatingNetworkUUID(UUID_VALUE);
+        neutronFloatingIP.setPortUUID(UUID_VALUE);
+        neutronFloatingIP.setFixedIPAddress(FIXED_IP_ADDRESS);
+        neutronFloatingIP.setFloatingIPAddress(FLOATING_IP_ADDRESS);
+        neutronFloatingIP.setTenantUUID(UUID_VALUE);
+        neutronFloatingIP.setRouterUUID(UUID_VALUE);
+        neutronFloatingIP.setStatus(STATUS);
+        Floatingip floatingipReceived = neutronFloatingIPInterface.toMd(neutronFloatingIP);
+        assertEquals("UUID mismatch", UUID_VALUE, String.valueOf(floatingipReceived.getUuid().getValue()));
+        assertEquals("FloatingNetworkId mismatch", UUID_VALUE, String.valueOf(floatingipReceived.getFloatingNetworkId().getValue()));
+        assertEquals("Port ID mismatch", UUID_VALUE, String.valueOf(floatingipReceived.getPortId().getValue()));
+        assertEquals("Fixed IP Address mismatch", FIXED_IP_ADDRESS, String.valueOf(floatingipReceived.getFixedIpAddress().getValue()));
+        assertEquals("Floating IP Address mismatch", FLOATING_IP_ADDRESS, String.valueOf(floatingipReceived.getFloatingIpAddress().getValue()));
+        assertEquals("Tenant Id mismatch", UUID_VALUE, String.valueOf(floatingipReceived.getTenantId().getValue()));
+        assertEquals("Router Id mismatch", UUID_VALUE, String.valueOf(floatingipReceived.getRouterId().getValue()));
+        assertEquals("Status mismatch", STATUS, String.valueOf(floatingipReceived.getStatus()));
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#fromMd} is called
+     * and then checks that it gets values from Floating Ip.
+     */
+    @Test
+    public void testFromMd() throws Exception {
+        ProviderContext providerContext = mock(ProviderContext.class);
+        DataBroker broker = mock(DataBroker.class);
+        when(providerContext.getSALService(DataBroker.class)).thenReturn(broker);
+        Floatingip actualfloatingip = new FloatingipBuilder()
+                .setUuid(new Uuid(UUID_VALUE))
+                .setFixedIpAddress(
+                        new IpAddress(FIXED_IP_ADDRESS.toCharArray()))
+                .setFloatingIpAddress(
+                        new IpAddress(FLOATING_IP_ADDRESS.toCharArray()))
+                .setFloatingNetworkId(new Uuid(UUID_VALUE))
+                .setPortId(new Uuid(UUID_VALUE))
+                .setRouterId(new Uuid(UUID_VALUE)).setStatus(STATUS)
+                .setTenantId(new Uuid(UUID_VALUE)).build();
+        NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+        NeutronFloatingIP neutronFloatingIPReceived = neutronFloatingIPInterface.fromMd(actualfloatingip);
+        assertEquals("UUID mismatch", UUID_VALUE, neutronFloatingIPReceived.getID());
+        assertEquals("FloatingNetworkId mismatch", UUID_VALUE, neutronFloatingIPReceived.getFloatingNetworkUUID());
+        assertEquals("Port ID mismatch", UUID_VALUE, neutronFloatingIPReceived.getPortUUID());
+        assertEquals("Fixed IP Address mismatch", FIXED_IP_ADDRESS, neutronFloatingIPReceived.getFixedIPAddress());
+        assertEquals("Floating IP Address mismatch", FLOATING_IP_ADDRESS, neutronFloatingIPReceived.getFloatingIPAddress());
+        assertEquals("Tenant Id mismatch", UUID_VALUE, neutronFloatingIPReceived.getTenantUUID());
+        assertEquals("Router Id mismatch", UUID_VALUE, neutronFloatingIPReceived.getRouterUUID());
+        assertEquals("Status mismatch", STATUS, neutronFloatingIPReceived.getStatus());
+    }
+
+    /**
+     * Test that checks if @{NeutronFloatingIPInterface#registerNewInterface} is called
+     * and then checks that it register service or not.
+     */
+    @Ignore
+    @Test
+    public void testRegisterNewInterface() throws Exception {
+        ProviderContext providerContext = mock(ProviderContext.class);
+        DataBroker broker = mock(DataBroker.class);
+        BundleContext bundleContext = mock(BundleContext.class);
+        ServiceRegistration serviceRegistration = mock(ServiceRegistration.class);
+        mockStatic(NeutronFloatingIPInterface.class);
+        List<ServiceRegistration<?>> serviceRegistrationList = new ArrayList<>();
+        serviceRegistrationList.add(serviceRegistration);
+        when(providerContext.getSALService(DataBroker.class)).thenReturn(broker);
+        NeutronFloatingIPInterface neutronFloatingIPInterface = spy(new NeutronFloatingIPInterface(providerContext));
+        when(bundleContext.registerService(INeutronFloatingIPCRUD.class, neutronFloatingIPInterface, null)).thenReturn(serviceRegistration);
+        NeutronFloatingIPInterface.registerNewInterface(bundleContext, providerContext, serviceRegistrationList);
+        verifyStatic();
+        NeutronFloatingIPInterface.registerNewInterface(any(BundleContext.class), any(ProviderContext.class), any(List.class));
+    }
+}
\ No newline at end of file
index 8e414710ba9d4377a69b99f0f8624443f9025734..0376bd9eb810e2bec127ea459983152851ee6074 100644 (file)
@@ -46,7 +46,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   </scm>
 
   <properties>
-    <powermock.version>1.5.2</powermock.version>
+    <powermock.version>1.6.4</powermock.version>
   </properties>
 
   <dependencies>
@@ -54,6 +54,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
+      <version>1.10.19</version>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -75,4 +76,27 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <version>${powermock.version}</version>
     </dependency>
   </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-instrument</id>
+            <goals>
+              <goal>instrument</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-restore-instrumented-classes</id>
+            <goals>
+              <goal>restore-instrumented-classes</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
 </project>
index c3b878c593b0a00402facf842654f15d68438114..403e2e00aeaf2d041ca0c03f01a5bcd6d08a20c9 100644 (file)
@@ -35,12 +35,39 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.acti
 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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.OfjNxHashFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.OfjNxMpAlgorithm;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.DstChoice;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxArpShaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxArpThaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc1CaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc2CaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIdCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIpv4DstCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfArpOpCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfArpSpaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfArpTpaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfEthDstCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.group.buckets.bucket.action.action.NxActionRegLoadNodesNodeGroupBucketsBucketActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.group.buckets.bucket.action.action.NxActionRegMoveNodesNodeGroupBucketsBucketActionsCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionConntrackNodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionMultipathNodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionOutputRegNodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegMoveNodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionResubmitNodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc1NodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc2NodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc3NodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc4NodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNsiNodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNspNodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.conntrack.grouping.NxConntrack;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.conntrack.grouping.NxConntrackBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.multipath.grouping.NxMultipath;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.multipath.grouping.NxMultipathBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.NxOutputReg;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.NxOutputRegBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
@@ -49,6 +76,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.reg.move.grouping.NxRegMove;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.NxRegMoveBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.nx.reg.move.SrcBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.resubmit.grouping.NxResubmit;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.resubmit.grouping.NxResubmitBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._1.grouping.NxSetNshc1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._1.grouping.NxSetNshc1Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._2.grouping.NxSetNshc2;
@@ -57,6 +86,10 @@ 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._3.grouping.NxSetNshc3Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._4.grouping.NxSetNshc4;
 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.nx.action.set.nsi.grouping.NxSetNsi;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsi.grouping.NxSetNsiBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsp.grouping.NxSetNsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsp.grouping.NxSetNspBuilder;
 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;
@@ -403,6 +436,17 @@ public final class ActionUtils {
         return new NxActionMultipathNodesNodeTableFlowApplyActionsCaseBuilder().setNxMultipath(r).build();
     }
 
+    public static Action nxConntrackAction(Integer flags, Long zoneSrc,
+                                           Integer conntrackZone, Short recircTable) {
+        NxConntrack r = new NxConntrackBuilder()
+            .setFlags(flags)
+            .setZoneSrc(zoneSrc)
+            .setConntrackZone(conntrackZone)
+            .setRecircTable(recircTable)
+            .build();
+        return new NxActionConntrackNodesNodeTableFlowApplyActionsCaseBuilder().setNxConntrack(r).build();
+    }
+
     /**
      * Accepts a MAC address and returns the corresponding long, where the
      * MAC bytes are set on the lower order bytes of the long.
index 33228f9ea40143110a3a8510b9ebc6eb9e93451a..bbb93d8b5532b7363db72a76051b9572f5200604 100644 (file)
@@ -45,6 +45,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev14
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmOfEthDst;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.ExtensionKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlowBuilder;
@@ -53,6 +54,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ge
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionListBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxCtStateKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxCtZoneKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg0Key;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg1Key;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg2Key;
@@ -66,14 +69,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfTcpSrcKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfUdpDstKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfUdpSrcKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.ct.state.grouping.NxmNxCtStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.ct.zone.grouping.NxmNxCtZoneBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.reg.grouping.NxmNxRegBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.tun.id.grouping.NxmNxTunIdBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNspKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsp.grouping.NxmNxNspBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNsiKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsi.grouping.NxmNxNsiBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.tcp.dst.grouping.NxmOfTcpDstBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.eth.dst.grouping.NxmOfEthDstBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.tcp.src.grouping.NxmOfTcpSrcBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.tcp.dst.grouping.NxmOfTcpDstBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.udp.dst.grouping.NxmOfUdpDstBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.udp.src.grouping.NxmOfUdpSrcBuilder;
 import org.slf4j.Logger;
@@ -1161,6 +1167,37 @@ public class MatchUtils {
         return matchBuilder;
     }
 
+    public static MatchBuilder addCtState(MatchBuilder matchBuilder,int ct_state, int mask) {
+        NxmNxCtStateBuilder ctStateBuilder = new NxmNxCtStateBuilder();
+        ctStateBuilder.setCtState((long)ct_state);
+        ctStateBuilder.setMask((long)mask);
+        NxAugMatchNodesNodeTableFlow nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder()
+        .setNxmNxCtState(ctStateBuilder.build())
+        .build();
+        GeneralAugMatchNodesNodeTableFlow genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+        .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmNxCtStateKey.class)
+                                           .setExtension(new ExtensionBuilder()
+                                           .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                         .build()).build())).build();
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, genAugMatch);
+        return matchBuilder;
+    }
+
+    public static MatchBuilder addCtZone(MatchBuilder matchBuilder,int ct_zone) {
+        NxmNxCtZoneBuilder ctZoneBuilder = new NxmNxCtZoneBuilder();
+        ctZoneBuilder.setCtZone(ct_zone);
+        NxAugMatchNodesNodeTableFlow nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder()
+        .setNxmNxCtZone(ctZoneBuilder.build())
+        .build();
+        GeneralAugMatchNodesNodeTableFlow genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+        .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmNxCtZoneKey.class)
+                                           .setExtension(new ExtensionBuilder()
+                                           .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                         .build()).build())).build();
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, genAugMatch);
+        return matchBuilder;
+    }
+
     public static class RegMatch {
         final Class<? extends NxmNxReg> reg;
         final Long value;
index fba5f0902d7711c1a888e0a4e5c3a8b0e8d0d920..dd99e667bd007e53b4760dbbcb855e8f8270468f 100644 (file)
@@ -45,7 +45,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   </scm>
 
   <properties>
-    <powermock.version>1.5.2</powermock.version>
+    <powermock.version>1.6.4</powermock.version>
   </properties>
 
   <dependencies>
@@ -65,6 +65,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
+      <version>1.10.19</version>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -111,6 +112,24 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           </instructions>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-instrument</id>
+            <goals>
+              <goal>instrument</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>default-restore-instrumented-classes</id>
+            <goals>
+              <goal>restore-instrumented-classes</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>