BUG9094 Bind to last SF interface if origin node 82/62782/2
authorJaime Caamaño Ruiz <jaime.caamano.ruiz@ericsson.com>
Fri, 1 Sep 2017 15:11:48 +0000 (17:11 +0200)
committerSam Hague <shague@redhat.com>
Thu, 7 Sep 2017 18:34:02 +0000 (18:34 +0000)
If the last SF is in one of the possible origin nodes for the
classified traffic, bind the classifier on it's port. This is to be
to handle the possible scenario where origin, last SF and destination
of traffic are on the same node. On this scenario, SFC on last hop will
not de-encapsulate the traffic, instead it will be handed off to the
dispatcher table for the egress classifier function to handle it. To be
able to do this, it needs to be bound to the last SF port.

Change-Id: I97f60e8cc409ea42c830e408b4df91051b50689c
Signed-off-by: Jaime Caamaño Ruiz <jaime.caamano.ruiz@ericsson.com>
(cherry picked from commit 9509d783b6c9fe5a348e0f39e86b8ae72cc53c3f)

vpnservice/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/SfcProvider.java
vpnservice/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ConfigurationClassifierImpl.java

index 7a3d4a484aaff5717898b6c8c98e6cab5acaa2fe..e0dab41fa055320b653fee1c0c17b104295707cc 100644 (file)
@@ -59,31 +59,33 @@ public class SfcProvider {
         return rsp;
     }
 
-    // This is for Logical SFFs
     public Optional<String> getFirstHopSfInterfaceFromRsp(RenderedServicePath rsp) {
-        Optional<RenderedServicePathHop> firstHop = getRspFirstHop(rsp);
-        if (!firstHop.isPresent()) {
-            LOG.warn("getFirstHopSfInterfaceFromRsp RSP [{}] cant get first hop", rsp.getName().getValue());
-            return Optional.empty();
-        }
+        return getRspFirstHop(rsp).flatMap(this::getHopSfInterface);
+    }
+
+    public Optional<String> getLastHopSfInterfaceFromRsp(RenderedServicePath rsp) {
+        return getRspLastHop(rsp).flatMap(this::getHopSfInterface);
+    }
+
+    public Optional<String> getHopSfInterface(RenderedServicePathHop hop) {
+
+        LOG.trace("getHopSfInterface of hop {}", hop);
 
-        SfName sfName = firstHop.get().getServiceFunctionName();
+        SfName sfName = hop.getServiceFunctionName();
         if (sfName == null) {
-            LOG.warn("getFirstHopSfInterfaceFromRsp RSP [{}] first hop has no SF", rsp.getName().getValue());
+            LOG.warn("getHopSfInterface hop has no SF");
             return Optional.empty();
         }
 
         Optional<ServiceFunction> sf = getServiceFunction(sfName);
         if (!sf.isPresent()) {
-            LOG.warn("getFirstHopSfInterfaceFromRsp RSP [{}] SF [{}] does not exist", rsp.getName().getValue(),
-                    sfName.getValue());
+            LOG.warn("getHopSfInterface SF [{}] does not exist", sfName.getValue());
             return Optional.empty();
         }
 
         List<SfDataPlaneLocator> sfDplList = sf.get().getSfDataPlaneLocator();
         if (sfDplList == null || sfDplList.isEmpty()) {
-            LOG.warn("getFirstHopSfInterfaceFromRsp RSP [{}] SF [{}] has no SfDpl", rsp.getName().getValue(),
-                    sfName.getValue());
+            LOG.warn("getHopSfInterface SF [{}] has no SfDpl", sfName.getValue());
             return Optional.empty();
         }
 
@@ -117,4 +119,14 @@ public class SfcProvider {
 
         return Optional.ofNullable(hops.get(0));
     }
+
+    private Optional<RenderedServicePathHop> getRspLastHop(RenderedServicePath rsp) {
+        List<RenderedServicePathHop> hops = rsp.getRenderedServicePathHop();
+        if (hops == null || hops.isEmpty()) {
+            LOG.warn("getRspLastHop RSP [{}] has no hops list", rsp.getName().getValue());
+            return Optional.empty();
+        }
+
+        return Optional.ofNullable(hops.get(hops.size() - 1));
+    }
 }
index b45e87ff40346a19156ca2f3f0d64e7f587ef100..ca51d17fa4ce99a637883ec91dae802dd598f27b 100644 (file)
@@ -125,6 +125,18 @@ public class ConfigurationClassifierImpl implements ClassifierState {
             return Collections.emptySet();
         }
 
+        String lastHopInterface = sfcProvider.getLastHopSfInterfaceFromRsp(rsp).orElse(null);
+        if (lastHopInterface == null) {
+            LOG.error("RSP has no valid last hop interface");
+            return Collections.emptySet();
+        }
+
+        DpnIdType lastHopDpn = geniusProvider.getDpnIdFromInterfaceName(lastHopInterface).orElse(null);
+        if (lastHopDpn == null) {
+            LOG.error("RSP has no valid last hop DPN");
+            return Collections.emptySet();
+        }
+
         List<String> interfaces = new ArrayList<>();
         NeutronNetwork network = matches.getAugmentation(NeutronNetwork.class);
         if (network != null) {
@@ -180,6 +192,13 @@ public class ConfigurationClassifierImpl implements ClassifierState {
                         nsi));
             });
 
+            // To handle chain egress when origin, last SF and destination are on the same node,
+            // we need to bind to the SF interface so that SFC pipeline to classifier pipeline
+            // hand-off can happen through the dispatcher table
+            if (nodeDpn.equals(lastHopDpn)) {
+                entries.add(ClassifierEntry.buildIngressEntry(new InterfaceKey(lastHopInterface)));
+            }
+
             // Egress services must bind to egress ports. Since we dont know before-hand what
             // the egress ports will be, we will bind on all switch ports. If the packet
             // doesnt have NSH, it will be returned to the the egress dispatcher table.