Bug 4996 - Wrong flows when using SFC coexistence
authorSam Hague <shague@redhat.com>
Thu, 28 Jan 2016 21:51:51 +0000 (16:51 -0500)
committerSam Hague <shague@redhat.com>
Fri, 29 Jan 2016 14:45:05 +0000 (14:45 +0000)
Signed-off-by: Sam Hague <shague@redhat.com>
(cherry picked from commit f00b01e77a14b1ad53b6553296499c9d30365808)

Change-Id: I25fd28e89f78fb101c1e187d0ce06eba02567dfb
Signed-off-by: Sam Hague <shague@redhat.com>
15 files changed:
openstack/net-virt-sfc/impl/pom.xml
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/AbstractDataTreeListener.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/ISfcClassifierService.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/ISfcStandaloneClassifierService.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcAclListener.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/RspListener.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/SfcUtils.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/standalone/openflow13/services/SfcClassifierService.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/NetvirtSfcWorkaroundOF13Provider.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/FlowCache.java [new file with mode: 0644]
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/FlowNames.java [new file with mode: 0644]
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/NetvirtSfcUtils.java [moved from openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/SfcUtils.java with 95% similarity]
utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java

index 065ba94aa9d0037854d85745e0368f3d43b8a3d2..718375495fc4e06a92bbb2858aac6bb7c47aa72b 100644 (file)
@@ -150,7 +150,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <Embed-Dependency>utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
             <Embed-Transitive>true</Embed-Transitive>
             <Export-Package>
-              org.opendaylight.ovsdb.openstack.netvirt.sfc
+              org.opendaylight.ovsdb.openstack.netvirt.sfc,
+              org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services
             </Export-Package>
           </instructions>
         </configuration>
index 87a9db615cdd7ffb3e9cd672e73ed574ce7f414d..f5b6f2c4ce184b3e923b09fff52fe24efe495abe 100644 (file)
@@ -37,11 +37,13 @@ public abstract class AbstractDataTreeListener<T extends DataObject> implements
     public void onDataTreeChanged(Collection<DataTreeModification<T>> changes) {
         Preconditions.checkNotNull(changes, "Changes may not be null!");
 
-        LOG.info("Received Data Tree Changed ...", changes);
+        LOG.info("onDataTreeChanged: Received Data Tree Changed ...", changes);
         for (DataTreeModification<T> change : changes) {
             final InstanceIdentifier<T> key = change.getRootPath().getRootIdentifier();
             final DataObjectModification<T> mod = change.getRootNode();
-            LOG.info("Received Data Tree Changed Update of Type={} for Key={}", mod.getModificationType(), key);
+            LOG.info("onDataTreeChanged: Received Data Tree Changed Update of Type={} for Key={}",
+                    mod.getModificationType(), key);
+            LOG.info("onDataTreeChanged: mod: {}", mod);
             switch (mod.getModificationType()) {
                 case DELETE:
                     remove(key, mod.getDataBefore());
index 008339eda43e0822c9b72ad87ec6c68ab592b9d5..ce92080d6a29d847b1177df861c0b94737e93e03 100644 (file)
@@ -9,12 +9,13 @@
 package org.opendaylight.ovsdb.openstack.netvirt.sfc;
 
 import java.net.InetAddress;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 
 public interface ISfcClassifierService {
-    void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
-                                  NshUtils nshHeader, long vxGpeOfPort, boolean write);
+    void programIngressClassifier(long dataPathId, String ruleName, Matches matches, long nsp, short nsi,
+                                  NshUtils nshHeader, long vxGpeOfPort, String rspName, boolean write);
 
     void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write);
 
@@ -22,10 +23,10 @@ public interface ISfcClassifierService {
                                   int tunnelOfPort, int tunnelId, short gotoTableId, boolean write);
 
     void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
-                                 long sfOfPort, int tunnelId, boolean write);
+                                 long sfOfPort, int tunnelId, String rspName, boolean write);
 
     void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
-                                       long sfOfPort, int tunnelId, boolean write);
+                                       long sfOfPort, int tunnelId, String rspName, boolean write);
 
     void program_sfEgress(long dataPathId, int dstPort, boolean write);
 
@@ -33,5 +34,7 @@ public interface ISfcClassifierService {
                            String ipAddress, String sfDplName, boolean write);
 
     void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
-                               String ipAddress, boolean write);
+                               String ipAddress, String rspName, boolean write);
+
+    void clearFlows(DataBroker dataBroker, String rspName);
 }
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/ISfcStandaloneClassifierService.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/ISfcStandaloneClassifierService.java
new file mode 100644 (file)
index 0000000..ef21df7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2015 Red Hat, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.sfc;
+
+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;
+
+public interface ISfcStandaloneClassifierService {
+    void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
+                                  NshUtils nshHeader, long vxGpeOfPort, boolean write);
+
+    void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write);
+
+    void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                  int tunnelOfPort, int tunnelId, short gotoTableId, boolean write);
+
+    void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                 long sfOfPort, int tunnelId, boolean write);
+
+    void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+                                       long sfOfPort, int tunnelId, boolean write);
+
+    void program_sfEgress(long dataPathId, int dstPort, boolean write);
+
+    void program_sfIngress(long dataPathId, int dstPort, long sfOfPort,
+                           String ipAddress, String sfDplName, boolean write);
+
+    void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
+                               String ipAddress, boolean write);
+}
index 74776698cb219d469a354acd76910172fd8556a4..7d6169754e6205b9bd741c949ba46b7a65e41e9b 100644 (file)
@@ -46,7 +46,7 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener<Acl> {
             LOG.info("Registering Data Change Listener for NetvirtSfc AccessList configuration.");
             listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
         } catch (final Exception e) {
-            LOG.warn("Netvirt AccesList DataChange listener registration fail!");
+            LOG.warn("Netvirt AccessList DataChange listener registration fail!");
             throw new IllegalStateException("NetvirtSfcAccessListListener startup fail! System needs restart.", e);
         }
     }
index f238f42d3c550e3bf81cf3857a2dd0b32f32fb20..0fff3d3c01583c21171a146cab8c4b50db2093b1 100644 (file)
@@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory;
  */
 public class RspListener extends AbstractDataTreeListener<RenderedServicePath> {
     private static final Logger LOG = LoggerFactory.getLogger(RspListener.class);
+    private ListenerRegistration<RspListener> listenerRegistration;
 
     public RspListener(final INetvirtSfcOF13Provider provider, final DataBroker db) {
         super(provider, RenderedServicePath.class);
@@ -37,13 +38,13 @@ public class RspListener extends AbstractDataTreeListener<RenderedServicePath> {
 
     private void registrationListener(final DataBroker db) {
         final DataTreeIdentifier<RenderedServicePath> treeId =
-                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, getRspIid());
+                new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, getRspIid());
         try {
             LOG.info("Registering Data Change Listener for NetvirtSfc RenderedServicePath configuration.");
-            ListenerRegistration<RspListener> listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
+            listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
         } catch (final Exception e) {
             LOG.warn("Netvirt RenderedServicePath DataChange listener registration failed!");
-            throw new IllegalStateException("NetvirtSfcAccessListListener startup failed! System needs restart.", e);
+            throw new IllegalStateException("RspListener startup failed! System needs restart.", e);
         }
     }
 
index ccd8832cf385f26eeb717599e8cfeda9bcdf9324..04b9578dcf1f97c77aeb8b3b32827fec328044e7 100644 (file)
@@ -12,13 +12,16 @@ import java.util.List;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.sfc.provider.api.SfcProviderAclAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
 import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI;
 import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePaths;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathKey;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctions;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionKey;
@@ -113,14 +116,18 @@ public class SfcUtils {
                         List<Ace> aces = accessListEntries.getAce();
                         for (Ace ace : aces) {
                             RedirectToSfc sfcRedirect = ace.getActions().getAugmentation(RedirectToSfc.class);
-                            if ((sfcRedirect != null && sfcRedirect.getRspName().equals(name)) ||
-                                    (sfcRedirect != null && sfcRedirect.getSfcName().equals(name)) ||
-                                    (sfcRedirect != null && sfcRedirect.getSfpName().equals(name))) {
+                            if ((sfcRedirect != null) &&
+                                    (sfcRedirect.getRspName().equals(name) ||
+                                    (sfcRedirect.getSfcName().equals(name)) ||
+                                    (sfcRedirect.getSfpName().equals(name)))) {
                                 aceFound = ace;
                                 break;
                             }
                         }
                     }
+                    if (aceFound != null) {
+                        break;
+                    }
                 }
             }
         }
@@ -189,4 +196,24 @@ public class SfcUtils {
 
         return (Ip)serviceFunctionForwarder.getSffDataPlaneLocator().get(0).getDataPlaneLocator().getLocatorType();
     }
+
+    public RenderedServicePathHop getFirstHop(RenderedServicePath rsp) {
+        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+        if (pathHopList.isEmpty()) {
+            LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
+            return null;
+        }
+
+        return pathHopList.get(0);
+    }
+
+    public RenderedServicePathHop getLastHop(RenderedServicePath rsp) {
+        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+        if (pathHopList.isEmpty()) {
+            LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
+            return null;
+        }
+
+        return pathHopList.get(pathHopList.size()-1);
+    }
 }
index 92ffcbd5141ef66c86dcd9204fd285dcc816451c..933638cede4e03ec5572484ad03a29157acec88d 100644 (file)
@@ -12,6 +12,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcStandaloneClassifierService;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
@@ -20,7 +21,8 @@ import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface, ISfcClassifierService {
+public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface,
+        ISfcStandaloneClassifierService {
     private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
 
     public SfcClassifierService(Service service) {
@@ -76,6 +78,5 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
 
     @Override
     public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr, String ipAddress, boolean write) {
-
     }
 }
index e8123401617153c3267734006555387bcc058048..f8bae2d45ef718e6cd60423e075feb259661cc52 100644 (file)
@@ -60,6 +60,7 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
     private static final short SFC_TABLE = 150;
     private MdsalUtils mdsalUtils;
     private SfcUtils sfcUtils;
+    private DataBroker dataBroker;
     private static final String VXGPE = "vxgpe";
     public static final String TUNNEL_ENDPOINT_KEY = "local_ip";
 
@@ -68,6 +69,7 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
         Preconditions.checkNotNull(mdsalUtils, "Input mdsalUtils cannot be NULL!");
         Preconditions.checkNotNull(sfcUtils, "Input sfcUtils cannot be NULL!");
 
+        this.dataBroker = dataBroker;
         this.mdsalUtils = mdsalUtils;
         this.sfcUtils = sfcUtils;
     }
@@ -116,6 +118,17 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
 
     }
 
+    @Override
+    public void removeRsp(RenderedServicePath change) {
+        LOG.info("removeRsp not implemented yet");
+        sfcClassifierService.clearFlows(dataBroker, change.getName().getValue());
+    }
+
+    @Override
+    public void updateRsp(RenderedServicePath change) {
+        LOG.info("updateRsp not implemented yet");
+    }
+
     private void processAclEntry(Ace entry) {
         Matches matches = entry.getMatches();
         Preconditions.checkNotNull(matches, "ACL Entry cannot be null!");
@@ -171,26 +184,28 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
         for (RenderedServicePathHop hop : pathHopList) {
             for (Node bridgeNode : bridgeNodes) {
                 // ignore bridges other than br-int
+                // TODO: Get bridge name from DPL, rework this loop to use DPL list
                 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(bridgeNode, "br-int");
                 if (ovsdbBridgeAugmentation == null) {
                     continue;
                 }
+                // TODO: Get port name from the DPL
                 long vxGpeOfPort = getOFPort(bridgeNode, VXGPE);
                 if (vxGpeOfPort == 0L) {
-                    LOG.warn("programAclEntry: Could not identify gpe vtep {} -> OF ({}) on {}",
+                    LOG.warn("handleRenderedServicePath: Could not identify gpe vtep {} -> OF ({}) on {}",
                             VXGPE, vxGpeOfPort, bridgeNode);
                     continue;
                 }
                 long dataPathId = southbound.getDataPathId(bridgeNode);
                 if (dataPathId == 0L) {
-                    LOG.warn("programAclEntry: Could not identify datapathId on {}", bridgeNode);
+                    LOG.warn("handleRenderedServicePath: Could not identify datapathId on {}", bridgeNode);
                     continue;
                 }
 
                 ServiceFunction serviceFunction =
                         SfcProviderServiceFunctionAPI.readServiceFunction(firstHop.getServiceFunctionName());
                 if (serviceFunction == null) {
-                    LOG.warn("programAclEntry: Could not identify ServiceFunction {} on {}",
+                    LOG.warn("handleRenderedServicePath: Could not identify ServiceFunction {} on {}",
                             firstHop.getServiceFunctionName().getValue(), bridgeNode);
                     continue;
                 }
@@ -198,12 +213,12 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
                         SfcProviderServiceForwarderAPI
                                 .readServiceFunctionForwarder(hop.getServiceFunctionForwarder());
                 if (serviceFunctionForwarder == null) {
-                    LOG.warn("programAclEntry: Could not identify ServiceFunctionForwarder {} on {}",
+                    LOG.warn("handleRenderedServicePath: Could not identify ServiceFunctionForwarder {} on {}",
                             firstHop.getServiceFunctionName().getValue(), bridgeNode);
                     continue;
                 }
 
-                handleSf(bridgeNode, serviceFunction);
+                handleSf(bridgeNode, serviceFunction, rsp);
                 handleSff(bridgeNode, serviceFunctionForwarder, serviceFunction, hop, firstHop, lastHop,
                         entry.getRuleName(), matches, vxGpeOfPort, rsp);
                 if (firstHop == lastHop) {
@@ -243,7 +258,8 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
                 nshHeader.setNshTunUdpPort(ip.getPort());
             }
             sfcClassifierService.programIngressClassifier(dataPathId, ruleName, matches,
-                    nshHeader, vxGpeOfPort, true);
+                    rsp.getPathId(), rsp.getStartingIndex(),
+                    nshHeader, vxGpeOfPort, rsp.getName().getValue(), true);
         } else if (hop == lastHop) {
             LOG.info("handleSff: last hop processing {} - {}",
                     bridgeNode.getNodeId().getValue(), serviceFunctionForwarder.getName().getValue());
@@ -252,10 +268,10 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
             long sfOfPort = getSfPort(bridgeNode, sfDplName);
             // TODO: Coexistence: SFC flows should take this using new egressTable REST
             sfcClassifierService.programEgressClassifier(dataPathId, vxGpeOfPort, rsp.getPathId(),
-                    lastServiceindex, sfOfPort, 0, true);
+                    lastServiceindex, sfOfPort, 0, rsp.getName().getValue(), true);
             // TODO: Coexistence: This flow should like like one above, change port, add reg0=1, resubmit
             sfcClassifierService.programEgressClassifierBypass(dataPathId, vxGpeOfPort, rsp.getPathId(),
-                    lastServiceindex, sfOfPort, 0, true);
+                    lastServiceindex, sfOfPort, 0, rsp.getName().getValue(), true);
         } else {
             // add typical sff flows
         }
@@ -264,7 +280,7 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
         //sfcClassifierService.programSfcTable(dataPathId, vxGpeOfPort, SFC_TABLE, true);
     }
 
-    void handleSf(Node bridgeNode, ServiceFunction serviceFunction) {
+    void handleSf(Node bridgeNode, ServiceFunction serviceFunction, RenderedServicePath rsp) {
         if (isSfOnBridge(bridgeNode, serviceFunction)) {
             LOG.info("handleSf: sf and bridge are on the same node: {} - {}, adding workaround and arp",
                     bridgeNode.getNodeId().getValue(), serviceFunction.getName().getValue());
@@ -283,7 +299,8 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
             // TODO: Coexistence: SFC flows should take this using new sf dpl augmentation
             //sfcClassifierService.program_sfEgress(dataPathId, sfIpPort, true);
             //sfcClassifierService.program_sfIngress(dataPathId, sfIpPort, sfOfPort, sfIpAddr, sfDplName, true);
-            sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpAddr, true);
+            sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpAddr,
+                    rsp.getName().getValue(), true);
         } else {
             LOG.info("handleSf: sf and bridge are not on the same node: {} - {}, do nothing",
                     bridgeNode.getNodeId().getValue(), serviceFunction.getName().getValue());
@@ -333,6 +350,7 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
         String rspName = rsp.getName().getValue();
         String rspNameSuffix = "_rsp";
         String sfcName = rspName.substring(0, rspName.length() - rspNameSuffix.length());
+        LOG.info("getAceFromRenderedServicePath: rsp: {}, sfcName: {}", rsp, sfcName);
         ace = sfcUtils.getAce(sfcName);
 
         return ace;
@@ -456,16 +474,6 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
         return mac;
     }
 
-    @Override
-    public void removeRsp(RenderedServicePath change) {
-        LOG.info("removeRsp not implemented yet");
-    }
-
-    @Override
-    public void updateRsp(RenderedServicePath change) {
-        LOG.info("updateRsp not implemented yet");
-    }
-
     @Override
     public void setDependencies(ServiceReference serviceReference) {
         nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/FlowCache.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/FlowCache.java
new file mode 100644 (file)
index 0000000..e569eb1
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2015 Red Hat, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
+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.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowCache {
+    private static final Logger LOG = LoggerFactory.getLogger(FlowCache.class);
+    private Map<String, Map<Integer, InstanceIdentifier<Flow>>> flowCache = new HashMap<>();
+
+    public void addFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, int flowId) {
+        Map<Integer, InstanceIdentifier<Flow>> flowMap = flowCache.get(rspName);
+        if (flowMap == null) {
+            LOG.info("addFlow: adding new flowMap for {}({})", rspName, flowId);
+            flowMap = new HashMap<>();
+        }
+        InstanceIdentifier<Flow> path = FlowUtils.createFlowPath(flowBuilder, nodeBuilder);
+        flowMap.put(flowId, path);
+        flowCache.put(rspName, flowMap);
+        LOG.info("addFlow: added {}({}) {} to cache size {} - {}", rspName, flowId, path,
+                flowCache.size(), flowCache);
+    }
+
+    public void removeFlow(String rspName, int flowId) {
+        Map<Integer, InstanceIdentifier<Flow>> flowMap = flowCache.get(rspName);
+        if (flowMap != null) {
+            flowMap.remove(flowId);
+            if (flowMap.isEmpty()) {
+                flowCache.remove(rspName);
+                LOG.info("removeFlow: removed flowMap {}({}) from cache size {} - {}", rspName, flowId,
+                        flowCache.size(), flowCache);
+            } else {
+                flowCache.put(rspName, flowMap);
+            }
+        }
+        LOG.info("removeFlow: removed {}({}) from cache size {} - {}", rspName, flowId, flowCache.size(), flowCache);
+    }
+
+    public Map<Integer, InstanceIdentifier<Flow>> getFlows(String rspName) {
+        return flowCache.get(rspName);
+    }
+}
diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/FlowNames.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/FlowNames.java
new file mode 100644 (file)
index 0000000..6f519af
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2015 Red Hat, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services;
+
+public class FlowNames {
+
+    public static String getSfcIngressClass(String ruleName, long nsp, short nsi) {
+        return "sfcIngressClass_" + nsp + "_" + nsi + "_" + ruleName;
+    }
+
+    public static String getSfcTable(long vxGpeOfPort) {
+        return "sfcTable_" + vxGpeOfPort;
+    }
+
+    public static String getSfcEgressClass1(long vxGpeOfPort) {
+        return "sfcEgressClass1_" + vxGpeOfPort;
+    }
+
+    public static String getSfcEgressClass(long vxGpeOfPort, long nsp, short nsi) {
+        return "sfcEgressClass_" + nsp + "_" + nsi + "_" + vxGpeOfPort;
+    }
+
+    public static String getSfcEgressClassBypass(long nsp, short nsi, long sfOfPort) {
+        return "sfcEgressClassBypass_" + nsp + "_" + nsi + "_"  + sfOfPort;
+    }
+
+    public static String getSfEgress(int dstPort) {
+        return "sfEgress_" + dstPort;
+    }
+
+    public static String getSfIngress(int dstPort, String ipAddress) {
+        return "sfIngress_" + dstPort + "_" + ipAddress;
+    }
+
+    public static String getArpResponder(String ipAddress) {
+        return "ArpResponder_" + ipAddress;
+    }
+}
index e96b9006bf2f4c6411ac33cc146ab915e9932780..c6442e6aecb12b3931d4136fe65b22e7a6624637 100644 (file)
@@ -9,9 +9,15 @@
 package org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services;
 
 import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
@@ -31,9 +37,8 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.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.FlowCookie;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
@@ -46,6 +51,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
@@ -55,6 +61,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
     private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
     private static final short UDP_SHORT = 17;
     static int cookieIndex = 0;
+    private FlowCache flowCache = new FlowCache();
 
     private enum FlowID {
         FLOW_INGRESSCLASS(1), FLOW_SFINGRESS(2), FLOW_SFEGRESS(3), FLOW_SFARP(4),
@@ -64,7 +71,6 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         FlowID(int value) {
             this.value = value;
         }
-
     }
 
     private BigInteger getCookie(FlowID flowID) {
@@ -108,12 +114,22 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         return flowBuilder;
     }
 
+    private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, FlowID flowID) {
+        flowCache.addFlow(flowBuilder, nodeBuilder, rspName, flowID.value);
+        writeFlow(flowBuilder, nodeBuilder);
+    }
+
+    private void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, FlowID flowID) {
+        flowCache.removeFlow(rspName, flowID.value);
+        removeFlow(flowBuilder, nodeBuilder);
+    }
+
     @Override
-    public void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
-                                         NshUtils nshHeader, long vxGpeOfPort, boolean write) {
+    public void programIngressClassifier(long dataPathId, String ruleName, Matches matches, long nsp, short nsi,
+                                         NshUtils nshHeader, long vxGpeOfPort, String rspName, boolean write) {
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
-        String flowName = "sfcIngressClass_" + ruleName;// + "_" + nshHeader.getNshNsp();
+        String flowName = FlowNames.getSfcIngressClass(ruleName, nsp, nsi);
         initFlowBuilder(flowBuilder, flowName, getTable(), FlowID.FLOW_INGRESSCLASS,
                 (short)nshHeader.getNshNsp(), nshHeader.getNshNsi());
 
@@ -151,9 +167,9 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
             InstructionsBuilder isb = new InstructionsBuilder();
             isb.setInstruction(instructions);
             flowBuilder.setInstructions(isb.build());
-            writeFlow(flowBuilder, nodeBuilder);
+            writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_INGRESSCLASS);
         } else {
-            removeFlow(flowBuilder, nodeBuilder);
+            removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_INGRESSCLASS);
         }
     }
 
@@ -161,7 +177,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
     public void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write) {
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
-        String flowName = "sfcTable_" + vxGpeOfPort;
+        String flowName = FlowNames.getSfcTable(vxGpeOfPort);
         initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER), FlowID.FLOW_SFCTABLE)
                 .setPriority(1000);
 
@@ -191,7 +207,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
                                          int tunnelOfPort, int tunnelId, short gotoTableId, boolean write) {
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
-        String flowName = "sfcEgressClass1_" + vxGpeOfPort;
+        String flowName = FlowNames.getSfcEgressClass1(vxGpeOfPort);
         initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER), FlowID.FLOW_EGRESSCLASSUNUSED,
                 (short)nsp, nsi);
 
@@ -220,10 +236,10 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
 
     @Override
     public void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
-                                        long sfOfPort, int tunnelId, boolean write) {
+                                        long sfOfPort, int tunnelId, String rspName, boolean write) {
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
-        String flowName = "sfcEgressClass_" + nsp + "_" + + nsi + "_"  + vxGpeOfPort;
+        String flowName = FlowNames.getSfcEgressClass(vxGpeOfPort, nsp, nsi);
         initFlowBuilder(flowBuilder, flowName, getTable(Service.SFC_CLASSIFIER), FlowID.FLOW_EGRESSCLASS,
                 (short)nsp, nsi);
 
@@ -268,18 +284,18 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
 
             isb.setInstruction(instructions);
             flowBuilder.setInstructions(isb.build());
-            writeFlow(flowBuilder, nodeBuilder);
+            writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASS);
         } else {
-            removeFlow(flowBuilder, nodeBuilder);
+            removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASS);
         }
     }
 
     @Override
     public void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
-                                              long sfOfPort, int tunnelId, boolean write) {
+                                              long sfOfPort, int tunnelId, String rspName, boolean write) {
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
-        String flowName = "sfcEgressClassBypass_" + nsp + "_" + + nsi + "_"  + sfOfPort;
+        String flowName = FlowNames.getSfcEgressClassBypass(nsp, nsi, sfOfPort);
         initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER),
                 FlowID.FLOW_EGRESSCLASSBYPASS, (short)nsp, nsi)
                 .setPriority(40000);
@@ -304,9 +320,9 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
 
             isb.setInstruction(instructions);
             flowBuilder.setInstructions(isb.build());
-            writeFlow(flowBuilder, nodeBuilder);
+            writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASSBYPASS);
         } else {
-            removeFlow(flowBuilder, nodeBuilder);
+            removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASSBYPASS);
         }
     }
 
@@ -315,7 +331,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
     public void program_sfEgress(long dataPathId, int dstPort, boolean write) {
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
-        String flowName = "sfEgress_" + dstPort;
+        String flowName = FlowNames.getSfEgress(dstPort);
         initFlowBuilder(flowBuilder, flowName, getTable(), FlowID.FLOW_SFEGRESS);
 
         MatchBuilder matchBuilder = new MatchBuilder();
@@ -348,7 +364,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
                                   String ipAddress, String sfDplName, boolean write) {
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
-        String flowName = "sfIngress_" + dstPort + "_" + ipAddress;
+        String flowName = FlowNames.getSfIngress(dstPort, ipAddress);
         initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable(), FlowID.FLOW_SFINGRESS);
 
         MatchBuilder matchBuilder = new MatchBuilder();
@@ -378,10 +394,10 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
 
     @Override
     public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
-                                      String ipAddress, boolean write) {
+                                      String ipAddress, String rspName, boolean write) {
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
         FlowBuilder flowBuilder = new FlowBuilder();
-        String flowName = "ArpResponder_" + ipAddress;
+        String flowName = FlowNames.getArpResponder(ipAddress);
         initFlowBuilder(flowBuilder, flowName, getTable(Service.ARP_RESPONDER), FlowID.FLOW_SFARP)
                 .setPriority(1024);
 
@@ -459,9 +475,9 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
 
             isb.setInstruction(instructions);
             flowBuilder.setInstructions(isb.build());
-            writeFlow(flowBuilder, nodeBuilder);
+            writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFARP);
         } else {
-            removeFlow(flowBuilder, nodeBuilder);
+            removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFARP);
         }
     }
 
@@ -516,4 +532,35 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         LOG.info("buildMatch: {}", matchBuilder.build());
         return matchBuilder;
     }
+
+    private static FlowID flowSet[] = {FlowID.FLOW_INGRESSCLASS, FlowID.FLOW_EGRESSCLASS,
+            FlowID.FLOW_EGRESSCLASSBYPASS, FlowID.FLOW_SFARP};
+
+    @Override
+    public void clearFlows(DataBroker dataBroker, String rspName) {
+        Map<Integer, InstanceIdentifier<Flow>> flowMap = flowCache.getFlows(rspName);
+        if (flowMap != null) {
+            for (FlowID flowID : flowSet) {
+                InstanceIdentifier<Flow> path = flowMap.get(flowID.value);
+                if (path != null) {
+                    flowCache.removeFlow(rspName, flowID.value);
+                    removeFlow(dataBroker, path);
+                }
+            }
+        }
+    }
+
+    private void removeFlow(DataBroker dataBroker, InstanceIdentifier<Flow> path) {
+        WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
+        modification.delete(LogicalDatastoreType.CONFIGURATION, path);
+
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
+        try {
+            commitFuture.get();  // TODO: Make it async (See bug 1362)
+            LOG.debug("Transaction success for deletion of Flow {}", path);
+        } catch (Exception e) {
+            LOG.error(e.getMessage(), e);
+            modification.cancel();
+        }
+    }
 }
index 7a215dc2c7e3383d34fb3254ea0282637a40dc5f..fb6001b6862959f15c29c258931bc70d52d73afa 100644 (file)
@@ -27,9 +27,11 @@ import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRunti
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.junit.Assert;
@@ -38,9 +40,13 @@ import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.MdsalHelper;
 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;
@@ -54,7 +60,8 @@ import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionForward
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionPathUtils;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionUtils;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcConfigUtils;
-import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.NetvirtSfcUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services.FlowNames;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
@@ -111,6 +118,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.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.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
@@ -137,9 +145,11 @@ import com.google.common.collect.Maps;
 @ExamReactorStrategy(PerClass.class)
 public class NetvirtSfcIT extends AbstractMdsalTestBase {
     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcIT.class);
+    private static final int MDSAL_TIMEOUT = 10000;
+    private static final int NO_MDSAL_TIMEOUT = 0;
     private static AclUtils aclUtils = new AclUtils();
     private static ClassifierUtils classifierUtils = new ClassifierUtils();
-    private static SfcUtils sfcUtils = new SfcUtils();
+    private static NetvirtSfcUtils netvirtSfcUtils = new NetvirtSfcUtils();
     private static ServiceFunctionUtils serviceFunctionUtils = new ServiceFunctionUtils();
     private static ServiceFunctionForwarderUtils serviceFunctionForwarderUtils = new ServiceFunctionForwarderUtils();
     private static ServiceFunctionChainUtils serviceFunctionChainUtils = new ServiceFunctionChainUtils();
@@ -149,6 +159,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     private static MdsalUtils mdsalUtils;
     private static AtomicBoolean setup = new AtomicBoolean(false);
     private static SouthboundUtils southboundUtils;
+    private static SfcUtils sfcUtils;
     private static String addressStr;
     private static String portStr;
     private static String connectionType;
@@ -177,9 +188,10 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     private static final String SF1DPLNAME = "sf1";
     private static final String SF2DPLNAME = "sf2";
     // Use 192.168.50.70 when running against vagrant vm for workaround testing
+    // Use 192.168.1.129 (or whatever address is dhcp'ed) for tacker-vm
     // "192.168.50.70"; "127.0.0.1"; "192.168.1.129";
-    private static final String SFF1IP = "192.168.1.129";
-    private static final String SFF2IP = "192.168.1.129";//"127.0.0.1";
+    private static final String SFF1IP = "192.168.50.70";
+    private static final String SFF2IP = "127.0.0.1";
     private static final String SFF1NAME = "sff1";
     private static final String SFF2NAME = "sff2";
     private static final String SFFDPL1NAME = "vxgpe";
@@ -190,8 +202,9 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     private static final String BRIDGE2NAME= "br-int";
     private static final String ACLNAME= "httpAcl";
     private static final String RULENAME= "httpRule";
-    private static final String SFCNAME = "sfc1";
+    private static final String SFCNAME = "SFC";
     private static final String SFCPATH = "SFC-Path";
+    private static final String RSPNAME = SFCPATH + "_rsp";
     private static final String SFCSF1NAME = "firewall-abstract";
     private static final SftType SFCSF1TYPE = new SftType("firewall");
     private static final int GPEUDPPORT = 6633;
@@ -242,8 +255,9 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
                                 .version(asInProject())
                                 .type("jar")),
                 configureConsole().startLocalConsole(),
+                //vmOption("-verbose:class"),
                 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
-                        keepRuntimeFolder()
+                keepRuntimeFolder()
         };
     }
 
@@ -331,12 +345,14 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         mdsalUtils = new MdsalUtils(dataBroker);
         assertNotNull("mdsalUtils should not be null", mdsalUtils);
         southboundUtils = new SouthboundUtils(mdsalUtils);
+        sfcUtils = new SfcUtils(mdsalUtils);
         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);
     }
 
@@ -439,7 +455,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     }
 
     private SfcBuilder netvirtSfcBuilder() {
-        return sfcUtils.sfcBuilder(new SfcBuilder(), "sfc");
+        return netvirtSfcUtils.sfcBuilder(new SfcBuilder(), "sfc");
     }
 
     @Test
@@ -629,14 +645,26 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
      * Test that the NetvirtSfc SfcClassifierService is added to the Netvirt pipeline.
      * @throws InterruptedException
      */
-    @Test
+    /*@Test
     public void testNetvirtSfcPipeline() throws InterruptedException {
-        String bridgeName = INTEGRATION_BRIDGE_NAME;
         ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
-        assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
+        InstanceIdentifier<Node> ovsdbIid = SouthboundUtils.createInstanceIdentifier(connectionInfo);
+        final NotifyingDataChangeListener ovsdbOperationalListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
+        ovsdbOperationalListener.registerDataChangeListener();
+
+        String bridgeName = INTEGRATION_BRIDGE_NAME;
+        InstanceIdentifier<Node> bridgeIid = SouthboundUtils.createInstanceIdentifier(connectionInfo, bridgeName);
+        final NotifyingDataChangeListener bridgeOperationalListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+        bridgeOperationalListener.registerDataChangeListener();
+        assertNotNull("connection failed", southboundUtils.addOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
+
+        ovsdbOperationalListener.waitForCreation(MDSAL_TIMEOUT);
         Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
         assertNotNull("node is not connected", ovsdbNode);
 
+        bridgeOperationalListener.waitForCreation(MDSAL_TIMEOUT);
         assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
                 + " is not connected", isControllerConnected(connectionInfo));
 
@@ -647,23 +675,40 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
         assertNotEquals("datapathId was not found", datapathId, 0);
 
-        String flowId = "DEFAULT_PIPELINE_FLOW_" + Service.SFC_CLASSIFIER.getTable();
+        String flowId = "DEFAULT_PIPELINE_FLOW_" + pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER);
         verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
 
-        readwait();
-
-        assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
-        Thread.sleep(1000);
-        assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
+        assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName, NO_MDSAL_TIMEOUT));
+        bridgeOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+        bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+        assertNull("Bridge should not be found", bridgeNode);
+        assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
+        ovsdbOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+        ovsdbNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
+        assertNull("Ovsdb node should not be found", ovsdbNode);
+    }*/
+
+    public class NotifyingDataChangeListener2 {
+        int something;
+
+        public NotifyingDataChangeListener2(int something) {
+            this.something = something;
+        }
     }
 
+    @Test
+    public void testClassNotFound() throws InterruptedException {
+        LOG.info("shague >>>>>");
+        final NotifyingDataChangeListener2 lis2 = new NotifyingDataChangeListener2(500);
+        LOG.info("shague 2 >>>>>");
+    }
     /**
      * 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
+    /*@Test
     public void testNetvirtSfcAll() throws InterruptedException {
         if (userSpaceEnabled.equals("yes")) {
             LOG.info("testNetvirtSfcAll: skipping test because userSpaceEnabled {}", userSpaceEnabled);
@@ -676,12 +721,24 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         short egressTable = pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER);
         testModelPut(sfcOfRendererConfigBuilder(sfcTableoffset, egressTable), SfcOfRendererConfig.class);
 
-        String bridgeName = INTEGRATION_BRIDGE_NAME;
         ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
-        assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
+        InstanceIdentifier<Node> ovsdbIid = SouthboundUtils.createInstanceIdentifier(connectionInfo);
+        final NotifyingDataChangeListener ovsdbOperationalListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
+        ovsdbOperationalListener.registerDataChangeListener();
+
+        String bridgeName = INTEGRATION_BRIDGE_NAME;
+        InstanceIdentifier<Node> bridgeIid = SouthboundUtils.createInstanceIdentifier(connectionInfo, bridgeName);
+        final NotifyingDataChangeListener bridgeOperationalListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+        bridgeOperationalListener.registerDataChangeListener();
+        assertNotNull("connection failed", southboundUtils.addOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
+
+        ovsdbOperationalListener.waitForCreation(MDSAL_TIMEOUT);
         Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
         assertNotNull("node is not connected", ovsdbNode);
 
+        bridgeOperationalListener.waitForCreation(MDSAL_TIMEOUT);
         assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
                 + " is not connected", isControllerConnected(connectionInfo));
 
@@ -704,20 +761,17 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         externalIds.clear();
         externalIds.put("attached-mac", "f6:00:00:0c:00:02");
         southboundUtils.addTerminationPoint(bridgeNode, "vm2", "internal");
-        // SFC will add the SFF dpl port when creating the RSP
-        /*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);*/
+
+        InstanceIdentifier<TerminationPoint> tpIid =
+                southboundUtils.createTerminationPointInstanceIdentifier(bridgeNode, SFFDPL1NAME);
+        final NotifyingDataChangeListener portOperationalListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, tpIid);
+        portOperationalListener.registerDataChangeListener();
+
+        InstanceIdentifier<RenderedServicePath> rspIid = sfcUtils.getRspId(RSPNAME);
+        final NotifyingDataChangeListener rspOperationalListener =
+                new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, rspIid);
+        rspOperationalListener.registerDataChangeListener();
 
         testModelPut(serviceFunctionsBuilder(), ServiceFunctions.class);
         testModelPut(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class);
@@ -727,51 +781,47 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         testModelPut(accessListsBuilder(), AccessLists.class);
         testModelPut(classifiersBuilder(), Classifiers.class);
 
-        long vxGpeOfPort = getOFPort(bridgeNode, "vxgpe");
+        portOperationalListener.waitForCreation(MDSAL_TIMEOUT);
+        long vxGpeOfPort = southbound.getOFPort(bridgeNode, SFFDPL1NAME);
         assertNotEquals("vxGpePort was not found", 0, vxGpeOfPort);
 
-        readwait();
+        rspOperationalListener.waitForCreation(MDSAL_TIMEOUT);
+        RenderedServicePath rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, rspIid);
+        assertNotNull("RSP was not found", rsp);
 
-        flowId = "sfcIngressClass_" + "httpRule";
+        flowId = FlowNames.getSfcIngressClass(RULENAME, rsp.getPathId(), rsp.getStartingIndex());
         verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
-        // SFC is adding these flows now
-        //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;
+        flowId = FlowNames.getArpResponder(SF1IP);
         verifyFlow(datapathId, flowId, Service.ARP_RESPONDER);
-
-        readwait();
-
-        assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
-        Thread.sleep(1000);
-        assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
-    }
-
-    // Not used yet
-    private void getSffDplPort(String rspName) {
-        long ofPort = 0;
+        RenderedServicePathHop lastHop = sfcUtils.getLastHop(rsp);
+        short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
+        flowId = FlowNames.getSfcEgressClass(vxGpeOfPort, rsp.getPathId(), lastServiceindex);
+        verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
+        flowId = FlowNames.getSfcEgressClassBypass(rsp.getPathId(), lastServiceindex, 1);
+        verifyFlow(datapathId, flowId, Service.CLASSIFIER);
+
+        deleteRsp(RSPNAME);
+        rspOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+        rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, rspIid);
+        assertNull("RSP should not be found", rsp);
+
+        assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName, NO_MDSAL_TIMEOUT));
+        bridgeOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+        bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+        assertNull("Bridge should not be found", bridgeNode);
+        assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
+        ovsdbOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+        ovsdbNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
+        assertNull("Ovsdb node should not be found", ovsdbNode);
+    }*/
+
+    private void deleteRsp(String rspName) {
         RenderedServicePathKey renderedServicePathKey =
                 new RenderedServicePathKey(RspName.getDefaultInstance(rspName));
         InstanceIdentifier<RenderedServicePath> path =
                 InstanceIdentifier.create(RenderedServicePaths.class)
                         .child(RenderedServicePath.class, renderedServicePathKey);
-        RenderedServicePath rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
-        if (rsp == null) {
-            LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
-            return;
-        }
-        List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
-        if (pathHopList.isEmpty()) {
-            LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
-            return;
-        }
-
-        for (RenderedServicePathHop hop : pathHopList) {
-        }
+        mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, path);
     }
 
     /**
@@ -783,7 +833,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     @Test
     public void testStandalone() throws InterruptedException {
         String bridgeName = "sw1";
-        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);
@@ -936,32 +986,82 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         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);
+    /*private static class NotifyingDataChangeListener2 implements DataChangeListener {
+        @Override
+        public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent) {
+
+        }
+    }*/
+
+    /*public class NotifyingDataChangeListener implements DataChangeListener {
+        private final LogicalDatastoreType type;
+        private final Set<InstanceIdentifier<?>> createdIids = new HashSet<>();
+        private final Set<InstanceIdentifier<?>> removedIids = new HashSet<>();
+        private final Set<InstanceIdentifier<?>> updatedIids = new HashSet<>();
+        private final InstanceIdentifier<?> iid;
+        private final int RETRY_WAIT = 100;
+
+        private NotifyingDataChangeListener(LogicalDatastoreType type, InstanceIdentifier<?> iid) {
+            this.type = type;
+            this.iid = iid;
+        }
+
+        @Override
+        public void onDataChanged(
+                AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent) {
+            LOG.info("{} DataChanged: created {}", type, asyncDataChangeEvent.getCreatedData().keySet());
+            LOG.info("{} DataChanged: removed {}", type, asyncDataChangeEvent.getRemovedPaths());
+            LOG.info("{} DataChanged: updated {}", type, asyncDataChangeEvent.getUpdatedData().keySet());
+            createdIids.addAll(asyncDataChangeEvent.getCreatedData().keySet());
+            removedIids.addAll(asyncDataChangeEvent.getRemovedPaths());
+            updatedIids.addAll(asyncDataChangeEvent.getUpdatedData().keySet());
+            synchronized(this) {
+                notifyAll();
+            }
+        }
+
+        public boolean isCreated(InstanceIdentifier<?> iid) {
+            return createdIids.remove(iid);
         }
-        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;
-                    }
+
+        public boolean isRemoved(InstanceIdentifier<?> iid) {
+            return removedIids.remove(iid);
+        }
+
+        public boolean isUpdated(InstanceIdentifier<?> iid) {
+            return updatedIids.remove(iid);
+        }
+
+        public void clear() {
+            createdIids.clear();
+            removedIids.clear();
+            updatedIids.clear();
+        }
+
+        public void registerDataChangeListener() {
+            dataBroker.registerDataChangeListener(type, iid, this, AsyncDataBroker.DataChangeScope.SUBTREE);
+        }
+
+        public void waitForCreation(long timeout) throws InterruptedException {
+            synchronized (this) {
+                long _start = System.currentTimeMillis();
+                LOG.info("Waiting for {} DataChanged creation on {}", type, iid);
+                while (!isCreated(iid) && (System.currentTimeMillis() - _start) < timeout) {
+                    wait(RETRY_WAIT);
                 }
-                try {
-                    Thread.sleep(500);
-                } catch (InterruptedException e) {
-                    LOG.error("Interrupted while waiting for ofPort {}", portName, e);
+                LOG.info("Woke up, waited {}ms for creation of {}", (System.currentTimeMillis() - _start), iid);
+            }
+        }
+
+        public void waitForDeletion(long timeout) throws InterruptedException {
+            synchronized (this) {
+                long _start = System.currentTimeMillis();
+                LOG.info("Waiting for {} DataChanged deletion on {}", type, iid);
+                while (!isRemoved(iid) && (System.currentTimeMillis() - _start) < timeout) {
+                    wait(RETRY_WAIT);
                 }
+                LOG.info("Woke up, waited {}ms for deletion of {}", (System.currentTimeMillis() - _start), iid);
             }
         }
-        return ofPort;
-    }
+    }*/
 }
similarity index 95%
rename from openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/SfcUtils.java
rename to openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/NetvirtSfcUtils.java
index 5b24ef437a6e73ed5bf2c4ae513e688d99fefba0..03595e13b86ab04fd9cae1731b1870d02dad9bac 100644 (file)
@@ -10,7 +10,7 @@ package org.opendaylight.ovsdb.openstack.netvirt.sfc.utils;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.SfcBuilder;
 
-public class SfcUtils {
+public class NetvirtSfcUtils {
     public SfcBuilder sfcBuilder(SfcBuilder sfcBuilder, String sfcName) {
         return sfcBuilder.setName(sfcName);
     }
index 1933f236af56cb3e8f1e8980f700af31fd45818e..332c273a4b9b4ff58b34ff65cb3523821191140f 100644 (file)
@@ -119,6 +119,10 @@ public class SouthboundUtils {
         return SouthboundMapper.createInstanceIdentifier(createManagedNodeId(key, bridgeName));
     }
 
+    public static InstanceIdentifier<Node> createInstanceIdentifier(ConnectionInfo key, String bridgeName) {
+        return createInstanceIdentifier(key, new OvsdbBridgeName(bridgeName));
+    }
+
     public InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(Node node, String portName){
 
         InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
@@ -176,13 +180,20 @@ public class SouthboundUtils {
     }
 
     public boolean addOvsdbNode(final ConnectionInfo connectionInfo) {
+        return addOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
+    }
+
+    public boolean addOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
         boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION,
                 createInstanceIdentifier(connectionInfo),
                 createNode(connectionInfo));
-        try {
-            Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-        } catch (InterruptedException e) {
-            LOG.warn("Interrupted while waiting after adding OVSDB node {}", connectionInfoToString(connectionInfo), e);
+        if (timeout != 0) {
+            try {
+                Thread.sleep(timeout);
+            } catch (InterruptedException e) {
+                LOG.warn("Interrupted while waiting after adding OVSDB node {}",
+                        connectionInfoToString(connectionInfo), e);
+            }
         }
         return result;
     }
@@ -193,26 +204,40 @@ public class SouthboundUtils {
     }
 
     public boolean deleteOvsdbNode(final ConnectionInfo connectionInfo) {
+        return deleteOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
+    }
+
+    public boolean deleteOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
         boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
                 createInstanceIdentifier(connectionInfo));
-        try {
-            Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-        } catch (InterruptedException e) {
-            LOG.warn("Interrupted while waiting after deleting OVSDB node {}", connectionInfoToString(connectionInfo),
-                    e);
+        if (timeout != 0) {
+            try {
+                Thread.sleep(timeout);
+            } catch (InterruptedException e) {
+                LOG.warn("Interrupted while waiting after deleting OVSDB node {}",
+                        connectionInfoToString(connectionInfo), e);
+            }
         }
         return result;
     }
 
     public Node connectOvsdbNode(final ConnectionInfo connectionInfo) {
-        addOvsdbNode(connectionInfo);
+        return connectOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
+    }
+
+    public Node connectOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
+        addOvsdbNode(connectionInfo, timeout);
         Node node = getOvsdbNode(connectionInfo);
         LOG.info("Connected to {}", connectionInfoToString(connectionInfo));
         return node;
     }
 
     public boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo) {
-        deleteOvsdbNode(connectionInfo);
+        return disconnectOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
+    }
+
+    public boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
+        deleteOvsdbNode(connectionInfo, timeout);
         LOG.info("Disconnected from {}", connectionInfoToString(connectionInfo));
         return true;
     }
@@ -272,13 +297,18 @@ public class SouthboundUtils {
     }
 
     public boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName) {
+        return deleteBridge(connectionInfo, bridgeName, OVSDB_UPDATE_TIMEOUT);
+    }
 
+    public boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName, long timeout) {
         boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
                 createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName)));
-        try {
-            Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-        } catch (InterruptedException e) {
-            LOG.warn("Interrupted while waiting after deleting bridge {}", bridgeName, e);
+        if (timeout != 0) {
+            try {
+                Thread.sleep(timeout);
+            } catch (InterruptedException e) {
+                LOG.warn("Interrupted while waiting after deleting bridge {}", bridgeName, e);
+            }
         }
         return result;
     }
@@ -291,6 +321,18 @@ public class SouthboundUtils {
         return protocolList;
     }
 
+    public boolean addBridge(final ConnectionInfo connectionInfo, InstanceIdentifier<Node> bridgeIid,
+                             final String bridgeName, NodeId bridgeNodeId, final boolean setProtocolEntries,
+                             final Class<? extends OvsdbFailModeBase> failMode, final boolean setManagedBy,
+                             final Class<? extends DatapathTypeBase> dpType,
+                             final List<BridgeExternalIds> externalIds,
+                             final List<ControllerEntry> controllerEntries,
+                             final List<BridgeOtherConfigs> otherConfigs,
+                             final String dpid) throws InterruptedException {
+        return addBridge(connectionInfo, bridgeIid, bridgeName, bridgeNodeId, setProtocolEntries, failMode,
+                setManagedBy, dpType, externalIds, controllerEntries, otherConfigs, dpid);
+    }
+
     /*
      * base method for adding test bridges.  Other helper methods used to create bridges should utilize this method.
      *
@@ -314,7 +356,7 @@ public class SouthboundUtils {
                              final List<BridgeExternalIds> externalIds,
                              final List<ControllerEntry> controllerEntries,
                              final List<BridgeOtherConfigs> otherConfigs,
-                             final String dpid) throws InterruptedException {
+                             final String dpid, long timeout) throws InterruptedException {
 
         NodeBuilder bridgeNodeBuilder = new NodeBuilder();
         if (bridgeIid == null) {
@@ -356,7 +398,9 @@ public class SouthboundUtils {
                 ovsdbBridgeAugmentationBuilder.toString());
         boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
                 bridgeIid, bridgeNodeBuilder.build());
-        Thread.sleep(OVSDB_UPDATE_TIMEOUT);
+        if (timeout != 0) {
+            Thread.sleep(OVSDB_UPDATE_TIMEOUT);
+        }
         return result;
     }