Merge "Bug 8859 : Table 220 programmed with wrong service-index"
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / servicebindings / flowbased / utilities / FlowBasedServicesUtils.java
index 76428635f8d9cc78ade65e79b451443ee42f3795..4beb1586b88124bb97992037397fb19887e9f6bf 100644 (file)
@@ -13,6 +13,7 @@ import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import org.apache.commons.lang3.StringUtils;
 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;
@@ -48,6 +49,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.SplitHorizon;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.BoundServicesStateList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
 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.ServiceModeEgress;
@@ -55,6 +57,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.ser
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.bound.services.state.list.BoundServicesState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.bound.services.state.list.BoundServicesStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.bound.services.state.list.BoundServicesStateKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
@@ -73,6 +78,7 @@ import org.slf4j.LoggerFactory;
 
 public class FlowBasedServicesUtils {
     private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
+    private static final int DEFAULT_DISPATCHER_PRIORITY = 10;
 
     public enum ServiceMode {
         INGRESS, EGRESS
@@ -95,7 +101,7 @@ public class FlowBasedServicesUtils {
     public static NodeConnectorId getNodeConnectorIdFromInterface(String interfaceName, DataBroker dataBroker) {
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
             .ietf.interfaces.rev140508.interfaces.state.Interface ifState = InterfaceManagerCommonUtils
-                .getInterfaceStateFromOperDS(interfaceName, dataBroker);
+                .getInterfaceState(interfaceName, dataBroker);
         if (ifState != null) {
             List<String> ofportIds = ifState.getLowerLayerIf();
             return new NodeConnectorId(ofportIds.get(0));
@@ -129,10 +135,10 @@ public class FlowBasedServicesUtils {
         matches.add(new MatchInPort(dpId, portNo));
         int vlanId = 0;
         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
-        if (l2vlan != null && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent) {
+        if (l2vlan != null) {
             vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
         }
-        if (vlanId > 0) {
+        if (vlanId >= 0  && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent) {
             matches.add(new MatchVlanVid(vlanId));
         }
         return matches;
@@ -206,8 +212,8 @@ public class FlowBasedServicesUtils {
         }
 
         String serviceRef = boundServiceNew.getServiceName();
-        String flowRef = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, iface.getName(), boundServiceNew,
-                boundServiceNew.getServicePriority());
+        String flowRef = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, iface.getName(),
+                boundServiceNew, boundServiceNew.getServicePriority());
         StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
         Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef, stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
                 stypeOpenflow.getFlowCookie(), matches, instructionSet);
@@ -224,18 +230,6 @@ public class FlowBasedServicesUtils {
         writeTransaction.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
     }
 
-    public static void removeFlow(String flowRef, BigInteger dpId, WriteTransaction writeTransaction) {
-        LOG.debug("Removing Ingress Flows");
-        FlowKey flowKey = new FlowKey(new FlowId(flowRef));
-        Node nodeDpn = buildInventoryDpnNode(dpId);
-        InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey)
-                .build();
-
-        writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
-    }
-
     private static Node buildInventoryDpnNode(BigInteger dpnId) {
         NodeId nodeId = new NodeId("openflow:" + dpnId);
         Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
@@ -245,7 +239,6 @@ public class FlowBasedServicesUtils {
 
     public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
             WriteTransaction writeTransaction, 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);
@@ -280,18 +273,20 @@ public class FlowBasedServicesUtils {
         }
 
         // build the flow and install it
-        String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, interfaceName, boundService,
-                currentServiceIndex);
+        String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, interfaceName,
+            boundService, currentServiceIndex);
         Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
-                boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches,
+                DEFAULT_DISPATCHER_PRIORITY, serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches,
                 instructions);
+        LOG.debug("Installing LPort Dispatcher Flow on DPN {}, for interface {}, with flowRef {}", dpId,
+            interfaceName, flowRef);
         installFlow(dpId, ingressFlow, writeTransaction);
     }
 
     public static void installEgressDispatcherFlows(BigInteger dpId, BoundServices boundService, String interfaceName,
             WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex,
             Interface iface) {
-        LOG.debug("Installing Egress Dispatcher Flows {}, {}", dpId, interfaceName);
+        LOG.debug("Installing Egress Dispatcher Flows on dpn : {}, for interface : {}", dpId, interfaceName);
         installEgressDispatcherFlow(dpId, boundService, interfaceName, writeTransaction, interfaceTag,
                 currentServiceIndex, nextServiceIndex);
 
@@ -308,51 +303,60 @@ public class FlowBasedServicesUtils {
 
     private static void installEgressDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
             WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
-        String serviceRef = boundService.getServiceName();
-        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);
-        List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
-        int instructionSize = serviceInstructions.size();
+        // Get the metadata and mask from the service's write metadata instruction
+        StypeOpenflow stypeOpenflow = boundService.getAugmentation(StypeOpenflow.class);
+        if (stypeOpenflow == null) {
+            LOG.warn("Could not install egress dispatcher flow, missing service openflow configuration");
+            return;
+        }
+        List<Instruction> serviceInstructions = stypeOpenflow.getInstruction() != null
+                ? stypeOpenflow.getInstruction()
+                : Collections.emptyList();
 
         // build the final instruction for LPort Dispatcher table flow entry
+        List<Action> finalApplyActions = new ArrayList<>();
         List<Instruction> instructions = new ArrayList<>();
         if (boundService.getServicePriority() != ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
                 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
             BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
-            BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex,
-                    metadataValues[0]);
-            BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
-            instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
-            instructions.add(MDSALUtil.buildAndGetSetReg6ActionInstruction(0, ++instructionSize, 0, 31,
+            BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForEgressDispatcherTable();
+            instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadataValues[0], metadataMask,
+                    instructions.size()));
+            finalApplyActions.add(MDSALUtil.createSetReg6Action(finalApplyActions.size(), 0, 31,
                     MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, nextServiceIndex)));
         }
-        if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
-            for (Instruction info : serviceInstructions) {
+
+        final int applyActionsOffset = finalApplyActions.size();
+        for (Instruction info : serviceInstructions) {
+            if (info.getInstruction() instanceof WriteActionsCase) {
+                List<Action> writeActions = ActionConverterUtil.convertServiceActionToFlowAction(
+                        ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction());
+                instructions.add(MDSALUtil.buildWriteActionsInstruction(writeActions, instructions.size()));
+            } else if (info.getInstruction() instanceof ApplyActionsCase) {
+                List<Action> applyActions = ActionConverterUtil.convertServiceActionToFlowAction(
+                        ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction(),
+                        applyActionsOffset);
+                finalApplyActions.addAll(applyActions);
+            } else if (!(info.getInstruction() instanceof WriteMetadataCase)) {
                 // Skip meta data write as that is handled already
-                if (info.getInstruction() instanceof WriteMetadataCase) {
-                    continue;
-                } else if (info.getInstruction() instanceof WriteActionsCase) {
-                    info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
-                            ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction()));
-                } else if (info.getInstruction() instanceof ApplyActionsCase) {
-                    info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
-                            ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction()));
-                }
-                instructions.add(info);
+                instructions.add(MDSALUtil.buildInstruction(info, instructions.size()));
             }
         }
+        if (!finalApplyActions.isEmpty()) {
+            instructions.add(MDSALUtil.buildApplyActionsInstruction(finalApplyActions, instructions.size()));
+        }
 
         // build the flow and install it
+        String serviceRef = boundService.getServiceName();
+        List<? extends MatchInfoBase> matches = FlowBasedServicesUtils
+                .getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
         String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, boundService,
-                currentServiceIndex);
+            currentServiceIndex);
         Flow egressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
-                boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches,
+                boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenflow.getFlowCookie(), matches,
                 instructions);
-        LOG.debug("Installing Egress Dispatcher Flow {}, {}", flowRef, interfaceName);
+        LOG.debug("Installing Egress Dispatcher Flow for interface : {}, with flow-ref : {}", interfaceName, flowRef);
         installFlow(dpId, egressFlow, writeTransaction);
     }
 
@@ -420,16 +424,31 @@ public class FlowBasedServicesUtils {
     }
 
     public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
-            Interface interfaceInfo, String portNo, String interfaceName, int ifIndex) {
+                                                          Interface interfaceInfo, String portNo,
+                                                          String interfaceName, int ifIndex) {
+        List<Instruction> instructions =
+                IfmUtil.getEgressInstructionsForInterface(interfaceInfo, portNo, null, true, ifIndex, 0);
+        bindDefaultEgressDispatcherService(dataBroker, futures, interfaceName, instructions);
+    }
+
+    public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
+            Interface interfaceInfo, String interfaceName, int ifIndex, long groupId) {
+        List<Instruction> instructions =
+             IfmUtil.getEgressInstructionsForInterface(interfaceInfo, StringUtils.EMPTY, null, true, ifIndex, groupId);
+        bindDefaultEgressDispatcherService(dataBroker, futures, interfaceName, instructions);
+    }
+
+    public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
+            String interfaceName, List<Instruction> instructions) {
         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
         int priority = ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
-                NwConstants.DEFAULT_EGRESS_SERVICE_INDEX);
-        List<Instruction> instructions = IfmUtil.getEgressInstructionsForInterface(interfaceInfo, portNo, null, true,
-                ifIndex);
-        BoundServices serviceInfo = getBoundServices(String.format("%s.%s", "default", interfaceName),
-                ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
-                        NwConstants.DEFAULT_EGRESS_SERVICE_INDEX),
-                priority, NwConstants.EGRESS_DISPATCHER_TABLE_COOKIE, instructions);
+                                             NwConstants.DEFAULT_EGRESS_SERVICE_INDEX);
+        BoundServices
+                serviceInfo =
+                getBoundServices(String.format("%s.%s", "default", interfaceName),
+                        ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
+                                              NwConstants.DEFAULT_EGRESS_SERVICE_INDEX),
+                        priority, NwConstants.EGRESS_DISPATCHER_TABLE_COOKIE, instructions);
         IfmUtil.bindService(tx, interfaceName, serviceInfo, ServiceModeEgress.class);
         futures.add(tx.submit());
     }
@@ -475,7 +494,7 @@ public class FlowBasedServicesUtils {
         boundServicesOld.getAugmentation(StypeOpenflow.class);
         // build the flow and install it
         String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, iface, boundServicesOld,
-                currentServiceIndex);
+            currentServiceIndex);
         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
         Node nodeDpn = buildInventoryDpnNode(dpId);
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
@@ -497,7 +516,7 @@ public class FlowBasedServicesUtils {
             short currentServiceIndex, BoundServices boundServicesOld) {
         // build the flow and install it
         String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, boundServicesOld,
-                currentServiceIndex);
+            currentServiceIndex);
         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
         Node nodeDpn = buildInventoryDpnNode(dpId);
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
@@ -528,16 +547,17 @@ public class FlowBasedServicesUtils {
         return String.format("%d:%s:%s", tableId, dpnId, infName);
     }
 
-    private static String getFlowRef(BigInteger dpnId, short tableId, String iface, BoundServices service,
-            short currentServiceIndex) {
-        return String.valueOf(dpnId) + tableId + NwConstants.FLOWID_SEPARATOR + iface + NwConstants.FLOWID_SEPARATOR
-                + currentServiceIndex;
+    private static String getFlowRef(BigInteger dpnId, short tableId, String iface,BoundServices service,
+                                     short currentServiceIndex) {
+        return String.valueOf(dpnId) + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + iface
+                + NwConstants.FLOWID_SEPARATOR + currentServiceIndex;
     }
 
     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();
+        return new StringBuffer().append(dpnId).append(NwConstants.FLOWID_SEPARATOR).append(tableId).append(NwConstants
+                .FLOWID_SEPARATOR).append(iface).append(NwConstants.FLOWID_SEPARATOR)
+                .append(shFlag.toString()).toString();
     }
 
     /**
@@ -637,6 +657,52 @@ public class FlowBasedServicesUtils {
         futures.add(inventoryConfigShardTransaction.submit());
     }
 
+    public static BoundServicesState buildBoundServicesState(
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
+            interfaceState, Class<? extends ServiceModeBase> serviceMode) {
+        NodeConnectorId nodeConnectorId = IfmUtil.getNodeConnectorIdFromInterface(interfaceState);
+        BigInteger dpId = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
+        long portNo = IfmUtil.getPortNumberFromNodeConnectorId(nodeConnectorId);
+        BoundServicesStateKey boundServicesStateKey = new BoundServicesStateKey(interfaceState.getName(), serviceMode);
+        return new BoundServicesStateBuilder().setDpid(dpId).setIfIndex(interfaceState.getIfIndex())
+            .setInterfaceName(interfaceState.getName()).setInterfaceType(interfaceState.getType()).setPortNo(portNo)
+            .setServiceMode(serviceMode).setKey(boundServicesStateKey).build();
+    }
+
+    public static BoundServicesState getBoundServicesState(DataBroker dataBroker,
+                                                           String interfaceName,
+                                                           Class<? extends ServiceModeBase>
+                                                                                 serviceMode) {
+        InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
+            .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName, serviceMode)).build();
+        return IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, dataBroker).orNull();
+    }
+
+    public static void addBoundServicesState(List<ListenableFuture<Void>> futures,
+                                             DataBroker dataBroker, String interfaceName,
+                                             BoundServicesState interfaceBoundServicesState) {
+        LOG.info("adding bound-service state information for interface : {}, service-mode : {}",
+            interfaceBoundServicesState.getInterfaceName(), interfaceBoundServicesState.getServiceMode().getName());
+        InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
+            .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName,
+                interfaceBoundServicesState.getServiceMode())).build();
+        WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+        writeTransaction.put(LogicalDatastoreType.OPERATIONAL, id, interfaceBoundServicesState, true);
+        futures.add(writeTransaction.submit());
+    }
+
+    public static  void removeBoundServicesState(List<ListenableFuture<Void>> futures,
+                                                 DataBroker dataBroker,
+                                                 String interfaceName, Class<? extends ServiceModeBase> serviceMode) {
+        LOG.info("remove bound-service state information for interface : {}, service-mode : {}", interfaceName,
+            serviceMode.getName());
+        InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
+            .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName, serviceMode)).build();
+        WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+        writeTransaction.delete(LogicalDatastoreType.OPERATIONAL, id);
+        futures.add(writeTransaction.submit());
+    }
+
     private static boolean isExternal(Interface iface) {
         if (iface == null) {
             return false;