X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=interfacemanager%2Finterfacemanager-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fgenius%2Finterfacemanager%2Fservicebindings%2Fflowbased%2Futilities%2FFlowBasedServicesUtils.java;h=edddf787b715adf918584760496e15dd82aa2aff;hb=948b6a39239ab278fcd25b521aa55b2d5bea199c;hp=63ce4058913a780bd95caefc833da74e69d2b3bc;hpb=2c0cb5d476bb844545e7b9e584518e87ced96920;p=genius.git diff --git a/interfacemanager/interfacemanager-impl/src/main/java/org/opendaylight/genius/interfacemanager/servicebindings/flowbased/utilities/FlowBasedServicesUtils.java b/interfacemanager/interfacemanager-impl/src/main/java/org/opendaylight/genius/interfacemanager/servicebindings/flowbased/utilities/FlowBasedServicesUtils.java index 63ce40589..edddf787b 100644 --- a/interfacemanager/interfacemanager-impl/src/main/java/org/opendaylight/genius/interfacemanager/servicebindings/flowbased/utilities/FlowBasedServicesUtils.java +++ b/interfacemanager/interfacemanager-impl/src/main/java/org/opendaylight/genius/interfacemanager/servicebindings/flowbased/utilities/FlowBasedServicesUtils.java @@ -8,14 +8,35 @@ package org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableBiMap; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import com.google.common.util.concurrent.ListenableFuture; 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.genius.interfacemanager.IfmConstants; import org.opendaylight.genius.interfacemanager.IfmUtil; import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils; -import org.opendaylight.genius.mdsalutil.*; +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; +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; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; @@ -24,33 +45,48 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta 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.instruction.instruction.WriteMetadataCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan; +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.ServiceTypeFlowBased; +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress; +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.SplitHorizon; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -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.StypeOpenflow; -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; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - public class FlowBasedServicesUtils { private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class); - public static ServicesInfo getServicesInfoForInterface(String interfaceName, DataBroker dataBroker) { - ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName); + public enum ServiceMode { + INGRESS, + EGRESS + } + + public static final ImmutableBiMap SERVICE_MODE_MAP = + new ImmutableBiMap.Builder>() + .put(ServiceMode.EGRESS, ServiceModeEgress.class) + .put(ServiceMode.INGRESS, ServiceModeIngress.class) + .build(); + + public static ServicesInfo getServicesInfoForInterface(String interfaceName, Class serviceMode, + DataBroker dataBroker) { + ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName,serviceMode); InstanceIdentifier.InstanceIdentifierBuilder servicesInfoIdentifierBuilder = InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey); Optional servicesInfoOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION, @@ -63,9 +99,9 @@ public class FlowBasedServicesUtils { return null; } - public static NodeConnectorId getNodeConnectorIdFromInterface(Interface iface, DataBroker dataBroker) { + 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(iface.getName(), dataBroker); + InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(interfaceName, dataBroker); if(ifState != null) { List ofportIds = ifState.getLowerLayerIf(); return new NodeConnectorId(ofportIds.get(0)); @@ -73,6 +109,23 @@ public class FlowBasedServicesUtils { return null; } + public static NodeConnectorId getNodeConnectorIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) { + if(ifState != null) { + List ofportIds = ifState.getLowerLayerIf(); + return new NodeConnectorId(ofportIds.get(0)); + } + return null; + } + + public static BigInteger getDpnIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) { + NodeConnectorId nodeConnectorId = null; + if(ifState != null) { + List ofportIds = ifState.getLowerLayerIf(); + nodeConnectorId = new NodeConnectorId(ofportIds.get(0)); + } + return IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId); + } + public static List getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) { List matches = new ArrayList<>(); matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {dpId, BigInteger.valueOf(portNo)})); @@ -87,40 +140,26 @@ public class FlowBasedServicesUtils { return matches; } - public static List getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) { - List matches = new ArrayList(); + public static List getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo) { + List matches = new ArrayList<>(); matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)})); return matches; } - public static List getMatchInfoForDispatcherTable(BigInteger dpId, Interface iface, + public static List getMatchInfoForDispatcherTable(BigInteger dpId, int interfaceTag, short servicePriority) { - List matches = new ArrayList(); + List matches = new ArrayList<>(); matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority), MetaDataUtil.getMetaDataMaskForLPortDispatcher() })); return matches; } - public static Long getLPortTag(Interface iface, DataBroker dataBroker) { - /*ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class); - String portName = parentRefs.getParentInterface(); - BigInteger dpIdFromInterface = parentRefs.getDatapathNodeIdentifier(); - String portKey = FlowBasedServicesUtils.getInterfaceRefInfo(dpIdFromInterface.toString(), portName); - if (iface.getType().isAssignableFrom(L2vlan.class)) { - InterfacesMetaKey interfacesMetaKey = new InterfacesMetaKey(portKey); - InterfacesInfoKey interfacesInfoKey = new InterfacesInfoKey(iface.getName()); - InterfacesInfo interfacesInfo = VlanInterfaceUtilities.getInterfacesInfoFromConfigDS(interfacesMetaKey, - interfacesInfoKey, dataBroker); - return interfacesInfo.getLporttag(); - } else if (iface.getType().isAssignableFrom(Tunnel.class)) { - TunnelInterfaceRefInfoKey tunnelInterfaceRefInfoKey = new TunnelInterfaceRefInfoKey(portKey); - TunnelInterfaceEntries tunnelInterfaceEntries = - TunnelInterfaceUtilities.getTunnelInterfaceRefEntriesFromConfigDs( - tunnelInterfaceRefInfoKey, iface.getName(), dataBroker); - return tunnelInterfaceEntries.getLportTag(); - } */ - return 0L; + public static List getMatchInfoForEgressDispatcherTable(int interfaceTag, short serviceIndex) { + List matches = new ArrayList<>(); + matches.add(new NxMatchInfo(NxMatchFieldType.nxm_reg_6, new long[] { + MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, serviceIndex)})); + return matches; } public static void installInterfaceIngressFlow(BigInteger dpId, Interface iface, @@ -130,7 +169,7 @@ public class FlowBasedServicesUtils { List instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction(); int serviceInstructionsSize = instructions.size(); - List instructionSet = new ArrayList(); + List instructionSet = new ArrayList<>(); int vlanId = 0; IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class); if(l2vlan != null && l2vlan.getVlanId() != null){ @@ -146,10 +185,10 @@ public class FlowBasedServicesUtils { BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions); short sIndex = boundServiceNew.getServicePriority(); BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, - ++sIndex, metadataValues[0]); + ++sIndex, metadataValues[0], isExternal(iface)); BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher( MetaDataUtil.METADATA_MASK_SERVICE_INDEX, - MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]); + MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG, metadataValues[1]); instructionSet.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++serviceInstructionsSize)); } @@ -165,7 +204,8 @@ public class FlowBasedServicesUtils { } String serviceRef = boundServiceNew.getServiceName(); - String flowRef = getFlowRef(dpId, 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, @@ -201,12 +241,11 @@ public class FlowBasedServicesUtils { return nodeDpn; } - public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, Interface iface, + public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName, WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) { - LOG.debug("Installing LPort Dispatcher Flows {}, {}", dpId, iface); + LOG.debug("Installing LPort Dispatcher Flow {}, {}", dpId, interfaceName); String serviceRef = boundService.getServiceName(); - List matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, iface, - interfaceTag, currentServiceIndex); + List matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, interfaceTag, currentServiceIndex); // Get the metadata and mask from the service's write metadata instruction StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class); @@ -217,7 +256,7 @@ public class FlowBasedServicesUtils { BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable(); // build the final instruction for LPort Dispatcher table flow entry - List instructions = new ArrayList(); + List instructions = new ArrayList<>(); instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize)); if (serviceInstructions != null && !serviceInstructions.isEmpty()) { for (Instruction info : serviceInstructions) { @@ -230,15 +269,135 @@ public class FlowBasedServicesUtils { } // build the flow and install it - String flowRef = getFlowRef(dpId, iface.getName(), 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, instructions); installFlow(dpId, ingressFlow, t); } + 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 matches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex); + + // Get the metadata and mask from the service's write metadata instruction + StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class); + List serviceInstructions = stypeOpenFlow.getInstruction(); + int instructionSize = serviceInstructions.size(); + + // build the final instruction for LPort Dispatcher table flow entry + List 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, + MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, nextServiceIndex))); + } + if (serviceInstructions != null && !serviceInstructions.isEmpty()) { + for (Instruction info : serviceInstructions) { + // Skip meta data write as that is handled already + if (info.getInstruction() instanceof WriteMetadataCase) { + continue; + } + instructions.add(info); + } + } + + // build the flow and install it + String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, boundService, currentServiceIndex); + Flow egressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef, + boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions); + 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 shMatches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex); + shMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { shFlagSet, MetaDataUtil.METADATA_MASK_SH_FLAG })); + List shInstructions = new ArrayList<>(); + List 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 instructions) { + StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority).setInstruction(instructions); + return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)) + .setServiceName(serviceName).setServicePriority(servicePriority) + .setServiceType(ServiceTypeFlowBased.class).addAugmentation(StypeOpenflow.class, augBuilder.build()).build(); + } + + public static InstanceIdentifier buildServiceId(String interfaceName, short serviceIndex) { + return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, + new ServicesInfoKey(interfaceName, ServiceModeIngress.class)) + .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build(); + } + + public static InstanceIdentifier buildServiceId(String interfaceName, short serviceIndex, Class serviceMode) { + return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, + new ServicesInfoKey(interfaceName, serviceMode)) + .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build(); + } + + public static void unbindDefaultEgressDispatcherService(DataBroker dataBroker, String interfaceName, String parentInterface) { + IfmUtil.unbindService(dataBroker, interfaceName, buildServiceId(interfaceName, + ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX), + ServiceModeEgress.class), parentInterface); + } + + public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List> futures, + Interface interfaceInfo, String portNo, + String interfaceName, int ifIndex) { + WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); + int priority = ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX); + List 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); + IfmUtil.bindService(tx, interfaceName, serviceInfo, ServiceModeEgress.class); + futures.add(tx.submit()); + } + public static void removeIngressFlow(String name, BoundServices serviceOld, BigInteger dpId, WriteTransaction t) { LOG.debug("Removing Ingress Flows"); - String flowKeyStr = getFlowRef(dpId, name, serviceOld, serviceOld.getServicePriority()); + String flowKeyStr = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, name, serviceOld, serviceOld.getServicePriority()); FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr)); Node nodeDpn = buildInventoryDpnNode(dpId); InstanceIdentifier flowInstanceId = InstanceIdentifier.builder(Nodes.class) @@ -251,9 +410,9 @@ public class FlowBasedServicesUtils { public static void removeLPortDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) { LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface); - StypeOpenflow stypeOpenFlow = boundServicesOld.getAugmentation(StypeOpenflow.class); + boundServicesOld.getAugmentation(StypeOpenflow.class); // build the flow and install it - String flowRef = getFlowRef(dpId, iface, boundServicesOld, currentServiceIndex); + String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, iface, boundServicesOld, currentServiceIndex); FlowKey flowKey = new FlowKey(new FlowId(flowRef)); Node nodeDpn = buildInventoryDpnNode(dpId); InstanceIdentifier flowInstanceId = InstanceIdentifier.builder(Nodes.class) @@ -263,11 +422,46 @@ public class FlowBasedServicesUtils { t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId); } - private static String getFlowRef(BigInteger dpnId, String iface, BoundServices service, short currentServiceIndex) { - return new StringBuffer().append(dpnId).append(NwConstants.VLAN_INTERFACE_INGRESS_TABLE).append(NwConstants.FLOWID_SEPARATOR) + 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)); + Node nodeDpn = buildInventoryDpnNode(dpId); + InstanceIdentifier flowInstanceId = 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, flowKey).build(); + + 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 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 @@ -277,14 +471,14 @@ public class FlowBasedServicesUtils { * @param currentServiceInfo * @return */ - public static BoundServices[] getHighAndLowPriorityService( - List serviceInfos, BoundServices currentServiceInfo) { - BoundServices higher = null; // this will be used to hold the immediate higher service priority with respect to the currentServiceInfo - BoundServices lower = null; // this will be used to hold the immediate lower service priority with respect to the currentServiceInfo + public static BoundServices[] getHighAndLowPriorityService( + List serviceInfos, BoundServices currentServiceInfo) { + BoundServices higher = null; // this will be used to hold the immediate higher service priority with respect to the currentServiceInfo + BoundServices lower = null; // this will be used to hold the immediate lower service priority with respect to the currentServiceInfo if (serviceInfos == null || serviceInfos.isEmpty()) { return new BoundServices[]{lower, higher}; } - List availableServiceInfos = new ArrayList(serviceInfos); + List availableServiceInfos = new ArrayList<>(serviceInfos); Collections.sort(availableServiceInfos, new Comparator() { @Override public int compare(BoundServices serviceInfo1, BoundServices serviceInfo2) { @@ -303,7 +497,7 @@ public class FlowBasedServicesUtils { } public static BoundServices getHighestPriorityService(List serviceInfos) { - List availableServiceInfos = new ArrayList(serviceInfos); + List availableServiceInfos = new ArrayList<>(serviceInfos); if (availableServiceInfos.isEmpty()) { return null; } @@ -317,37 +511,58 @@ public class FlowBasedServicesUtils { return highPriorityService; } - public static void installVlanFlow(BigInteger dpId, long portNo, Interface iface, - WriteTransaction t, List matches, int lportTag) { + public static void installLportIngressFlow(BigInteger dpId, long portNo, Interface iface, + List> futures, DataBroker dataBroker, + int lportTag) { int vlanId = 0; boolean isVlanTransparent = false; + WriteTransaction inventoryConfigShardTransaction = dataBroker.newWriteOnlyTransaction(); + List matches = getMatchInfoForVlanPortAtIngressTable(dpId, portNo, iface); IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class); if(l2vlan != null){ vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue(); isVlanTransparent = l2vlan.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent; } int instructionKey = 0; - BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0); - BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(); - List instructions = new ArrayList(); + BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0, BigInteger.ZERO, isExternal(iface)); + BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG); + List instructions = new ArrayList<>(); + + final SplitHorizon splitHorizon = iface.getAugmentation(SplitHorizon.class); + boolean overrideSplitHorizonProtection = (splitHorizon != null && splitHorizon.isOverrideSplitHorizonProtection()); + int actionKey = 0; + List actions = new ArrayList<>(); if (vlanId != 0 && !isVlanTransparent) { - instructions.add(MDSALUtil.buildAndGetPopVlanActionInstruction(lportTag, instructionKey++)); + actions.add(MDSALUtil.createPopVlanAction(actionKey++)); + } + if (overrideSplitHorizonProtection) { + actions.add(MDSALUtil.createNxOfInPortAction(actionKey++,0)); } + if (actions.size() != 0) { + instructions.add(MDSALUtil.buildApplyActionsInstruction(actions,instructionKey++)); + } + instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++)); - instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.DHCP_TABLE, instructionKey++)); + instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.LPORT_DISPATCHER_TABLE, instructionKey++)); int priority = isVlanTransparent ? 1 : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY; String flowRef = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, iface.getName()); Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef, 0, 0, - IfmConstants.VLAN_TABLE_COOKIE, matches, instructions); - installFlow(dpId, ingressFlow, t); -} + NwConstants.VLAN_TABLE_COOKIE, matches, instructions); + installFlow(dpId, ingressFlow, inventoryConfigShardTransaction); + futures.add(inventoryConfigShardTransaction.submit()); + } public static String getFlowRef(short tableId, BigInteger dpnId, String infName) { return String.format("%d:%s:%s", tableId, dpnId, infName); } - public static void removeIngressFlow(String interfaceName, BigInteger dpId, WriteTransaction t) { - LOG.debug("Removing Ingress Flows"); + public static void removeIngressFlow(String interfaceName, BigInteger dpId, DataBroker dataBroker, + List> futures) { + if(dpId == null){ + return; + } + LOG.debug("Removing Ingress Flows for {}", interfaceName); + WriteTransaction t = dataBroker.newWriteOnlyTransaction(); String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName); FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr)); Node nodeDpn = buildInventoryDpnNode(dpId); @@ -356,7 +571,14 @@ public class FlowBasedServicesUtils { .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build(); t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId); + futures.add(t.submit()); } - + private static boolean isExternal(Interface iface) { + if (iface == null) { + return false; + } + IfExternal ifExternal = iface.getAugmentation(IfExternal.class); + return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal()); + } }