Add egress split horizon drop flows for external interfaces 94/47794/9
authorAlon Kochba <alonko@hpe.com>
Tue, 1 Nov 2016 11:36:07 +0000 (13:36 +0200)
committerAlon Kochba <alonko@hpe.com>
Thu, 3 Nov 2016 10:29:49 +0000 (12:29 +0200)
Add drop flows to egress dispatcher to drop packets originating from
an external interface, marked by SH metadata bit, if the packet is
being sent to an external interface.

Change-Id: I028bd5a795b35613bb27b61577a5056e9a109188
Signed-off-by: Alon Kochba <alonko@hpe.com>
interfacemanager/interfacemanager-impl/src/main/java/org/opendaylight/genius/interfacemanager/servicebindings/flowbased/config/helpers/FlowBasedEgressServicesConfigBindHelper.java
interfacemanager/interfacemanager-impl/src/main/java/org/opendaylight/genius/interfacemanager/servicebindings/flowbased/config/helpers/FlowBasedEgressServicesConfigUnbindHelper.java
interfacemanager/interfacemanager-impl/src/main/java/org/opendaylight/genius/interfacemanager/servicebindings/flowbased/state/helpers/FlowBasedEgressServicesStateBindHelper.java
interfacemanager/interfacemanager-impl/src/main/java/org/opendaylight/genius/interfacemanager/servicebindings/flowbased/state/helpers/FlowBasedEgressServicesStateUnbindHelper.java
interfacemanager/interfacemanager-impl/src/main/java/org/opendaylight/genius/interfacemanager/servicebindings/flowbased/utilities/FlowBasedServicesUtils.java
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/genius/mdsalutil/MetaDataUtil.java

index b1fe285c94a2a3371d7d3b0161f36fb669ddc1fe..90f0c6aac243c75b618fec6558d49a0cb0a20d41 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
@@ -105,12 +106,13 @@ public class FlowBasedEgressServicesConfigBindHelper implements FlowBasedService
         List<ListenableFuture<Void>> futures = new ArrayList<>();
         BigInteger dpId = FlowBasedServicesUtils.getDpnIdFromInterface(ifState);
         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
+        Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(ifState.getName(), dataBroker);
         LOG.info("binding egress service for vlan port: {}", ifState.getName());
         if (allServices.size() == 1) {
             //calling LportDispatcherTableForService with current service index as 0 and next service index as
             // some value since this is the only service bound.
-            FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, boundServiceNew, ifState.getName(),
-                    transaction, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, (short) (boundServiceNew.getServicePriority() + 1));
+            FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, boundServiceNew, ifState.getName(),
+                    transaction, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, (short) (boundServiceNew.getServicePriority() + 1), iface);
             if (transaction != null) {
                 futures.add(transaction.submit());
             }
@@ -129,7 +131,8 @@ public class FlowBasedEgressServicesConfigBindHelper implements FlowBasedService
                 //In this case the match criteria of existing service should be changed.
                 BoundServices lower = FlowBasedServicesUtils.getHighAndLowPriorityService(allServices, low)[0];
                 short lowerServiceIndex = (short) ((lower != null) ? lower.getServicePriority() : low.getServicePriority() + 1);
-                FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, low, ifState.getName(), transaction, ifState.getIfIndex(), low.getServicePriority(), lowerServiceIndex);
+                FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, low, ifState.getName(), transaction, ifState.getIfIndex(),
+                        low.getServicePriority(), lowerServiceIndex, iface);
             } else {
                 currentServiceIndex = boundServiceNew.getServicePriority();
             }
@@ -137,12 +140,12 @@ public class FlowBasedEgressServicesConfigBindHelper implements FlowBasedService
         if (high != null) {
             currentServiceIndex = boundServiceNew.getServicePriority();
             if (high.equals(highest)) {
-                FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, high, ifState.getName(), transaction, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, currentServiceIndex);
+                FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, high, ifState.getName(), transaction, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, currentServiceIndex, iface);
             } else {
-                FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, high, ifState.getName(), transaction, ifState.getIfIndex(), high.getServicePriority(), currentServiceIndex);
+                FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, high, ifState.getName(), transaction, ifState.getIfIndex(), high.getServicePriority(), currentServiceIndex, iface);
             }
         }
-        FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, boundServiceNew, ifState.getName(), transaction, ifState.getIfIndex(), currentServiceIndex, nextServiceIndex);
+        FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, boundServiceNew, ifState.getName(), transaction, ifState.getIfIndex(), currentServiceIndex, nextServiceIndex, iface);
         futures.add(transaction.submit());
         return futures;
     }
index 5be2bc84f0a33f4cca73419f1d080f54d9bda4c1..c716bab97b8e851d6c1269b9f43543b2edc9ef23 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilit
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
@@ -96,10 +97,11 @@ public class FlowBasedEgressServicesConfigUnbindHelper implements FlowBasedServi
 
         List<ListenableFuture<Void>> futures = new ArrayList<>();
         WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+        Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(ifaceState.getName(), dataBroker);
         BigInteger dpId = FlowBasedServicesUtils.getDpnIdFromInterface(ifaceState);
         if (boundServices.isEmpty()) {
             // Remove default entry from Lport Dispatcher Table.
-            FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), boundServiceOld, t, NwConstants.DEFAULT_SERVICE_INDEX);
+            FlowBasedServicesUtils.removeEgressDispatcherFlows(dpId, ifaceState.getName(), boundServiceOld, t, NwConstants.DEFAULT_SERVICE_INDEX);
             if (t != null) {
                 futures.add(t.submit());
             }
@@ -110,22 +112,22 @@ public class FlowBasedEgressServicesConfigUnbindHelper implements FlowBasedServi
         BoundServices high = highLow[1];
         // This means the one removed was the highest priority service
         if (high == null) {
-            FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), boundServiceOld, t, NwConstants.DEFAULT_SERVICE_INDEX);
+            FlowBasedServicesUtils.removeEgressDispatcherFlows(dpId, ifaceState.getName(), boundServiceOld, t, NwConstants.DEFAULT_SERVICE_INDEX);
             if (low != null) {
                 //delete the lower services flow entry.
-                FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), low, t, low.getServicePriority());
+                FlowBasedServicesUtils.removeEgressDispatcherFlows(dpId, ifaceState.getName(), low, t, low.getServicePriority());
                 BoundServices lower = FlowBasedServicesUtils.getHighAndLowPriorityService(boundServices, low)[0];
                 short lowerServiceIndex = (short) ((lower!=null) ? lower.getServicePriority() : low.getServicePriority() + 1);
-                FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, low, ifaceState.getName(), t, ifaceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, lowerServiceIndex);
+                FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, low, ifaceState.getName(), t, ifaceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, lowerServiceIndex, iface);
             }
         } else {
-            FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), boundServiceOld, t, boundServiceOld.getServicePriority());
+            FlowBasedServicesUtils.removeEgressDispatcherFlows(dpId, ifaceState.getName(), boundServiceOld, t, boundServiceOld.getServicePriority());
             short lowerServiceIndex = (short) ((low!=null) ? low.getServicePriority() : boundServiceOld.getServicePriority() + 1);
             BoundServices highest = FlowBasedServicesUtils.getHighestPriorityService(boundServices);
             if (high.equals(highest)) {
-                FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, high, ifaceState.getName(),t, ifaceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, lowerServiceIndex);
+                FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, high, ifaceState.getName(),t, ifaceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, lowerServiceIndex, iface);
             } else {
-                FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, high, ifaceState.getName(),t, ifaceState.getIfIndex(), high.getServicePriority(), lowerServiceIndex);
+                FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, high, ifaceState.getName(),t, ifaceState.getIfIndex(), high.getServicePriority(), lowerServiceIndex, iface);
             }
         }
         futures.add(t.submit());
index ed8b32db4a9011ae23087b21f84ac8e30069ff0e..ac54322e38c6f72db0b2fa47bfa645ffd78a9a52 100644 (file)
@@ -111,16 +111,17 @@ public class FlowBasedEgressServicesStateBindHelper implements FlowBasedServices
         });
         BoundServices highestPriority = allServices.remove(0);
         short nextServiceIndex = (short) (allServices.size() > 0 ? allServices.get(0).getServicePriority() : highestPriority.getServicePriority() + 1);
-        FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, highestPriority, ifState.getName(), t, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, nextServiceIndex);
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(ifState.getName(), dataBroker);
+        FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, highestPriority, ifState.getName(), t, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, nextServiceIndex, iface);
         BoundServices prev = null;
         for (BoundServices boundService : allServices) {
             if (prev!=null) {
-                FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, prev, ifState.getName(), t, ifState.getIfIndex(), prev.getServicePriority(), boundService.getServicePriority());
+                FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, prev, ifState.getName(), t, ifState.getIfIndex(), prev.getServicePriority(), boundService.getServicePriority(), iface);
             }
             prev = boundService;
         }
         if (prev!=null) {
-            FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, prev, ifState.getName(), t, ifState.getIfIndex(), prev.getServicePriority(), (short) (prev.getServicePriority()+1));
+            FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, prev, ifState.getName(), t, ifState.getIfIndex(), prev.getServicePriority(), (short) (prev.getServicePriority()+1), iface);
         }
         futures.add(t.submit());
         return futures;
index ad7654f532d181c9fb74a69c125292b9346ef9c5..ca70cd4ad1eeb52eadd70f7b673bf53ce95fe789 100644 (file)
@@ -114,9 +114,9 @@ public class FlowBasedEgressServicesStateUnbindHelper implements FlowBasedServic
             }
         });
         BoundServices highestPriority = allServices.remove(0);
-        FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), highestPriority, t, NwConstants.DEFAULT_SERVICE_INDEX);
+        FlowBasedServicesUtils.removeEgressDispatcherFlows(dpId, ifaceState.getName(), highestPriority, t, NwConstants.DEFAULT_SERVICE_INDEX);
         for (BoundServices boundService : allServices) {
-            FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), boundService, t, boundService.getServicePriority());
+            FlowBasedServicesUtils.removeEgressDispatcherFlows(dpId, ifaceState.getName(), boundService, t, boundService.getServicePriority());
         }
         futures.add(t.submit());
         return futures;
index b73a1f340378f8a9b79016015d6591660989df8d..c49e6e02149a1da204a60030c71089ba0bdcf8e2 100644 (file)
@@ -24,6 +24,10 @@ import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUt
 import org.opendaylight.genius.mdsalutil.MatchFieldType;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
+import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.ActionType;
+import org.opendaylight.genius.mdsalutil.InstructionInfo;
+import org.opendaylight.genius.mdsalutil.InstructionType;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
@@ -31,6 +35,7 @@ import org.opendaylight.genius.mdsalutil.NxMatchInfo;
 import org.opendaylight.genius.mdsalutil.NxMatchFieldType;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
@@ -150,8 +155,8 @@ public class FlowBasedServicesUtils {
         return matches;
     }
 
-    public static List<NxMatchInfo> getMatchInfoForEgressDispatcherTable(int interfaceTag, short serviceIndex) {
-        List<NxMatchInfo> matches = new ArrayList<>();
+    public static List<MatchInfoBase> getMatchInfoForEgressDispatcherTable(int interfaceTag, short serviceIndex) {
+        List<MatchInfoBase> matches = new ArrayList<>();
         matches.add(new NxMatchInfo(NxMatchFieldType.nxm_reg_6, new long[] {
                 MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, serviceIndex)}));
         return matches;
@@ -240,8 +245,7 @@ public class FlowBasedServicesUtils {
                                                   WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
         LOG.debug("Installing LPort Dispatcher Flow {}, {}", dpId, interfaceName);
         String serviceRef = boundService.getServiceName();
-        List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId,
-                interfaceTag, currentServiceIndex);
+        List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, interfaceTag, currentServiceIndex);
 
         // Get the metadata and mask from the service's write metadata instruction
         StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
@@ -271,12 +275,23 @@ public class FlowBasedServicesUtils {
         installFlow(dpId, ingressFlow, t);
     }
 
-    public static void installEgressDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
-                                                  WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
+    public static void installEgressDispatcherFlows(BigInteger dpId, BoundServices boundService, String interfaceName,
+                                                  WriteTransaction t, int interfaceTag, short currentServiceIndex,
+                                                  short nextServiceIndex, Interface iface) {
         LOG.debug("Installing Egress Dispatcher Flows {}, {}", dpId, interfaceName);
+        installEgressDispatcherFlow(dpId, boundService, interfaceName, t, interfaceTag, currentServiceIndex, nextServiceIndex);
+
+        // Install Split Horizon drop flow only for the default egress service - this flow drops traffic targeted to external interfaces if they arrived
+        // from an external interface (marked with the SH bit)
+        if (boundService.getServicePriority() == ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
+            installEgressDispatcherSplitHorizonFlow(dpId, boundService, interfaceName, t, interfaceTag, currentServiceIndex, iface);
+        }
+    }
+
+    private static void installEgressDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
+        WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
         String serviceRef = boundService.getServiceName();
-        List<? extends MatchInfoBase> matches;
-        matches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
+        List<? extends MatchInfoBase> matches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
 
         // Get the metadata and mask from the service's write metadata instruction
         StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
@@ -305,11 +320,39 @@ public class FlowBasedServicesUtils {
 
         // build the flow and install it
         String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, boundService, currentServiceIndex);
-        Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
+        Flow egressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
                 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
-        installFlow(dpId, ingressFlow, t);
+        installFlow(dpId, egressFlow, t);
     }
 
+    public static void installEgressDispatcherSplitHorizonFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
+            WriteTransaction t, int interfaceTag, short currentServiceIndex, Interface iface) {
+        // only install split horizon drop flows for external interfaces
+        if (!isExternal(iface)) {
+            return;
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Installing split horizon drop flow for external interface {} on dpId {}", interfaceName, dpId);
+        }
+
+        BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for checking the Split-Horizon flag
+        StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
+        List<MatchInfoBase> shMatches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
+        shMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { shFlagSet, MetaDataUtil.METADATA_MASK_SH_FLAG }));
+        List<InstructionInfo> shInstructions = new ArrayList<>();
+        List<ActionInfo> actionsInfos = new ArrayList<>();
+        actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}));
+        shInstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+
+        String flowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, currentServiceIndex, shFlagSet);
+        String serviceRef = boundService.getServiceName();
+        int splitHorizonFlowPriority = boundService.getServicePriority() + 1; // this must be higher priority than the egress flow
+        Flow egressSplitHorizonFlow = MDSALUtil.buildFlow(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
+                splitHorizonFlowPriority, serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), shMatches, shInstructions);
+
+        installFlow(dpId, egressSplitHorizonFlow, t);
+    }
 
     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
                                                  BigInteger cookie, List<Instruction> instructions) {
@@ -379,8 +422,14 @@ public class FlowBasedServicesUtils {
         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
     }
 
-    public static void removeEgressDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
+    public static void removeEgressDispatcherFlows(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
         LOG.debug("Removing Egress Dispatcher Flows {}, {}", dpId, iface);
+        removeEgressDispatcherFlow(dpId, iface, t, currentServiceIndex, boundServicesOld);
+        removeEgressSplitHorizonDispatcherFlow(dpId, iface, t, currentServiceIndex);
+    }
+
+    private static void removeEgressDispatcherFlow(BigInteger dpId, String iface, WriteTransaction t,
+            short currentServiceIndex, BoundServices boundServicesOld) {
         // build the flow and install it
         String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, boundServicesOld, currentServiceIndex);
         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
@@ -392,11 +441,27 @@ public class FlowBasedServicesUtils {
         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
     }
 
+    public static void removeEgressSplitHorizonDispatcherFlow(BigInteger dpId, String iface, WriteTransaction t, short currentServiceIndex) {
+        BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for checking the Split-Horizon flag
+        String shFlowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, currentServiceIndex, shFlagSet);
+        FlowKey shFlowKey = new FlowKey(new FlowId(shFlowRef));
+        Node nodeDpn = buildInventoryDpnNode(dpId);
+        InstanceIdentifier<Flow> shFlowInstanceId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, shFlowKey).build();
+
+        t.delete(LogicalDatastoreType.CONFIGURATION, shFlowInstanceId);
+    }
+
     private static String getFlowRef(BigInteger dpnId, short tableId, String iface, BoundServices service, short currentServiceIndex) {
         return new StringBuffer().append(dpnId).append(tableId).append(NwConstants.FLOWID_SEPARATOR)
                 .append(iface).append(NwConstants.FLOWID_SEPARATOR).append(currentServiceIndex).toString();
     }
 
+    private static String getSplitHorizonFlowRef(BigInteger dpnId, short tableId, String iface, short currentServiceIndex, BigInteger shFlag) {
+        return new StringBuffer().append(dpnId).append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(iface).append(NwConstants.FLOWID_SEPARATOR).append(shFlag.toString()).toString();
+    }
     /**
      * This util method returns an array of ServiceInfo in which index 0 will
      * have the immediate lower priority service and index 1 will have the
index fa5358df107ae7a7c8bfcab5e7931979a43da83f..84a1a05f2f0ffe5c14b2504e70b925bd00538010 100644 (file)
@@ -19,6 +19,7 @@ public class MetaDataUtil {
     public static final BigInteger METADA_MASK_TUNNEL_ID =       new BigInteger("00000000FFFFFF00", 16);
     public static final BigInteger METADATA_MASK_SERVICE_SH_FLAG = new BigInteger("000000FFFF000001", 16);
     public static final BigInteger METADATA_MASK_LPORT_TAG_SH_FLAG =     new BigInteger("0FFFFF0000000001", 16);
+    public static final BigInteger METADATA_MASK_SH_FLAG = new BigInteger("0000000000000001", 16);
     public static final BigInteger METADATA_MASK_ELAN_SUBNET_ROUTE =    new BigInteger("0000FFFF00000000", 16);
     public static final BigInteger METADATA_MASK_SUBNET_ROUTE =         new BigInteger("0000FFFFFFFFFFFE", 16);