Add support for table offset
authorSam Hague <shague@redhat.com>
Mon, 11 Jan 2016 19:57:15 +0000 (14:57 -0500)
committerSam Hague <shague@redhat.com>
Tue, 12 Jan 2016 16:34:16 +0000 (11:34 -0500)
This commit adds a new config parameter table-offset to
allow setting the openflow table base. The default value is 0.
The user can change the value via the config file
netvirt-providers-impl-default-config.xml or by using the restconf
api show below. The value used must be between 1 and 145 - with 145
coming from 255-110 - 110 is the max table in the netvirt pipeline.

The following curl commands can be used to configure the value:
- Get the current value:
curl -u admin:admin http://localhost:8181/restconf/config/netvirt-providers-config:netvirt-providers-config
- Change the value: In this example the value is changed to 1
curl -u admin:admin http://localhost:8181/restconf/config/netvirt-providers-config:netvirt-providers-config -i -H "Content-Type: application/json" --data '{"netvirt-providers-config": {"table-offset": 1}}' -X PUT

If the table-offset is set, then an extra flow is added to the br-ex and br-int
switches to steer packets from table 0 to the first table in the pipeline.

IT tests were all updated to check for the new table-offsets as well as
adding unti-tests. Some IT tests have a little more due to the Yang
pacth that enforces strictre rules on the Yang files and was failing the tests.

Further patches should add config service in netvirt to be a central point
handling all the config updates. SG is also adding a config value that should
be included.

Change-Id: I44b3a442e8050d8f1ef1c5cd9db5c32af2d5ce19
Signed-off-by: Sam Hague <shague@redhat.com>
21 files changed:
openstack/net-virt-it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/it/NetvirtIT.java
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/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-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/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/ClassifierProvider.java

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 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..f27e742e46d531b70055e3cf78bd4875399fbf00 100644 (file)
@@ -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 be01ac5a0cb6668a369d0890575fac2e958ef27a..11130380335189db1a7c3d06852cf7c7cfc14fa0 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;
@@ -383,7 +382,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)
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 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 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);
 }