X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=vpnservice%2Felanmanager%2Felanmanager-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetvirt%2Felan%2Futils%2FElanUtils.java;h=ad0ce127bae043cbeda3ce632d70504907c5f9c2;hb=205886db88d71869d0944cad10cfeb15cfd61c11;hp=d8ce904830b9484b9602ebd885df29c5c9885863;hpb=d554f4a5c6505eb140834286526dc3b86c8b9cf9;p=netvirt.git diff --git a/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java b/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java index d8ce904830..ad0ce127ba 100755 --- a/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java +++ b/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java @@ -8,27 +8,36 @@ package org.opendaylight.netvirt.elan.utils; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.common.primitives.Ints; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; import org.apache.commons.lang3.StringUtils; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; @@ -38,11 +47,12 @@ import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; import org.opendaylight.genius.itm.globals.ITMConstants; import org.opendaylight.genius.mdsalutil.ActionInfo; import org.opendaylight.genius.mdsalutil.FlowEntity; +import org.opendaylight.genius.mdsalutil.FlowEntityBuilder; import org.opendaylight.genius.mdsalutil.InstructionInfo; import org.opendaylight.genius.mdsalutil.MDSALUtil; -import org.opendaylight.genius.mdsalutil.MDSALUtil.MdsalOp; import org.opendaylight.genius.mdsalutil.MatchInfo; import org.opendaylight.genius.mdsalutil.MetaDataUtil; +import org.opendaylight.genius.mdsalutil.NWUtil; import org.opendaylight.genius.mdsalutil.NwConstants; import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit; import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions; @@ -52,13 +62,16 @@ import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination; import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource; import org.opendaylight.genius.mdsalutil.matches.MatchMetadata; import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId; -import org.opendaylight.genius.utils.ServiceIndex; +import org.opendaylight.genius.mdsalutil.packet.ARP; +import org.opendaylight.genius.mdsalutil.packet.Ethernet; +import org.opendaylight.genius.mdsalutil.packet.IPv4; import org.opendaylight.netvirt.elan.ElanException; +import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil; import org.opendaylight.netvirt.elan.internal.ElanInstanceManager; -import org.opendaylight.netvirt.elan.internal.ElanInterfaceManager; import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils; -import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils; -import org.opendaylight.netvirt.elan.l2gw.utils.L2GatewayConnectionUtils; +import org.opendaylight.netvirt.elanmanager.api.ElanHelper; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus; @@ -66,9 +79,12 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces. import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; 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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; 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.instruction.list.Instruction; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder; @@ -79,10 +95,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406. import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.IfIndexesInterfaceMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput; @@ -98,24 +114,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.ser 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.itm.op.rev160406.ExternalTunnelList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelList; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInputBuilder; 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.netvirt.elan.config.rev150710.ElanConfig; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstanceBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface; @@ -144,10 +153,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegments; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey; @@ -171,16 +182,19 @@ public class ElanUtils { private static Map elanInstanceLocalCache = new ConcurrentHashMap<>(); private static Map elanInterfaceLocalCache = new ConcurrentHashMap<>(); + private static Map> elanInstancToDpnsCache = new ConcurrentHashMap<>(); + private static Map> elanInstanceToInterfacesCache = new ConcurrentHashMap<>(); private final DataBroker broker; private final IMdsalApiManager mdsalManager; private final ElanInstanceManager elanInstanceManager; private final OdlInterfaceRpcService interfaceManagerRpcService; private final ItmRpcService itmRpcService; - private final ElanL2GatewayUtils elanL2GatewayUtils; private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils; - private final L2GatewayConnectionUtils l2GatewayConnectionUtils; private final IInterfaceManager interfaceManager; + private final ElanConfig elanConfig; + private final ElanItmUtils elanItmUtils; + private final ElanEtreeUtils elanEtreeUtils; public static final FutureCallback DEFAULT_CALLBACK = new FutureCallback() { @Override @@ -197,38 +211,30 @@ public class ElanUtils { @Inject public ElanUtils(DataBroker dataBroker, IMdsalApiManager mdsalManager, ElanInstanceManager elanInstanceManager, OdlInterfaceRpcService interfaceManagerRpcService, ItmRpcService itmRpcService, - ElanInterfaceManager elanInterfaceManager, - EntityOwnershipService entityOwnershipService, IInterfaceManager interfaceManager) { + ElanConfig elanConfig, + IInterfaceManager interfaceManager, + ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils, ElanEtreeUtils elanEtreeUtils, + ElanItmUtils elanItmUtils) { this.broker = dataBroker; this.mdsalManager = mdsalManager; this.elanInstanceManager = elanInstanceManager; this.interfaceManagerRpcService = interfaceManagerRpcService; this.itmRpcService = itmRpcService; this.interfaceManager = interfaceManager; + this.elanConfig = elanConfig; - elanL2GatewayMulticastUtils = - new ElanL2GatewayMulticastUtils(broker, elanInstanceManager, elanInterfaceManager, this); - elanL2GatewayUtils = new ElanL2GatewayUtils(broker, itmRpcService, this, - entityOwnershipService, elanL2GatewayMulticastUtils); - elanL2GatewayMulticastUtils.setEElanL2GatewayUtils(elanL2GatewayUtils); - l2GatewayConnectionUtils = new L2GatewayConnectionUtils(broker, - elanInstanceManager, entityOwnershipService, this); - } - - public void close() { - elanL2GatewayUtils.close(); - } - - public ElanL2GatewayUtils getElanL2GatewayUtils() { - return elanL2GatewayUtils; + this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils; + this.elanEtreeUtils = elanEtreeUtils; + this.elanItmUtils = elanItmUtils; } public ElanL2GatewayMulticastUtils getElanL2GatewayMulticastUtils() { return elanL2GatewayMulticastUtils; } - public L2GatewayConnectionUtils getL2GatewayConnectionUtils() { - return l2GatewayConnectionUtils; + public final Boolean isOpenStackVniSemanticsEnforced() { + return elanConfig.isOpenstackVniSemanticsEnforced() != null + ? elanConfig.isOpenstackVniSemanticsEnforced() : false; } public static void addElanInstanceIntoCache(String elanInstanceName, ElanInstance elanInstance) { @@ -289,7 +295,7 @@ public class ElanUtils { public static void releaseId(IdManagerService idManager, String poolName, String idKey) { ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build(); - Future> result = idManager.releaseId(releaseIdInput); + idManager.releaseId(releaseIdInput); } /** @@ -300,10 +306,9 @@ public class ElanUtils { */ @Deprecated @SuppressWarnings("checkstyle:IllegalCatch") - public Optional read(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path) { - try (ReadOnlyTransaction tx = broker != null ? broker.newReadOnlyTransaction() - : this.broker.newReadOnlyTransaction()) { + public static Optional read(@Nonnull DataBroker broker, + LogicalDatastoreType datastoreType, InstanceIdentifier path) { + try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) { return tx.read(datastoreType, path).get(); } catch (Exception e) { throw new RuntimeException(e); @@ -322,14 +327,14 @@ public class ElanUtils { InstanceIdentifier path) { WriteTransaction tx = broker.newWriteOnlyTransaction(); tx.delete(datastoreType, path); - Futures.addCallback(tx.submit(), DEFAULT_CALLBACK); + Futures.addCallback(tx.submit(), DEFAULT_CALLBACK, MoreExecutors.directExecutor()); } public static void delete(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier path, FutureCallback callback) { WriteTransaction tx = broker.newWriteOnlyTransaction(); tx.delete(datastoreType, path); - Futures.addCallback(tx.submit(), callback); + Futures.addCallback(tx.submit(), callback, MoreExecutors.directExecutor()); } public static InstanceIdentifier getElanInstanceIdentifier() { @@ -342,15 +347,11 @@ public class ElanUtils { if (elanObj != null) { return elanObj; } - InstanceIdentifier elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName); + InstanceIdentifier elanIdentifierId = + ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName); return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId).orNull(); } - public static InstanceIdentifier getElanInstanceConfigurationDataPath(String elanInstanceName) { - return InstanceIdentifier.builder(ElanInstances.class) - .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build(); - } - // elan-interfaces Config Container public static ElanInterface getElanInterfaceByElanInterfaceName(DataBroker broker, String elanInterfaceName) { ElanInterface elanInterfaceObj = getElanInterfaceFromCache(elanInterfaceName); @@ -431,9 +432,14 @@ public class ElanUtils { // elan-interface-forwarding-entries Operational container public ElanInterfaceMac getElanInterfaceMacByInterfaceName(String interfaceName) { + return getElanInterfaceMacByInterfaceName(broker, interfaceName); + } + + @Nullable + public static ElanInterfaceMac getElanInterfaceMacByInterfaceName(DataBroker dataBroker, String interfaceName) { InstanceIdentifier elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath( interfaceName); - return read(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orNull(); + return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orNull(); } /** @@ -503,17 +509,6 @@ public class ElanUtils { return existingElanInfo.orNull(); } - public EtreeLeafTagName getEtreeLeafTagByElanTag(long elanTag) { - InstanceIdentifier elanId = getElanInfoEntriesOperationalDataPath(elanTag); - Optional existingElanInfo = read(broker, - LogicalDatastoreType.OPERATIONAL, elanId); - if (existingElanInfo.isPresent()) { - ElanTagName elanTagName = existingElanInfo.get(); - return elanTagName.getAugmentation(EtreeLeafTagName.class); - } - return null; - } - public static InstanceIdentifier getElanInfoEntriesOperationalDataPath(long elanTag) { return InstanceIdentifier.builder(ElanTagNameMap.class).child(ElanTagName.class, new ElanTagNameKey(elanTag)) .build(); @@ -615,8 +610,13 @@ public class ElanUtils { * @return the elan mac table */ public MacTable getElanMacTable(String elanName) { + return getElanMacTable(broker, elanName); + } + + @Nullable + public static MacTable getElanMacTable(DataBroker dataBroker, String elanName) { InstanceIdentifier elanMacTableId = getElanMacTableOperationalDataPath(elanName); - return read(broker, LogicalDatastoreType.OPERATIONAL, elanMacTableId).orNull(); + return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanMacTableId).orNull(); } public static long getElanLocalBCGId(long elanTag) { @@ -635,25 +635,13 @@ public class ElanUtils { return ElanConstants.ELAN_GID_MIN + etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2; } - public static BigInteger getElanMetadataLabel(long elanTag) { - return MetaDataUtil.getElanTagMetadata(elanTag); - } - public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet) { int shBit = isSHFlagSet ? 1 : 0; return BigInteger.valueOf(elanTag).shiftLeft(24).or(BigInteger.valueOf(shBit)); } - public static BigInteger getElanMetadataLabel(long elanTag, int lportTag) { - return getElanMetadataLabel(elanTag).or(MetaDataUtil.getLportTagMetaData(lportTag)); - } - - public static BigInteger getElanMetadataMask() { - return MetaDataUtil.METADATA_MASK_SERVICE.or(MetaDataUtil.METADATA_MASK_LPORT_TAG); - } - /** - * Setting INTERNAL_TUNNEL_TABLE, SMAC, DMAC, UDMAC in this DPN and optionally in other DPNs. + * Setting SMAC, DMAC, UDMAC in this DPN and optionally in other DPNs. * * @param elanInfo * the elan info @@ -680,12 +668,14 @@ public class ElanUtils { } } - public void setupDMacFlowonRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId, - String macAddress, WriteTransaction writeFlowTx) throws ElanException { - synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, dstDpId)) { - LOG.debug("Acquired lock for mac : " + macAddress + ". Proceeding with install operation."); - setupOrigDmacFlowsonRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, writeFlowTx); - } + public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId, + String macAddress, WriteTransaction writeFlowTx) throws ElanException { + String elanInstanceName = elanInfo.getElanInstanceName(); + setupRemoteDmacFlow(dstDpId, interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag(), elanInfo.getElanTag(), + macAddress, elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName(), elanInfo); + LOG.info("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and" + + " mac address {} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), + macAddress, dstDpId); } /** @@ -705,24 +695,28 @@ public class ElanUtils { int lportTag = interfaceInfo.getInterfaceTag(); // Matching metadata and eth_src fields List mkMatches = new ArrayList<>(); - mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanInfo.getElanTag(), lportTag), getElanMetadataMask())); + mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanInfo.getElanTag(), lportTag), + ElanHelper.getElanMetadataMask())); mkMatches.add(new MatchEthernetSource(new MacAddress(macAddress))); List mkInstructions = new ArrayList<>(); mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE)); - BigInteger dpId = interfaceInfo.getDpId(); long elanTag = getElanTag(broker, elanInfo, interfaceInfo); - FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_SMAC_TABLE, - getKnownDynamicmacFlowRef(NwConstants.ELAN_SMAC_TABLE, dpId, lportTag, macAddress, elanTag), 20, - elanInfo.getDescription(), (int) macTimeout, 0, - ElanConstants.COOKIE_ELAN_KNOWN_SMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); - flowEntity.setStrictFlag(true); - flowEntity.setSendFlowRemFlag(macTimeout != 0); // If Mac timeout is 0, - // the flow wont be - // deleted - // automatically, so no - // need to get notified - return flowEntity; + return new FlowEntityBuilder() + .setDpnId(dpId) + .setTableId(NwConstants.ELAN_SMAC_TABLE) + .setFlowId(getKnownDynamicmacFlowRef(NwConstants.ELAN_SMAC_TABLE, dpId, lportTag, macAddress, elanTag)) + .setPriority(20) + .setFlowName(elanInfo.getDescription()) + .setIdleTimeOut((int) macTimeout) + .setHardTimeOut(0) + .setCookie(ElanConstants.COOKIE_ELAN_KNOWN_SMAC.add(BigInteger.valueOf(elanTag))) + .setMatchInfoList(mkMatches) + .setInstructionInfoList(mkInstructions) + .setStrictFlag(true) + // If Mac timeout is 0, the flow won't be deleted automatically, so no need to get notified + .setSendFlowRemFlag(macTimeout != 0) + .build(); } private static Long getElanTag(DataBroker broker, ElanInstance elanInfo, InterfaceInfo interfaceInfo) { @@ -754,7 +748,7 @@ public class ElanUtils { * the writeFLowGroup tx */ public void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager, - WriteTransaction writeFlowGroupTx) { + WriteTransaction writeFlowGroupTx) { BigInteger dpId = interfaceInfo.getDpId(); int lportTag = interfaceInfo.getInterfaceTag(); Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, @@ -838,7 +832,7 @@ public class ElanUtils { .getEgressActionsForInterface(getEgressActionInput); RpcResult rpcResult = result.get(); if (!rpcResult.isSuccessful()) { - LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, + LOG.debug("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors()); } else { List actions = rpcResult.getResult().getAction(); @@ -886,48 +880,24 @@ public class ElanUtils { continue; } - // For remote DPNs a flow is needed to indicate that - // packets of this ELAN going to this MAC - // need to be forwarded through the appropiated ITM - // tunnel + // For remote DPNs a flow is needed to indicate that packets of this ELAN going to this MAC need to be + // forwarded through the appropriate ITM tunnel setupRemoteDmacFlow(elanDpn.getDpId(), // srcDpn (the remote DPN in this case) dpId, // dstDpn (the local DPN) interfaceInfo.getInterfaceTag(), // lportTag of the local interface - elanTag, // identifier of the Elan + elanTag, // identifier of the Elan macAddress, // MAC to be programmed in remote DPN - elanInstanceName, writeFlowGroupTx, ifName, elanInfo); - LOG.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on" + elanInstanceName, writeFlowGroupTx, ifName, elanInfo + ); + LOG.debug("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on" + " dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, elanDpn.getDpId()); } // TODO: Make sure that the same is performed against the ElanDevices. } - private void setupOrigDmacFlowsonRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, - BigInteger dstDpId, String macAddress, WriteTransaction writeFlowTx) throws ElanException { - BigInteger dpId = interfaceInfo.getDpId(); - String elanInstanceName = elanInfo.getElanInstanceName(); - List remoteFEs = getInvolvedDpnsInElan(elanInstanceName); - for (DpnInterfaces remoteFE : remoteFEs) { - Long elanTag = elanInfo.getElanTag(); - if (remoteFE.getDpId().equals(dstDpId)) { - // Check for the Remote DPN present in Inventory Manager - setupRemoteDmacFlow(dstDpId, dpId, interfaceInfo.getInterfaceTag(), elanTag, macAddress, - elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName(), elanInfo); - LOG.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address {} on dpn:{}", - elanInstanceName, interfaceInfo.getPortName(), macAddress, remoteFE.getDpId()); - break; - } - } - } - - @SuppressWarnings("unchecked") public List getInvolvedDpnsInElan(String elanName) { - List dpns = elanInstanceManager.getElanDPNByName(elanName); - if (dpns == null) { - return Collections.emptyList(); - } - return dpns; + return elanInstanceManager.getElanDPNByName(elanName); } private void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress, @@ -943,7 +913,7 @@ public class ElanUtils { EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, ifName); if (etreeInterface != null) { if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) { - EtreeLeafTagName etreeTagName = getEtreeLeafTagByElanTag(elanTag); + EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); if (etreeTagName == null) { LOG.warn("Interface {} seems like it belongs to Etree but etreeTagName from elanTag {} is null", ifName, elanTag); @@ -972,7 +942,7 @@ public class ElanUtils { return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(macAddress).toString(); } - private static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId, + public static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId, String dstMacAddress, long elanTag, boolean shFlag) { return new StringBuffer().append(elanDmacTable).append(elanTag).append(dpId).append(extDeviceNodeId) .append(dstMacAddress).append(shFlag).toString(); @@ -1004,7 +974,7 @@ public class ElanUtils { ElanInstance elanInfo, long ifTag) { List mkMatches = new ArrayList<>(); - mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); + mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress))); List mkInstructions = new ArrayList<>(); @@ -1018,35 +988,40 @@ public class ElanUtils { return flow; } - public void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, - String macAddress, String displayName, WriteTransaction writeFlowGroupTx, String interfaceName, - ElanInstance elanInstance) throws ElanException { + public void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, String + macAddress, String displayName, WriteTransaction writeFlowGroupTx, String interfaceName, ElanInstance + elanInstance) throws ElanException { if (interfaceManager.isExternalInterface(interfaceName)) { LOG.debug("Ignoring install remote DMAC {} flow on provider interface {} elan {}", macAddress, interfaceName, elanInstance.getElanInstanceName()); return; } - - Flow flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTag, elanTag, macAddress, displayName, + Flow flowEntity; + // if openstack-vni-semantics are enforced, segmentation ID is passed as network VNI for VxLAN based provider + // networks, 0 otherwise + long lportTagOrVni = !isOpenStackVniSemanticsEnforced() ? lportTag : isVxlan(elanInstance) + ? elanInstance.getSegmentationId() : 0; + flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, elanInstance); mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx); - setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTag, elanTag, macAddress, displayName, interfaceName, + setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, interfaceName, writeFlowGroupTx, elanInstance); } - private void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, - String macAddress, String displayName, String interfaceName, - WriteTransaction writeFlowGroupTx, ElanInstance elanInstance) throws ElanException { + private void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag, + String macAddress, String displayName, String interfaceName, + WriteTransaction writeFlowGroupTx, ElanInstance elanInstance) + throws ElanException { Flow flowEntity; EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceName); if (etreeInterface != null) { if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) { - EtreeLeafTagName etreeTagName = getEtreeLeafTagByElanTag(elanTag); + EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); if (etreeTagName == null) { LOG.warn("Interface " + interfaceName + " seems like it belongs to Etree but etreeTagName from elanTag " + elanTag + " is null."); } else { - flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTag, + flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, etreeTagName.getEtreeLeafTag().getValue(), macAddress, displayName, elanInstance); mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx); } @@ -1057,15 +1032,15 @@ public class ElanUtils { /** * Builds a Flow to be programmed in a remote DPN's DMAC table. This flow * consists in: Match: + elanTag in packet's metadata + packet going to a - * MAC known to be located in another DPN Actions: + set_tunnel_id(lportTag) + * MAC known to be located in another DPN Actions: + set_tunnel_id * + output ITM internal tunnel interface with the other DPN * * @param srcDpId * the src Dpn Id * @param destDpId * dest Dp Id - * @param lportTag - * lport Tag + * @param lportTagOrVni + * lportTag or network VNI * @param elanTag * elan Tag * @param macAddress @@ -1076,10 +1051,10 @@ public class ElanUtils { * @throws ElanException in case of issues creating the flow objects */ @SuppressWarnings("checkstyle:IllegalCatch") - public Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, + public Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag, String macAddress, String displayName, ElanInstance elanInstance) throws ElanException { List mkMatches = new ArrayList<>(); - mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); + mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress))); List mkInstructions = new ArrayList<>(); @@ -1090,17 +1065,17 @@ public class ElanUtils { if (isVlan(elanInstance) || isFlat(elanInstance)) { String interfaceName = getExternalElanInterface(elanInstance.getElanInstanceName(), srcDpId); if (null == interfaceName) { - LOG.error("buildRemoteDmacFlowEntry: Could not find interfaceName for {} {}", srcDpId, - elanInstance); + LOG.info("buildRemoteDmacFlowEntry: Could not find interfaceName for {} {}", srcDpId, + elanInstance); } actions = getEgressActionsForInterface(interfaceName, null); - } else { - actions = getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTag); + } else if (isVxlan(elanInstance)) { + actions = elanItmUtils.getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTagOrVni); } mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); } catch (Exception e) { LOG.error("Could not get egress actions to add to flow for srcDpId=" + srcDpId + ", destDpId=" + destDpId - + ", lportTag=" + lportTag, e); + + ", lportTag/VNI=" + lportTagOrVni, e); } Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, @@ -1149,7 +1124,7 @@ public class ElanUtils { private void executeEtreeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId, WriteTransaction deleteFlowGroupTx) { - EtreeLeafTagName etreeLeafTag = getEtreeLeafTagByElanTag(elanTag); + EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); if (etreeLeafTag != null) { executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId, etreeLeafTag.getEtreeLeafTag().getValue(), dstDpId, deleteFlowGroupTx); @@ -1223,18 +1198,19 @@ public class ElanUtils { // Add the ElanState in the elan-state operational data-store tx.put(LogicalDatastoreType.OPERATIONAL, getElanInstanceOperationalDataPath(elanInstanceName), - elanInfo, true); + elanInfo, WriteTransaction.CREATE_MISSING_PARENTS); // Add the ElanMacTable in the elan-mac-table operational data-store MacTable elanMacTable = new MacTableBuilder().setKey(new MacTableKey(elanInstanceName)).build(); tx.put(LogicalDatastoreType.OPERATIONAL, getElanMacTableOperationalDataPath(elanInstanceName), - elanMacTable, true); + elanMacTable, WriteTransaction.CREATE_MISSING_PARENTS); ElanTagNameBuilder elanTagNameBuilder = new ElanTagNameBuilder().setElanTag(elanTag) .setKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName); long etreeLeafTag = -1; if (isEtreeInstance(elanInstanceAdded)) { - etreeLeafTag = retrieveNewElanTag(idManager, elanInstanceName + ElanConstants.LEAVES_POSTFIX); + etreeLeafTag = retrieveNewElanTag(idManager,elanInstanceName + ElanConstants + .LEAVES_POSTFIX); EtreeLeafTagName etreeLeafTagName = new EtreeLeafTagNameBuilder() .setEtreeLeafTag(new EtreeLeafTag(etreeLeafTag)).build(); elanTagNameBuilder.addAugmentation(EtreeLeafTagName.class, etreeLeafTagName); @@ -1260,7 +1236,7 @@ public class ElanUtils { elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance); } ElanInstance elanInstanceWithTag = elanInstanceBuilder.build(); - tx.merge(LogicalDatastoreType.CONFIGURATION, getElanInstanceConfigurationDataPath(elanInstanceName), + tx.merge(LogicalDatastoreType.CONFIGURATION, ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstanceWithTag, true); } @@ -1285,32 +1261,9 @@ public class ElanUtils { return read(broker, LogicalDatastoreType.CONFIGURATION, node).isPresent(); } - public static ServicesInfo getServiceInfo(String elanInstanceName, long elanTag, String interfaceName) { - int priority = ElanConstants.ELAN_SERVICE_PRIORITY; - int instructionKey = 0; - List instructions = new ArrayList<>(); - instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(getElanMetadataLabel(elanTag), - MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey)); - instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_SMAC_TABLE, ++instructionKey)); - - short serviceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX); - ServicesInfo serviceInfo = InterfaceServiceUtil.buildServiceInfo( - String.format("%s.%s", elanInstanceName, interfaceName), serviceIndex, priority, - NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions); - return serviceInfo; - } - - public static void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path, T data) { - WriteTransaction tx = broker.newWriteOnlyTransaction(); - tx.put(datastoreType, path, data, true); - CheckedFuture futures = tx.submit(); - try { - futures.get(); - } catch (InterruptedException | ExecutionException e) { - LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data); - throw new RuntimeException(e.getMessage()); - } + public static ServicesInfo getServiceInfo(String elanInstanceName, String interfaceName) { + return InterfaceServiceUtil.buildServiceInfo(elanInstanceName + "." + interfaceName, + ElanConstants.ELAN_SERVICE_PRIORITY); } public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority, @@ -1322,156 +1275,12 @@ public class ElanUtils { .addAugmentation(StypeOpenflow.class, augBuilder.build()).build(); } - public static InstanceIdentifier buildServiceId(String vpnInterfaceName, short serviceIndex) { + public static InstanceIdentifier buildServiceId(String interfaceName, short serviceIndex) { return InstanceIdentifier.builder(ServiceBindings.class) - .child(ServicesInfo.class, new ServicesInfoKey(vpnInterfaceName, ServiceModeIngress.class)) + .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class)) .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build(); } - /** - * Builds the list of actions to be taken when sending the packet over a - * VxLan Tunnel Interface, such as setting the tunnel_id field, the vlanId - * if proceeds and output the packet over the right port. - * - * @param tunnelIfaceName - * the tunnel iface name - * @param tunnelKey - * the tunnel key - * @return the list - */ - public List buildTunnelItmEgressActions(String tunnelIfaceName, Long tunnelKey) { - if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) { - return buildItmEgressActions(tunnelIfaceName, tunnelKey); - } - - return Collections.emptyList(); - } - - /** - * Builds the list of actions to be taken when sending the packet over - * external port such as tunnel, physical port etc. - * - * @param interfaceName - * the interface name - * @param tunnelKey - * can be VNI for VxLAN tunnel interfaces, Gre Key for GRE - * tunnels, etc. - * @return the list - */ - @SuppressWarnings("checkstyle:IllegalCatch") - public List buildItmEgressActions(String interfaceName, Long tunnelKey) { - List result = Collections.emptyList(); - try { - GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder() - .setIntfName(interfaceName).setTunnelKey(tunnelKey).build(); - - Future> egressActionsOutputFuture = interfaceManagerRpcService - .getEgressActionsForInterface(getEgressActInput); - if (egressActionsOutputFuture.get().isSuccessful()) { - GetEgressActionsForInterfaceOutput egressActionsOutput = egressActionsOutputFuture.get().getResult(); - result = egressActionsOutput.getAction(); - } - } catch (Exception e) { - LOG.error("Error in RPC call getEgressActionsForInterface {}", e); - } - - if (result == null || result.size() == 0) { - LOG.warn("Could not build Egress actions for interface {} and tunnelId {}", interfaceName, tunnelKey); - } - return result; - } - - /** - * Builds the list of actions to be taken when sending the packet over an - * external VxLan tunnel interface, such as stamping the VNI on the VxLAN - * header, setting the vlanId if it proceeds and output the packet over the - * right port. - * - * @param srcDpnId - * Dpn where the tunnelInterface is located - * @param torNode - * NodeId of the ExternalDevice where the packet must be sent to. - * @param vni - * Vni to be stamped on the VxLAN Header. - * @return the external itm egress action - */ - public List getExternalTunnelItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni) { - List result = Collections.emptyList(); - - GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder() - .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()) - .setTunnelType(TunnelTypeVxlan.class).build(); - Future> output = itmRpcService - .getExternalTunnelInterfaceName(input); - try { - if (output.get().isSuccessful()) { - GetExternalTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult(); - String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName(); - LOG.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName); - - result = buildTunnelItmEgressActions(tunnelIfaceName, vni); - } - - } catch (InterruptedException | ExecutionException e) { - LOG.error("Error in RPC call getTunnelInterfaceName {}", e); - } - - return result; - } - - /** - * Builds the list of actions to be taken when sending the packet over an - * internal VxLan tunnel interface, such as setting the serviceTag on the - * VNI field of the VxLAN header, setting the vlanId if it proceeds and - * output the packet over the right port. - * - * @param sourceDpnId - * Dpn where the tunnelInterface is located - * @param destinationDpnId - * Dpn where the packet must be sent to. It is used here in order - * to select the right tunnel interface. - * @param serviceTag - * serviceId to be sent on the VxLAN header. - * @return the internal itm egress action - */ - public List getInternalTunnelItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId, - long serviceTag) { - List result = Collections.emptyList(); - - LOG.debug("In getInternalItmEgressAction Action source {}, destination {}, elanTag {}", sourceDpnId, - destinationDpnId, serviceTag); - Class tunType = TunnelTypeVxlan.class; - GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder() - .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build(); - Future> output = itmRpcService - .getTunnelInterfaceName(input); - try { - if (output.get().isSuccessful()) { - GetTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult(); - String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName(); - LOG.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName); - - result = buildTunnelItmEgressActions(tunnelIfaceName, serviceTag); - } - } catch (InterruptedException | ExecutionException e) { - LOG.error("Error in RPC call getTunnelInterfaceName {}", e); - } - - return result; - } - - /** - * Build the list of actions to be taken when sending the packet to external - * (physical) port. - * - * @param interfaceName - * Interface name - * @return the external port itm egress actions - */ - public List getExternalPortItmEgressAction(String interfaceName) { - return buildItmEgressActions(interfaceName, null); - } - public static List getTunnelMatchesForServiceId(int elanTag) { List mkMatches = new ArrayList<>(); // Matching metadata @@ -1483,35 +1292,22 @@ public class ElanUtils { public void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) { RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder() .setDpnId(destDpId).setServiceId(serviceId).build(); - Future> futureObject = itmRpcService - .removeTerminatingServiceActions(input); + Future> futureObject = itmRpcService.removeTerminatingServiceActions(input); try { RpcResult result = futureObject.get(); if (result.isSuccessful()) { - LOG.debug("Successfully completed removeTerminatingServiceActions"); + LOG.debug("Successfully completed removeTerminatingServiceActions for ELAN with serviceId {} on " + + "dpn {}", serviceId, destDpId); } else { - LOG.debug("Failure in removeTerminatingServiceAction RPC call"); + LOG.debug("Failure in removeTerminatingServiceAction RPC call for ELAN with serviceId {} on " + + "dpn {}", serviceId, destDpId); } } catch (InterruptedException | ExecutionException e) { - LOG.error("Error in RPC call removeTerminatingServiceActions {}", e); + LOG.error("Error in RPC call removeTerminatingServiceActions for ELAN with serviceId {} on " + + "dpn {}: {}", serviceId, destDpId, e); } } - public void createTerminatingServiceActions(BigInteger destDpId, int serviceId, List actions) { - List mkInstructions = new ArrayList<>(); - mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); - CreateTerminatingServiceActionsInput input = new CreateTerminatingServiceActionsInputBuilder() - .setDpnId(destDpId).setServiceId(serviceId).setInstruction(mkInstructions).build(); - - itmRpcService.createTerminatingServiceActions(input); - } - - public static TunnelList buildInternalTunnel(DataBroker broker) { - InstanceIdentifier tunnelListInstanceIdentifier = InstanceIdentifier.builder(TunnelList.class) - .build(); - return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, tunnelListInstanceIdentifier).orNull(); - } - /** * Gets the external tunnel. * @@ -1561,369 +1357,18 @@ public class ElanUtils { */ public List getAllExternalTunnels(LogicalDatastoreType datastoreType) { InstanceIdentifier iid = InstanceIdentifier.builder(ExternalTunnelList.class).build(); - return read(broker, datastoreType, iid).transform(ExternalTunnelList::getExternalTunnel).or( + return read(broker, datastoreType, iid).toJavaUtil().map(ExternalTunnelList::getExternalTunnel).orElse( Collections.emptyList()); } - /** - * Installs a Flow in a DPN's DMAC table. The Flow is for a MAC that is - * connected remotely in another CSS and accessible through an internal - * tunnel. It also installs the flow for dropping the packet if it came over - * an ITM tunnel (that is, if the Split-Horizon flag is set) - * - * @param localDpId - * Id of the DPN where the MAC Addr is accessible locally - * @param remoteDpId - * Id of the DPN where the flow must be installed - * @param lportTag - * lportTag of the interface where the mac is connected to. - * @param elanTag - * Identifier of the ELAN - * @param macAddress - * MAC to be installed in remoteDpId's DMAC table - * @param displayName - * the display name - * @throws ElanException in case of issues creating the flow objects - */ - public void installDmacFlowsToInternalRemoteMac(BigInteger localDpId, BigInteger remoteDpId, int lportTag, - long elanTag, String macAddress, String displayName) throws ElanException { - Flow flow = buildDmacFlowForInternalRemoteMac(localDpId, remoteDpId, lportTag, elanTag, macAddress, - displayName); - mdsalManager.installFlow(remoteDpId, flow); - } - - /** - * Installs a Flow in the specified DPN's DMAC table. The flow is for a MAC - * that is connected remotely in an External Device (TOR) and that is - * accessible through an external tunnel. It also installs the flow for - * dropping the packet if it came over an ITM tunnel (that is, if the - * Split-Horizon flag is set) - * - * @param dpnId - * Id of the DPN where the flow must be installed - * @param extDeviceNodeId - * the ext device node id - * @param elanTag - * the elan tag - * @param vni - * the vni - * @param macAddress - * the mac address - * @param displayName - * the display name - * @param interfaceName - * the interface name - * - * @return the dmac flows - * @throws ElanException in case of issues creating the flow objects - */ - public List> installDmacFlowsToExternalRemoteMac(BigInteger dpnId, - String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName, - String interfaceName) throws ElanException { - List> futures = new ArrayList<>(); - synchronized (getElanMacDPNKey(elanTag, macAddress, dpnId)) { - Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress, - displayName); - futures.add(mdsalManager.installFlow(dpnId, flow)); - - Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress); - futures.add(mdsalManager.installFlow(dpnId, dropFlow)); - installEtreeDmacFlowsToExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName, - interfaceName, futures); - } - return futures; - } - - private void installEtreeDmacFlowsToExternalRemoteMac(BigInteger dpnId, String extDeviceNodeId, Long elanTag, - Long vni, String macAddress, String displayName, String interfaceName, - List> futures) throws ElanException { - EtreeLeafTagName etreeLeafTag = getEtreeLeafTagByElanTag(elanTag); - if (etreeLeafTag != null) { - buildEtreeDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress, futures, - etreeLeafTag); - buildEtreeDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, vni, macAddress, displayName, interfaceName, - futures, etreeLeafTag); - } - } - - private void buildEtreeDmacFlowForExternalRemoteMac(BigInteger dpnId, String extDeviceNodeId, Long vni, - String macAddress, String displayName, String interfaceName, List> futures, - EtreeLeafTagName etreeLeafTag) throws ElanException { - boolean isRoot = false; - if (interfaceName == null) { - isRoot = true; - } else { - EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceName); - if (etreeInterface != null) { - if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) { - isRoot = true; - } - } - } - if (isRoot) { - Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, - etreeLeafTag.getEtreeLeafTag().getValue(), vni, macAddress, displayName); - futures.add(mdsalManager.installFlow(dpnId, flow)); - } - } - - private void buildEtreeDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId, - Long elanTag, String macAddress, List> futures, EtreeLeafTagName etreeLeafTag) { - if (etreeLeafTag != null) { - Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, - etreeLeafTag.getEtreeLeafTag().getValue(), macAddress); - futures.add(mdsalManager.installFlow(dpnId, dropFlow)); - } - } - public static List buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) { List mkMatches = new ArrayList<>(); mkMatches.add( new MatchMetadata(getElanMetadataLabel(elanTag, shFlag), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG)); mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddr))); - return mkMatches; } - /** - * Builds a Flow to be programmed in a DPN's DMAC table. This method must be - * used when the MAC is located in an External Device (TOR). The flow - * matches on the specified MAC and 1) sends the packet over the CSS-TOR - * tunnel if SHFlag is not set, or 2) drops it if SHFlag is set (what means - * the packet came from an external tunnel) - * - * @param dpId - * DPN whose DMAC table is going to be modified - * @param extDeviceNodeId - * Hwvtep node where the mac is attached to - * @param elanTag - * ElanId to which the MAC is being added to - * @param vni - * the vni - * @param dstMacAddress - * The mac address to be programmed - * @param displayName - * the display name - * @return the flow - * @throws ElanException in case of issues creating the flow objects - */ - @SuppressWarnings("checkstyle:IllegalCatch") - public Flow buildDmacFlowForExternalRemoteMac(BigInteger dpId, String extDeviceNodeId, long elanTag, - Long vni, String dstMacAddress, String displayName) throws ElanException { - List mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ false, dstMacAddress); - List mkInstructions = new ArrayList<>(); - try { - List actions = getExternalTunnelItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni); - mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); - } catch (Exception e) { - LOG.error("Could not get Egress Actions for DpId=" + dpId + ", externalNode=" + extDeviceNodeId, e); - } - - Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, - getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, dstMacAddress, elanTag, - false), - 20, /* prio */ - displayName, 0, /* idleTimeout */ - 0, /* hardTimeout */ - ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); - - return flow; - } - - /** - * Builds the flow that drops the packet if it came through an external - * tunnel, that is, if the Split-Horizon flag is set. - * - * @param dpnId - * DPN whose DMAC table is going to be modified - * @param extDeviceNodeId - * Hwvtep node where the mac is attached to - * @param elanTag - * ElanId to which the MAC is being added to - * @param dstMacAddress - * The mac address to be programmed - */ - private static Flow buildDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId, - Long elanTag, String dstMacAddress) { - List mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ true, dstMacAddress); - List mkInstructions = MDSALUtil.buildInstructionsDrop(); - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpnId, extDeviceNodeId, dstMacAddress, - elanTag, true); - Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, flowId, 20, /* prio */ - "Drop", 0, /* idleTimeout */ - 0, /* hardTimeout */ - ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); - - return flow; - } - - private static String getDmacDropFlowId(Long elanTag, String dstMacAddress) { - return new StringBuilder(NwConstants.ELAN_DMAC_TABLE).append(elanTag).append(dstMacAddress).append("Drop") - .toString(); - } - - /** - * Builds a Flow to be programmed in a remote DPN's DMAC table. This method - * must be used when the MAC is located in another CSS. - * - *

This flow consists in: Match: + elanTag in packet's metadata + packet - * going to a MAC known to be located in another DPN Actions: + - * set_tunnel_id(lportTag) + output on ITM internal tunnel interface with - * the other DPN - * - * @param localDpId - * the local dp id - * @param remoteDpId - * the remote dp id - * @param lportTag - * the lport tag - * @param elanTag - * the elan tag - * @param macAddress - * the mac address - * @param displayName - * the display name - * @return the flow - * @throws ElanException in case of issues creating the flow objects - */ - @SuppressWarnings("checkstyle:IllegalCatch") - public Flow buildDmacFlowForInternalRemoteMac(BigInteger localDpId, BigInteger remoteDpId, int lportTag, - long elanTag, String macAddress, String displayName) throws ElanException { - List mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ false, macAddress); - - List mkInstructions = new ArrayList<>(); - - try { - // List of Action for the provided Source and Destination DPIDs - List actions = getInternalTunnelItmEgressAction(localDpId, remoteDpId, lportTag); - mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); - } catch (Exception e) { - LOG.error("Could not get Egress Actions for localDpId=" + localDpId + ", remoteDpId=" - + remoteDpId + ", lportTag=" + lportTag, e); - } - - Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, - getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, localDpId, remoteDpId, macAddress, elanTag), - 20, /* prio */ - displayName, 0, /* idleTimeout */ - 0, /* hardTimeout */ - ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); - - return flow; - - } - - /** - * Installs or removes flows in DMAC table for MACs that are/were located in - * an external Elan Device. - * - * @param dpId - * Id of the DPN where the DMAC table is going to be modified - * @param extNodeId - * Id of the External Device where the MAC is located - * @param elanTag - * Id of the ELAN - * @param vni - * VNI of the LogicalSwitch to which the MAC belongs to, and that - * is associated with the ELAN - * @param macAddress - * the mac address - * @param elanInstanceName - * the elan instance name - * @param addOrRemove - * Indicates if flows must be installed or removed. - * @param interfaceName - * the interface name - * @throws ElanException in case of issues creating the flow objects - * @see org.opendaylight.genius.mdsalutil.MDSALUtil.MdsalOp - */ - public void setupDmacFlowsToExternalRemoteMac(BigInteger dpId, String extNodeId, Long elanTag, Long vni, - String macAddress, String elanInstanceName, MdsalOp addOrRemove, String interfaceName) - throws ElanException { - if (addOrRemove == MdsalOp.CREATION_OP) { - installDmacFlowsToExternalRemoteMac(dpId, extNodeId, elanTag, vni, macAddress, elanInstanceName, - interfaceName); - } else if (addOrRemove == MdsalOp.REMOVAL_OP) { - deleteDmacFlowsToExternalMac(elanTag, dpId, extNodeId, macAddress); - } - } - - /** - * Delete dmac flows to external mac. - * - * @param elanTag - * the elan tag - * @param dpId - * the dp id - * @param extDeviceNodeId - * the ext device node id - * @param macToRemove - * the mac to remove - * @return dmac flow - */ - public List> deleteDmacFlowsToExternalMac(long elanTag, BigInteger dpId, - String extDeviceNodeId, String macToRemove) { - List> futures = new ArrayList<>(); - synchronized (getElanMacDPNKey(elanTag, macToRemove, dpId)) { - // Removing the flows that sends the packet on an external tunnel - removeFlowThatSendsThePacketOnAnExternalTunnel(elanTag, dpId, extDeviceNodeId, macToRemove, futures); - - // And now removing the drop flow - removeTheDropFlow(elanTag, dpId, extDeviceNodeId, macToRemove, futures); - - deleteEtreeDmacFlowsToExternalMac(elanTag, dpId, extDeviceNodeId, macToRemove, futures); - } - return futures; - } - - private void deleteEtreeDmacFlowsToExternalMac(long elanTag, BigInteger dpId, String extDeviceNodeId, - String macToRemove, List> futures) { - EtreeLeafTagName etreeLeafTag = getEtreeLeafTagByElanTag(elanTag); - if (etreeLeafTag != null) { - removeFlowThatSendsThePacketOnAnExternalTunnel(etreeLeafTag.getEtreeLeafTag().getValue(), dpId, - extDeviceNodeId, macToRemove, futures); - removeTheDropFlow(etreeLeafTag.getEtreeLeafTag().getValue(), dpId, extDeviceNodeId, macToRemove, futures); - } - } - - private void removeTheDropFlow(long elanTag, BigInteger dpId, String extDeviceNodeId, String macToRemove, - List> futures) { - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove, - elanTag, true); - Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build(); - futures.add(mdsalManager.removeFlow(dpId, flowToRemove)); - } - - private void removeFlowThatSendsThePacketOnAnExternalTunnel(long elanTag, BigInteger dpId, - String extDeviceNodeId, String macToRemove, List> futures) { - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove, - elanTag, false); - Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build(); - futures.add(mdsalManager.removeFlow(dpId, flowToRemove)); - } - - /** - * Gets the dpid from interface. - * - * @param interfaceName - * the interface name - * @return the dpid from interface - */ - public BigInteger getDpidFromInterface(String interfaceName) { - BigInteger dpId = null; - Future> output = interfaceManagerRpcService - .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build()); - try { - RpcResult rpcResult = output.get(); - if (rpcResult.isSuccessful()) { - dpId = rpcResult.getResult().getDpid(); - } - } catch (NullPointerException | InterruptedException | ExecutionException e) { - LOG.error("Failed to get the DPN ID: {} for interface {}: {} ", dpId, interfaceName, e); - } - return dpId; - } - /** * Checks if is interface operational. * @@ -1994,25 +1439,25 @@ public class ElanUtils { return futures; } + public static boolean isVxlanNetwork(DataBroker broker, String elanInstanceName) { + ElanInstance elanInstance = getElanInstanceByName(broker, elanInstanceName); + return elanInstance != null && isVxlan(elanInstance); + } + public static boolean isVxlan(ElanInstance elanInstance) { return elanInstance != null && elanInstance.getSegmentType() != null && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class) && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0; } - public static boolean isVxlanNetwork(DataBroker broker, String elanInstanceName) { - ElanInstance elanInstance = getElanInstanceByName(broker, elanInstanceName); - return (elanInstance != null && isVxlan(elanInstance)); - } - - public static boolean isVxlanSegment(ElanInstance elanInstance) { + private static boolean isVxlanSegment(ElanInstance elanInstance) { if (elanInstance != null) { List elanSegments = elanInstance.getElanSegments(); if (elanSegments != null) { for (ElanSegments segment : elanSegments) { - if (segment != null && (segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class) + if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class) && segment.getSegmentationId() != null - && segment.getSegmentationId().longValue() != 0)) { + && segment.getSegmentationId().longValue() != 0) { return true; } } @@ -2021,6 +1466,10 @@ public class ElanUtils { return false; } + public static boolean isVxlanNetworkOrVxlanSegment(ElanInstance elanInstance) { + return isVxlan(elanInstance) || isVxlanSegment(elanInstance); + } + public static Long getVxlanSegmentationId(ElanInstance elanInstance) { Long segmentationId = 0L; @@ -2051,30 +1500,27 @@ public class ElanUtils { && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeFlat.class); } - public static boolean isEtreeRootInterfaceByInterfaceName(DataBroker broker, String interfaceName) { - EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceName); - return etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root; + public void addDmacRedirectToDispatcherFlows(Long elanTag, String displayName, + String macAddress, List dpnIds) { + for (BigInteger dpId : dpnIds) { + WriteTransaction writeTx = broker.newWriteOnlyTransaction(); + mdsalManager.addFlowToTx(buildDmacRedirectToDispatcherFlow(dpId, macAddress, displayName, elanTag), + writeTx); + writeTx.submit(); + } } - public void handleDmacRedirectToDispatcherFlows(Long elanTag, String displayName, - String macAddress, int addOrRemove, List dpnIds) { + public void removeDmacRedirectToDispatcherFlows(Long elanTag, String macAddress, List dpnIds) { for (BigInteger dpId : dpnIds) { - if (addOrRemove == NwConstants.ADD_FLOW) { - WriteTransaction writeTx = broker.newWriteOnlyTransaction(); - mdsalManager.addFlowToTx(buildDmacRedirectToDispatcherFlow(dpId, macAddress, displayName, elanTag), - writeTx); - writeTx.submit(); - } else { - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, macAddress, elanTag); - mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, flowId)); - } + String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, macAddress, elanTag); + mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, flowId)); } } public static FlowEntity buildDmacRedirectToDispatcherFlow(BigInteger dpId, String dstMacAddress, String displayName, long elanTag) { List matches = new ArrayList<>(); - matches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); + matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); matches.add(new MatchEthernetDestination(new MacAddress(dstMacAddress))); List instructions = new ArrayList<>(); List actions = new ArrayList<>(); @@ -2088,25 +1534,12 @@ public class ElanUtils { return flow; } - public static FlowEntity buildDmacRedirectToDispatcherFlowMacNoActions(BigInteger dpId, String dstMacAddress, - String displayName, long elanTag) { - List matches = new ArrayList<>(); - matches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); - matches.add(new MatchEthernetDestination(new MacAddress(dstMacAddress))); - - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, dstMacAddress, elanTag); - FlowEntity flow = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_DMAC_TABLE, flowId, 20, displayName, 0, 0, - ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), - matches, new ArrayList<>()); - return flow; - } - /** * Add Mac Address to ElanInterfaceForwardingEntries and ElanForwardingTables * Install SMAC and DMAC flows. */ public void addMacEntryToDsAndSetupFlows(IInterfaceManager interfaceManager, String interfaceName, - String macAddress, String elanName, WriteTransaction tx, WriteTransaction flowWritetx, int macTimeOut) + String macAddress, String elanName, WriteTransaction interfaceTx, WriteTransaction flowTx, int macTimeOut) throws ElanException { LOG.trace("Adding mac address {} and interface name {} to ElanInterfaceForwardingEntries and " + "ElanForwardingTables DS", macAddress, interfaceName); @@ -2117,12 +1550,12 @@ public class ElanUtils { .setIsStaticAddress(false).build(); InstanceIdentifier macEntryId = ElanUtils .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress); - tx.put(LogicalDatastoreType.OPERATIONAL, macEntryId, macEntry); + interfaceTx.put(LogicalDatastoreType.OPERATIONAL, macEntryId, macEntry); InstanceIdentifier elanMacEntryId = ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress); - tx.put(LogicalDatastoreType.OPERATIONAL, elanMacEntryId, macEntry); + interfaceTx.put(LogicalDatastoreType.OPERATIONAL, elanMacEntryId, macEntry); ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanName); setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), macTimeOut, macAddress, true, - flowWritetx); + flowTx); } /** @@ -2130,18 +1563,18 @@ public class ElanUtils { * Remove SMAC and DMAC flows. */ public void deleteMacEntryFromDsAndRemoveFlows(IInterfaceManager interfaceManager, String interfaceName, - String macAddress, String elanName, WriteTransaction tx, WriteTransaction deleteFlowTx) { + String macAddress, String elanName, WriteTransaction interfaceTx, WriteTransaction flowTx) { LOG.trace("Deleting mac address {} and interface name {} from ElanInterfaceForwardingEntries " + "and ElanForwardingTables DS", macAddress, interfaceName); PhysAddress physAddress = new PhysAddress(macAddress); MacEntry macEntry = getInterfaceMacEntriesOperationalDataPath(interfaceName, physAddress); InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName); if (macEntry != null && interfaceInfo != null) { - deleteMacFlows(ElanUtils.getElanInstanceByName(broker, elanName), interfaceInfo, macEntry, deleteFlowTx); + deleteMacFlows(ElanUtils.getElanInstanceByName(broker, elanName), interfaceInfo, macEntry, flowTx); } - tx.delete(LogicalDatastoreType.OPERATIONAL, + interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress)); - tx.delete(LogicalDatastoreType.OPERATIONAL, + interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress)); } @@ -2163,10 +1596,211 @@ public class ElanUtils { } public static String getElanMacDPNKey(long elanTag, String macAddress, BigInteger dpnId) { - return ("MAC-" + macAddress + " ELAN_TAG-" + elanTag + "DPN_ID-" + dpnId).intern(); + String elanMacDmacDpnKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag + "DPN_ID-" + dpnId; + return elanMacDmacDpnKey.intern(); } public static String getElanMacKey(long elanTag, String macAddress) { - return ("MAC-" + macAddress + " ELAN_TAG-" + elanTag).intern(); + String elanMacKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag; + return elanMacKey.intern(); + } + + // TODO This should return a collection of futures + public static void addToListenableFutureIfTxException(RuntimeException exception, + List> futures) { + Throwable cause = exception.getCause(); + if (cause != null && cause instanceof TransactionCommitFailedException) { + futures.add(Futures.immediateFailedCheckedFuture((TransactionCommitFailedException) cause)); + } + } + + public static List getPhysAddress(List macAddress) { + Preconditions.checkNotNull(macAddress, "macAddress cannot be null"); + List physAddresses = new ArrayList<>(); + for (String mac : macAddress) { + physAddresses.add(new PhysAddress(mac)); + } + return physAddresses; + } + + public static List getStaticMacEntries(List staticMacAddresses) { + if (isEmpty(staticMacAddresses)) { + return Collections.EMPTY_LIST; + } + StaticMacEntriesBuilder staticMacEntriesBuilder = new StaticMacEntriesBuilder(); + List staticMacEntries = new ArrayList<>(); + List physAddressList = getPhysAddress(staticMacAddresses); + for (PhysAddress physAddress : physAddressList) { + staticMacEntries.add(staticMacEntriesBuilder.setMacAddress(physAddress).build()); + } + return staticMacEntries; + } + + public static InstanceIdentifier getStaticMacEntriesCfgDataPathIdentifier(String interfaceName, + String macAddress) { + return InstanceIdentifier.builder(ElanInterfaces.class) + .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).child(StaticMacEntries.class, + new StaticMacEntriesKey(new PhysAddress(macAddress))).build(); + } + + public static List getDeletedEntries(List originalStaticMacEntries, + List updatedStaticMacEntries) { + if (isEmpty(originalStaticMacEntries)) { + return Collections.EMPTY_LIST; + } + List deleted = Lists.newArrayList(originalStaticMacEntries); + if (isNotEmpty(updatedStaticMacEntries)) { + deleted.removeAll(updatedStaticMacEntries); + } + return deleted; + } + + public static List diffOf(List orig, List updated) { + if (isEmpty(orig)) { + return Collections.EMPTY_LIST; + } + List diff = Lists.newArrayList(orig); + if (isNotEmpty(updated)) { + diff.removeAll(updated); + } + return diff; + } + + public static void segregateToBeDeletedAndAddEntries(List originalStaticMacEntries, + List updatedStaticMacEntries) { + if (isNotEmpty(updatedStaticMacEntries)) { + List existingClonedStaticMacEntries = new ArrayList<>(); + if (isNotEmpty(originalStaticMacEntries)) { + existingClonedStaticMacEntries.addAll(0, originalStaticMacEntries); + originalStaticMacEntries.removeAll(updatedStaticMacEntries); + updatedStaticMacEntries.removeAll(existingClonedStaticMacEntries); + } + } + } + + public static boolean isEmpty(Collection collection) { + return collection == null || collection.isEmpty(); + } + + public static boolean isNotEmpty(Collection collection) { + return !isEmpty(collection); + } + + public static void setElanInstancToDpnsCache(Map> elanInstancToDpnsCache) { + ElanUtils.elanInstancToDpnsCache = elanInstancToDpnsCache; + } + + public static Set getElanInvolvedDPNsFromCache(String elanName) { + return elanInstancToDpnsCache.get(elanName); + } + + public static void addDPNInterfaceToElanInCache(String elanName, DpnInterfaces dpnInterfaces) { + elanInstancToDpnsCache.computeIfAbsent(elanName, key -> new HashSet<>()).add(dpnInterfaces); + } + + public static void removeDPNInterfaceFromElanInCache(String elanName, DpnInterfaces dpnInterfaces) { + elanInstancToDpnsCache.computeIfAbsent(elanName, key -> new HashSet<>()).remove(dpnInterfaces); + } + + public Optional getSourceIpAddress(Ethernet ethernet) { + Optional srcIpAddress = Optional.absent(); + if (ethernet.getPayload() == null) { + return srcIpAddress; + } + byte[] ipAddrBytes = null; + if (ethernet.getPayload() instanceof IPv4) { + IPv4 ipv4 = (IPv4) ethernet.getPayload(); + ipAddrBytes = Ints.toByteArray(ipv4.getSourceAddress()); + } else if (ethernet.getPayload() instanceof ARP) { + ipAddrBytes = ((ARP) ethernet.getPayload()).getSenderProtocolAddress(); + } + if (ipAddrBytes != null) { + String ipAddr = NWUtil.toStringIpAddress(ipAddrBytes); + return Optional.of(IpAddressBuilder.getDefaultInstance(ipAddr)); + } + return srcIpAddress; + } + + public List getElanMacEntries(String elanName) { + MacTable macTable = getElanMacTable(elanName); + if (macTable == null) { + return Collections.emptyList(); + } + return macTable.getMacEntry(); + } + + public boolean isTunnelInLogicalGroup(String interfaceName, DataBroker broker) { + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang + .ietf.interfaces.rev140508.interfaces.Interface configIface = + interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName); + IfTunnel ifTunnel = configIface.getAugmentation(IfTunnel.class); + if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) { + ParentRefs refs = configIface.getAugmentation(ParentRefs.class); + if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) { + return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated + } + } + return false; + } + + public static void addElanInterfaceToElanInstanceCache(String elanInstanceName, String elanInterfaceName) { + elanInstanceToInterfacesCache.computeIfAbsent(elanInstanceName, key -> new HashSet<>()).add(elanInterfaceName); + } + + public static void removeElanInterfaceToElanInstanceCache(String elanInstanceName, String interfaceName) { + Set elanInterfaces = elanInstanceToInterfacesCache.get(elanInstanceName); + if (elanInterfaces == null || elanInterfaces.isEmpty()) { + return; + } + elanInterfaces.remove(interfaceName); + } + + @Nonnull public static Set removeAndGetElanInterfaces(String elanInstanceName) { + Set removed = elanInstanceToInterfacesCache.remove(elanInstanceName); + return removed != null ? removed : Collections.emptySet(); + } + + public static InstanceIdentifier getFlowIid(Flow flow, BigInteger dpnId) { + FlowKey flowKey = new FlowKey(new FlowId(flow.getId())); + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId = + new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId("openflow:" + dpnId); + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node nodeDpn = + new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build(); + return InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, + nodeDpn.getKey()).augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build(); + } + + public static String getElanInterfaceJobKey(String interfaceName) { + return "elaninterface-" + interfaceName; + } + + public void addArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress, String macAddress, + int lportTag, List instructions) { + LOG.info("Installing the ARP responder flow on DPN {} for Interface {} with MAC {} & IP {}", dpnId, + ingressInterfaceName, macAddress, ipAddress); + ElanInterface elanIface = getElanInterfaceByElanInterfaceName(broker, ingressInterfaceName); + ElanInstance elanInstance = getElanInstanceByName(broker, elanIface.getElanInstanceName()); + if (elanInstance == null) { + LOG.debug("addArpResponderFlow: elanInstance is null, Failed to install arp responder flow for Interface {}" + + " with MAC {} & IP {}", dpnId, + ingressInterfaceName, macAddress, ipAddress); + return; + } + String flowId = ArpResponderUtil.getFlowId(lportTag, ipAddress); + ArpResponderUtil.installFlow(mdsalManager, dpnId, flowId, flowId, NwConstants.DEFAULT_ARP_FLOW_PRIORITY, + ArpResponderUtil.generateCookie(lportTag, ipAddress), + ArpResponderUtil.getMatchCriteria(lportTag, elanInstance, ipAddress), instructions); + LOG.info("Installed the ARP Responder flow for Interface {}", ingressInterfaceName); + } + + public void removeArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress, + int lportTag) { + LOG.info("Removing the ARP responder flow on DPN {} of Interface {} with IP {}", dpnId, ingressInterfaceName, + ipAddress); + ArpResponderUtil.removeFlow(mdsalManager, dpnId, ArpResponderUtil.getFlowId(lportTag, ipAddress)); } } + +