X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=elanmanager%2Fimpl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetvirt%2Felan%2Finternal%2FElanInterfaceManager.java;h=0ed67f922045a8058631386af807b8798a22853f;hb=2f0569ed75ef8a1fb60f992d19c8bbdf92ff45bf;hp=e306a493014bcbd47c912882d91e57c2272e0899;hpb=cf8a16020e2beb992e12e84387d2060a0d17c81f;p=netvirt.git diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java index e306a49301..0ed67f9220 100644 --- a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java +++ b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java @@ -7,11 +7,16 @@ */ package org.opendaylight.netvirt.elan.internal; +import static java.util.Collections.emptyList; +import static org.opendaylight.genius.infra.Datastore.CONFIGURATION; +import static org.opendaylight.genius.infra.Datastore.OPERATIONAL; +import static org.opendaylight.infrautils.utils.concurrent.LoggingFutures.addErrorLogging; +import static org.opendaylight.mdsal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS; import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; import java.math.BigInteger; import java.util.ArrayList; @@ -20,22 +25,23 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; -import javax.annotation.PostConstruct; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.locks.ReentrantLock; +import javax.annotation.PreDestroy; 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.ReadWriteTransaction; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; +import org.opendaylight.genius.infra.Datastore.Configuration; +import org.opendaylight.genius.infra.Datastore.Operational; import org.opendaylight.genius.infra.ManagedNewTransactionRunner; import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl; +import org.opendaylight.genius.infra.TypedReadWriteTransaction; +import org.opendaylight.genius.infra.TypedWriteTransaction; import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo; import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; import org.opendaylight.genius.itm.globals.ITMConstants; @@ -58,14 +64,19 @@ import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata; import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; import org.opendaylight.genius.mdsalutil.matches.MatchMetadata; import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId; +import org.opendaylight.genius.utils.JvmGlobalLocks; import org.opendaylight.genius.utils.ServiceIndex; import org.opendaylight.infrautils.jobcoordinator.JobCoordinator; -import org.opendaylight.infrautils.utils.concurrent.ListenableFutures; -import org.opendaylight.netvirt.elan.ElanException; +import org.opendaylight.infrautils.utils.concurrent.Executors; +import org.opendaylight.infrautils.utils.concurrent.LoggingFutures; +import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.netvirt.elan.cache.ElanInstanceCache; import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache; import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils; import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils; +import org.opendaylight.netvirt.elan.recovery.impl.ElanServiceRecoveryHandler; import org.opendaylight.netvirt.elan.utils.ElanConstants; import org.opendaylight.netvirt.elan.utils.ElanEtreeUtils; import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler; @@ -76,10 +87,14 @@ import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils; import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice; import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils; import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager; +import org.opendaylight.serviceutils.srm.RecoverableListener; +import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry; +import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener; 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.interfaces.rev140508.interfaces.state.Interface; 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.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; @@ -87,9 +102,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService; 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.itm.op.rev160406.external.tunnel.list.ExternalTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; +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.NodeKey; 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.EtreeInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType; @@ -98,8 +118,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.Elan import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder; @@ -121,6 +139,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev14 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Uint32; +import org.opendaylight.yangtools.yang.common.Uint64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -131,9 +151,11 @@ import org.slf4j.LoggerFactory; * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface */ @Singleton -public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase { +public class ElanInterfaceManager extends AbstractAsyncDataTreeChangeListener + implements RecoverableListener { private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class); - private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L); + private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("NetvirtEventLogger"); + public static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L); private static final boolean SH_FLAG_SET = true; private static final boolean SH_FLAG_UNSET = false; @@ -152,6 +174,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase> unProcessedElanInterfaces = new ConcurrentHashMap<>(); @@ -165,8 +188,13 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase getWildCardPath() { - return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class); + @PreDestroy + public void close() { + super.close(); + Executors.shutdownAndAwaitTermination(getExecutorService()); } @Override - protected void remove(InstanceIdentifier identifier, ElanInterface del) { + public void remove(InstanceIdentifier identifier, ElanInterface del) { String interfaceName = del.getName(); - ElanInstance elanInfo = elanInstanceCache.get(del.getElanInstanceName()).orNull(); + String elanInstanceName = del.getElanInstanceName(); + EVENT_LOGGER.debug("ELAN-Interface, REMOVE {} Instance {}", interfaceName, elanInstanceName); + Queue elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName); + if (elanInterfaces != null && elanInterfaces.contains(del)) { + elanInterfaces.remove(del); + if (elanInterfaces.isEmpty()) { + unProcessedElanInterfaces.remove(elanInstanceName); + } + } + ElanInstance elanInfo = elanInstanceCache.get(elanInstanceName).orElse(null); /* * Handling in case the elan instance is deleted.If the Elan instance is * deleted, there is no need to explicitly delete the elan interfaces @@ -213,179 +264,174 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase> removeElanInterface(ElanInstance elanInfo, String interfaceName, InterfaceInfo interfaceInfo) { String elanName = elanInfo.getElanInstanceName(); - boolean isLastElanInterface = false; - boolean isLastInterfaceOnDpn = false; - BigInteger dpId = null; - long elanTag = elanInfo.getElanTag(); + EVENT_LOGGER.debug("ELAN-InterfaceState, REMOVE {} Instance {}", interfaceName, elanName); + Uint32 elanTag = elanInfo.getElanTag(); // We use two transaction so we don't suffer on multiple shards (interfaces and flows) - WriteTransaction interfaceTx = broker.newWriteOnlyTransaction(); - Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx); - if (elanState == null) { - interfaceTx.cancel(); - return Collections.emptyList(); - } - WriteTransaction flowTx = broker.newWriteOnlyTransaction(); - List elanInterfaces = elanState.getElanInterfaces(); - if (elanInterfaces.isEmpty()) { - isLastElanInterface = true; - } - if (interfaceInfo != null) { - dpId = interfaceInfo.getDpId(); - DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, - interfaceName, elanTag, interfaceTx); - /* - * If there are not elan ports, remove the unknown dmac, terminating - * service table flows, remote/local bc group - */ - if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null - || dpnInterfaces.getInterfaces().isEmpty()) { - // No more Elan Interfaces in this DPN - LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId); - if (!elanUtils.isOpenstackVniSemanticsEnforced()) { - removeDefaultTermFlow(dpId, elanInfo.getElanTag()); + List> futures = new ArrayList<>(); + RemoveElanInterfaceHolder holder = new RemoveElanInterfaceHolder(); + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> { + Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx); + if (elanState == null) { + return; + } + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> { + List elanInterfaces = elanState.getElanInterfaces(); + if (elanInterfaces == null || elanInterfaces.isEmpty()) { + holder.isLastElanInterface = true; } - removeUnknownDmacFlow(dpId, elanInfo, flowTx, elanInfo.getElanTag()); - removeEtreeUnknownDmacFlow(dpId, elanInfo, flowTx); - removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx); - removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx); - removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx); - if (isVxlanNetworkOrVxlanSegment(elanInfo)) { - if (elanUtils.isOpenstackVniSemanticsEnforced()) { - elanUtils.removeTerminatingServiceAction(dpId, - elanUtils.getVxlanSegmentationId(elanInfo).intValue()); + if (interfaceInfo != null) { + holder.dpId = interfaceInfo.getDpId(); + DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, holder.dpId, + interfaceName, elanTag, interfaceTx); + /* + * If there are not elan ports, remove the unknown dmac, terminating + * service table flows, remote/local bc group + */ + if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null + || dpnInterfaces.getInterfaces().isEmpty()) { + // No more Elan Interfaces in this DPN + EVENT_LOGGER.debug("ELAN-Flows, REMOVE {} Instance {}", interfaceName, elanName); + LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), + holder.dpId); + if (!elanUtils.isOpenstackVniSemanticsEnforced()) { + removeDefaultTermFlow(holder.dpId, elanInfo.getElanTag().toJava()); + } + removeUnknownDmacFlow(holder.dpId, elanInfo, flowTx, elanInfo.getElanTag().toJava()); + removeEtreeUnknownDmacFlow(holder.dpId, elanInfo, flowTx); + removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx); + removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx); + removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx); + if (isVxlanNetworkOrVxlanSegment(elanInfo)) { + if (elanUtils.isOpenstackVniSemanticsEnforced()) { + elanUtils.removeTerminatingServiceAction(holder.dpId, + ElanUtils.getVxlanSegmentationId(elanInfo).intValue()); + } + unsetExternalTunnelTable(holder.dpId, elanInfo, flowTx); + } + } else { + setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, flowTx); } - unsetExternalTunnelTable(dpId, elanInfo); } - isLastInterfaceOnDpn = true; - } else { - setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo); - } - } - - List> futures = new ArrayList<>(); - futures.add(ElanUtils.waitForTransactionToComplete(interfaceTx)); - futures.add(ElanUtils.waitForTransactionToComplete(flowTx)); + })); + })); + futures.forEach(ElanUtils::waitForTransactionToComplete); - if (isLastInterfaceOnDpn && dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) { - setElanAndEtreeBCGrouponOtherDpns(elanInfo, dpId); - } InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface( - interfaceName, elanInfo, interfaceInfo, this, isLastElanInterface); + interfaceName, elanInfo, interfaceInfo, this, holder.isLastElanInterface); jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker, ElanConstants.JOB_MAX_RETRIES); return futures; } - private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, - WriteTransaction deleteFlowGroupTx) { - EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag()); + private void removeEtreeUnknownDmacFlow(Uint64 dpId, ElanInstance elanInfo, + TypedReadWriteTransaction deleteFlowGroupTx) + throws ExecutionException, InterruptedException { + EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag().toJava()); if (etreeLeafTag != null) { - long leafTag = etreeLeafTag.getEtreeLeafTag().getValue(); + long leafTag = etreeLeafTag.getEtreeLeafTag().getValue().toJava(); removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag); } } private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo, - WriteTransaction deleteFlowGroupTx) { + TypedReadWriteTransaction deleteFlowGroupTx) + throws ExecutionException, InterruptedException { removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx); removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx); } private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo, - WriteTransaction deleteFlowGroupTx) { - EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class); + TypedReadWriteTransaction deleteFlowGroupTx) + throws ExecutionException, InterruptedException { + EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class); if (etreeInstance != null) { - BigInteger dpnId = interfaceInfo.getDpId(); - long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue()); - List listBuckets = new ArrayList<>(); - int bucketId = 0; - listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId)); - Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, - MDSALUtil.buildBucketLists(listBuckets)); - LOG.trace("deleted the localBroadCast Group:{}", group); - mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx); + Uint64 dpnId = interfaceInfo.getDpId(); + long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue().toJava()); + LOG.trace("deleted the localBroadCast Group:{}", groupId); + mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId); } } private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo, - WriteTransaction deleteFlowGroupTx) { - EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class); + TypedReadWriteTransaction deleteFlowGroupTx) + throws ExecutionException, InterruptedException { + EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class); if (etreeInstance != null) { - long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue(); - int bucketId = 0; - int actionKey = 0; - List listBuckets = new ArrayList<>(); - List listAction = new ArrayList<>(); - listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeTag)).buildAction(++actionKey)); - listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, - MDSALUtil.WATCH_GROUP)); - bucketId++; - listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag)); - BigInteger dpnId = interfaceInfo.getDpId(); + long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava(); + Uint64 dpnId = interfaceInfo.getDpId(); long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag); - Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, - MDSALUtil.buildBucketLists(listBuckets)); - LOG.trace("deleting the remoteBroadCast group:{}", group); - mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx); + LOG.trace("deleting the remoteBroadCast group:{}", groupId); + mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId); } } - private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) { + private static Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, + TypedReadWriteTransaction tx) throws ExecutionException, InterruptedException { String elanName = elanInfo.getElanInstanceName(); - Elan elanState = ElanUtils.getElanByName(broker, elanName); + Elan elanState = ElanUtils.getElanByName(tx, elanName); if (elanState == null) { return elanState; } - List elanInterfaces = elanState.getElanInterfaces(); + List existingElanInterfaces = elanState.getElanInterfaces(); + List elanInterfaces = new ArrayList<>(); + if (existingElanInterfaces != null) { + elanInterfaces.addAll(existingElanInterfaces); + } boolean isRemoved = elanInterfaces.remove(interfaceName); if (!isRemoved) { return elanState; } if (elanInterfaces.isEmpty()) { - tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName)); - tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName)); - tx.delete(LogicalDatastoreType.OPERATIONAL, - ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag())); + tx.delete(ElanUtils.getElanInstanceOperationalDataPath(elanName)); + tx.delete(ElanUtils.getElanMacTableOperationalDataPath(elanName)); + tx.delete(ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag())); + tx.delete(ElanUtils.getElanDpnOperationDataPath(elanName)); } else { Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName) - .setKey(new ElanKey(elanName)).build(); - tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName), - updateElanState); + .withKey(new ElanKey(elanName)).build(); + tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState); } return elanState; } - private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) { + private void deleteElanInterfaceFromConfigDS(String interfaceName, TypedReadWriteTransaction tx) + throws ExecutionException, InterruptedException { // removing the ElanInterface from the config data_store if interface is // not present in Interface config DS - if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null - && elanInterfaceCache.get(interfaceName).isPresent()) { - tx.delete(LogicalDatastoreType.CONFIGURATION, - ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName)); + InstanceIdentifier elanInterfaceId = ElanUtils + .getElanInterfaceConfigurationDataPathId(interfaceName); + FluentFuture> interfaceOptional = tx.read(elanInterfaceId); + if (!interfaceOptional.get().isPresent() && elanInterfaceCache.get(interfaceName).isPresent()) { + tx.delete(ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName)); } } List> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String interfaceName, boolean isLastElanInterface) { String elanName = elanInfo.getElanInstanceName(); + EVENT_LOGGER.debug("ELAN-InterfaceEntries, REMOVE {} Instance {}", interfaceName, elanName); List> futures = new ArrayList<>(); - futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(flowTx -> { - futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(interfaceTx -> { + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> { + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> { InstanceIdentifier elanInterfaceId = ElanUtils .getElanInterfaceMacEntriesOperationalDataPath(interfaceName); - Optional existingElanInterfaceMac = - interfaceTx.read(LogicalDatastoreType.OPERATIONAL, elanInterfaceId).checkedGet(); + Optional existingElanInterfaceMac = interfaceTx.read(elanInterfaceId).get(); LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName); if (interfaceInfo != null) { if (existingElanInterfaceMac.isPresent()) { @@ -399,9 +445,10 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase macEntryOptional = elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress); if (!isLastElanInterface && macEntryOptional.isPresent()) { - interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, - ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress)); + interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress)); } + EVENT_LOGGER.debug("ELAN-MacFlows, REMOVE {} Instance {} Mac {}", + interfaceName, elanName, macAddress); elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx); macAddresses.add(macAddress); } @@ -423,74 +470,87 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase interfaceLists = dpnInterfaces.getInterfaces(); - if (interfaceLists != null) { - interfaceLists.remove(interfaceName); - } + private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, Uint64 dpId, + String interfaceName, Uint32 elanTag, + TypedReadWriteTransaction tx) + throws ExecutionException, InterruptedException { + // FIXME: pass in and use ElanInstanceKey instead? + final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanName); + lock.lock(); + try { + DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId); + if (dpnInterfaces != null) { + List interfaceLists = null; + if (dpnInterfaces.getInterfaces() != null) { + interfaceLists = new ArrayList<>(dpnInterfaces.getInterfaces()); + } + if (interfaceLists != null) { + interfaceLists.remove(interfaceName); + } - if (interfaceLists == null || interfaceLists.isEmpty()) { - deleteAllRemoteMacsInADpn(elanName, dpId, elanTag); - deleteElanDpnInterface(elanName, dpId, tx); - } else { - dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx); + if (interfaceLists == null || interfaceLists.isEmpty()) { + deleteAllRemoteMacsInADpn(elanName, dpId, elanTag); + deleteElanDpnInterface(elanName, dpId, tx); + } else { + dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx); + } } + return dpnInterfaces; + } finally { + lock.unlock(); } - return dpnInterfaces; } - private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) { + private void deleteAllRemoteMacsInADpn(String elanName, Uint64 dpId, Uint32 elanTag) { List dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName); - for (DpnInterfaces dpnInterface : dpnInterfaces) { - BigInteger currentDpId = dpnInterface.getDpId(); - if (!currentDpId.equals(dpId)) { - for (String elanInterface : dpnInterface.getInterfaces()) { - ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface); - if (macs == null || macs.getMacEntry() == null) { - continue; - } - for (MacEntry mac : macs.getMacEntry()) { - removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac); - removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac); + addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> { + for (DpnInterfaces dpnInterface : dpnInterfaces) { + Uint64 currentDpId = dpnInterface.getDpId(); + if (!currentDpId.equals(dpId) && dpnInterface.getInterfaces() != null) { + for (String elanInterface : dpnInterface.getInterfaces()) { + ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface); + if (macs == null || macs.getMacEntry() == null) { + continue; + } + for (MacEntry mac : macs.getMacEntry()) { + removeTheMacFlowInTheDPN(dpId, elanTag, mac, confTx); + removeEtreeMacFlowInTheDPN(dpId, elanTag, mac, confTx); + } } } } - } + }), LOG, "Error deleting remote MACs in DPN {}", dpId); } - private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) { - EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); + private void removeEtreeMacFlowInTheDPN(Uint64 dpId, Uint32 elanTag, MacEntry mac, + TypedReadWriteTransaction confTx) throws ExecutionException, InterruptedException { + EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue()); if (etreeLeafTag != null) { - removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac); + removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), mac, confTx); } } - private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) { + private void removeTheMacFlowInTheDPN(Uint64 dpId, Uint32 elanTag, MacEntry mac, + TypedReadWriteTransaction confTx) throws ExecutionException, InterruptedException { mdsalManager - .removeFlow(dpId, + .removeFlow(confTx, dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, - ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId, - mac.getMacAddress().getValue(), elanTag))); + ElanUtils.getKnownDynamicmacFlowRef(elanTag, mac.getMacAddress().getValue()))); } /* @@ -510,11 +570,14 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase identifier, ElanInterface original, ElanInterface update) { + public void update(InstanceIdentifier identifier, ElanInterface original, ElanInterface update) { // updating the static-Mac Entries for the existing elanInterface String elanName = update.getElanInstanceName(); String interfaceName = update.getName(); + LOG.info("Update static mac entries for elan interface {} in elan instance {}", interfaceName, elanName); + EVENT_LOGGER.debug("ELAN-Interface, UPDATE {} Instance {}", original.getName(), elanName); List originalStaticMacEntries = original.getStaticMacEntries(); List updatedStaticMacEntries = update.getStaticMacEntries(); @@ -529,62 +592,74 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase macEntryIdentifier = getMacEntryOperationalDataPath(elanName, staticMacEntry.getMacAddress()); - Optional existingMacEntry = ElanUtils.read(broker, - LogicalDatastoreType.OPERATIONAL, macEntryIdentifier); - WriteTransaction tx = broker.newWriteOnlyTransaction(); - if (existingMacEntry.isPresent()) { - elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList( - elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(), - tx); - } else { - elanForwardingEntriesHandler.addElanInterfaceForwardingTableList( - elanName, interfaceName, staticMacEntry, tx); - } - ElanUtils.waitForTransactionToComplete(tx); + addErrorLogging(ElanUtils.waitForTransactionToComplete( + txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> { + Optional existingMacEntry = tx.read(macEntryIdentifier).get(); + if (existingMacEntry.isPresent()) { + LOG.debug("updating elan interface forwarding table for mac entry {} elan instance {}", + existingMacEntry.get(), elanName); + elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList( + elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(), + tx); + } else { + LOG.info("Adding elan interface forwarding table for mac entry {} elan interface" + + " {} elan instance {}.", staticMacEntry.getMacAddress(), interfaceName, elanName); + elanForwardingEntriesHandler.addElanInterfaceForwardingTableList( + elanName, interfaceName, staticMacEntry, tx); + } + })), LOG, "Error in update: identifier={}, original={}, update={}", identifier, original, update); } } @Override - protected void add(InstanceIdentifier identifier, ElanInterface elanInterfaceAdded) { - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { + public void add(InstanceIdentifier identifier, ElanInterface elanInterfaceAdded) { + LOG.info("Init for ELAN interface Add {}", elanInterfaceAdded); + addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> { String elanInstanceName = elanInterfaceAdded.getElanInstanceName(); String interfaceName = elanInterfaceAdded.getName(); + EVENT_LOGGER.debug("ELAN-Interface, ADD {} Instance {}", interfaceName, elanInstanceName); InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName); if (interfaceInfo == null) { LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName); return; } - ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull(); + ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orElse(null); if (elanInstance == null) { - elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName) - .setDescription(elanInterfaceAdded.getDescription()).build(); // Add the ElanInstance in the Configuration data-store List elanInterfaces = new ArrayList<>(); elanInterfaces.add(interfaceName); - elanInstance = ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx); + elanInstance = txRunner.applyWithNewReadWriteTransactionAndSubmit(CONFIGURATION, + confTx -> ElanUtils.updateOperationalDataStore(idManager, + new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription( + elanInterfaceAdded.getDescription()).build(), elanInterfaces, confTx, operTx)).get(); } - Long elanTag = elanInstance.getElanTag(); + Uint32 elanTag = elanInstance.getElanTag(); // If elan tag is not updated, then put the elan interface into // unprocessed entry map and entry. Let entries // in this map get processed during ELAN update DCN. - if (elanTag == null) { + if (elanTag == null || elanTag.longValue() == 0L) { ConcurrentLinkedQueue elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName); if (elanInterfaces == null) { elanInterfaces = new ConcurrentLinkedQueue<>(); } - elanInterfaces.add(elanInterfaceAdded); + if (!elanInterfaces.contains(elanInterfaceAdded)) { + elanInterfaces.add(elanInterfaceAdded); + } + LOG.error("ELAN tag for instance {} is not created. Adding it to unprocessed list." + + " Recreate the network if this message is seen multiple times", elanInstanceName); unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces); return; } InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded, interfaceInfo, elanInstance, this); jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES); - }), LOG, "Error procedding added ELAN interface"); + }), LOG, "Error processing added ELAN interface"); } - List> handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException { + List> handleunprocessedElanInterfaces(ElanInstance elanInstance) { + LOG.trace("Handling unprocessed elan interfaces for elan instance {}", elanInstance.getElanInstanceName()); List> futures = new ArrayList<>(); Queue elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName()); if (elanInterfaces == null || elanInterfaces.isEmpty()) { @@ -595,183 +670,242 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase writeFlowGroupTx) { ElanDpnInterfacesList elanDpnInterfacesList = elanUtils .getElanDpnInterfacesList(elanInstance.getElanInstanceName()); List dpnInterfaceLists = null; if (elanDpnInterfacesList != null) { dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces(); } - if (dpnInterfaceLists == null) { - dpnInterfaceLists = new ArrayList<>(); + if (dpnInterfaceLists != null && !dpnInterfaceLists.isEmpty()) { + Uint64 dstDpId = interfaceInfo.getDpId(); + processRemoteDmacFlowForInterface(dstDpId, elanInstance, dpnInterfaceLists, writeFlowGroupTx); } + } + + private void processRemoteDmacFlowForInterface(Uint64 dstDpId, ElanInstance elanInstance, + List dpnInterfaceLists, TypedWriteTransaction writeFlowGroupTx) { for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) { - BigInteger dstDpId = interfaceInfo.getDpId(); - if (dpnInterfaces.getDpId().equals(dstDpId)) { + if (Objects.equals(dpnInterfaces.getDpId(), dstDpId)) { continue; } List remoteElanInterfaces = dpnInterfaces.getInterfaces(); + if (remoteElanInterfaces == null || remoteElanInterfaces.isEmpty()) { + continue; + } for (String remoteIf : remoteElanInterfaces) { ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf); InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf); - if (elanIfMac == null) { + if (elanIfMac == null || remoteInterface == null) { continue; } - List remoteMacEntries = elanIfMac.getMacEntry(); - if (remoteMacEntries != null) { - for (MacEntry macEntry : remoteMacEntries) { - String macAddress = macEntry.getMacAddress().getValue(); - LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress, - dstDpId, elanInstance.getElanInstanceName()); - elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(), - remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress, - elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance); - } + List remoteMacEntries = elanIfMac.nonnullMacEntry(); + for (MacEntry macEntry : remoteMacEntries) { + String macAddress = macEntry.getMacAddress().getValue(); + LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress, + dstDpId, elanInstance.getElanInstanceName()); + elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(), + remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress, + elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance); } } } } + private static class AddElanInterfaceHolder { + private DpnInterfaces dpnInterfaces = null; + private boolean isFirstInterfaceInDpn = false; + private Uint64 dpId; + } + + @SuppressWarnings("checkstyle:ForbidCertainMethod") List> addElanInterface(ElanInterface elanInterface, - InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException { + InterfaceInfo interfaceInfo, ElanInstance elanInstance) { Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null"); Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null"); Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null"); String interfaceName = elanInterface.getName(); String elanInstanceName = elanInterface.getElanInstanceName(); + LOG.trace("Adding elan interface: interface name {} , instance name {}", interfaceName, elanInstanceName); + EVENT_LOGGER.debug("ELAN-InterfaceState, ADD {} Instance {}", interfaceName, elanInstanceName); - Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName); - WriteTransaction tx = broker.newWriteOnlyTransaction(); - if (elanInfo == null) { - List elanInterfaces = new ArrayList<>(); - elanInterfaces.add(interfaceName); - ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx); - } else { - createElanStateList(elanInstanceName, interfaceName, tx); - } - boolean isFirstInterfaceInDpn = false; - // Specific actions to the DPN where the ElanInterface has been added, - // for example, programming the - // External tunnel table if needed or adding the ElanInterface to the - // DpnInterfaces in the operational DS. - BigInteger dpId = interfaceInfo.getDpId(); - DpnInterfaces dpnInterfaces = null; - if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) { - InstanceIdentifier elanDpnInterfaces = ElanUtils - .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId); - Optional existingElanDpnInterfaces = ElanUtils.read(broker, - LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces); - if (!existingElanDpnInterfaces.isPresent()) { - isFirstInterfaceInDpn = true; - // ELAN's 1st ElanInterface added to this DPN - dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx); - // The 1st ElanInterface in a DPN must program the Ext Tunnel - // table, but only if Elan has VNI - if (isVxlanNetworkOrVxlanSegment(elanInstance)) { - setExternalTunnelTable(dpId, elanInstance); - } - elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName); - } else { - List elanInterfaces = existingElanDpnInterfaces.get().getInterfaces(); + List> futures = new ArrayList<>(); + AddElanInterfaceHolder holder = new AddElanInterfaceHolder(); + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> { + Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName); + if (elanInfo == null) { + LOG.trace("elanInfo is null for elan instance: {}", elanInstanceName); + List elanInterfaces = new ArrayList<>(); elanInterfaces.add(interfaceName); - if (elanInterfaces.size() == 1) { // 1st dpn interface - elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName); + futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, + confTx -> ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, confTx, + operTx))); + } else { + createElanStateList(elanInstanceName, interfaceName, operTx); + } + // Specific actions to the DPN where the ElanInterface has been added, + // for example, programming the + // External tunnel table if needed or adding the ElanInterface to the + // DpnInterfaces in the operational DS. + holder.dpId = interfaceInfo.getDpId(); + if (holder.dpId != null && !holder.dpId.equals(ElanConstants.INVALID_DPN)) { + // FIXME: use elanInstaince.key() instead? + final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName); + lock.lock(); + try { + InstanceIdentifier elanDpnInterfaces = ElanUtils + .getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId); + Optional existingElanDpnInterfaces = operTx.read(elanDpnInterfaces).get(); + if (ElanUtils.isVlan(elanInstance)) { + holder.isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName, + elanInstanceName, existingElanDpnInterfaces); + } else { + holder.isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent(); + } + if (holder.isFirstInterfaceInDpn) { + // ELAN's 1st ElanInterface added to this DPN + if (!existingElanDpnInterfaces.isPresent()) { + holder.dpnInterfaces = + createElanInterfacesList(elanInstanceName, interfaceName, holder.dpId, operTx); + } else { + List existingInterfaces = existingElanDpnInterfaces.get().getInterfaces(); + List elanInterfaces = + existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>(); + elanInterfaces.add(interfaceName); + holder.dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, holder.dpId, + elanInterfaces, operTx); + } + LOG.debug("1st interface {} for elan {} is added to dpn {}", + interfaceName, elanInstanceName, holder.dpId); + // The 1st ElanInterface in a DPN must program the Ext Tunnel + // table, but only if Elan has VNI + if (isVxlanNetworkOrVxlanSegment(elanInstance)) { + futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, + confTx -> setExternalTunnelTable(holder.dpId, elanInstance, confTx))); + } + elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance, + interfaceName); + } else { + List existingInterfaces = existingElanDpnInterfaces.get().getInterfaces(); + List elanInterfaces = + existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>(); + elanInterfaces.add(interfaceName); + if (elanInterfaces.size() == 1) { // 1st dpn interface + elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance, + interfaceName); + } + holder.dpnInterfaces = + updateElanDpnInterfacesList(elanInstanceName, holder.dpId, elanInterfaces, operTx); + LOG.debug("Interface {} for elan {} is added to dpn {}", + interfaceName, elanInstanceName, holder.dpId); + } + } finally { + lock.unlock(); } - dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx); } - } - // add code to install Local/Remote BC group, unknow DMAC entry, - // terminating service table flow entry - // call bindservice of interfacemanager to create ingress table flow - // enty. - // Add interface to the ElanInterfaceForwardingEntires Container - createElanInterfaceTablesList(interfaceName, tx); - List> futures = new ArrayList<>(); - futures.add(ElanUtils.waitForTransactionToComplete(tx)); - installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn); + // add code to install Local/Remote BC group, unknow DMAC entry, + // terminating service table flow entry + // call bindservice of interfacemanager to create ingress table flow + // enty. + })); + futures.forEach(ElanUtils::waitForTransactionToComplete); + futures.add( + ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, + confTx -> installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, holder.dpnInterfaces, + holder.isFirstInterfaceInDpn, confTx)))); // add the vlan provider interface to remote BC group for the elan // for internal vlan networks if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) { if (interfaceManager.isExternalInterface(interfaceName)) { LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName); - handleExternalInterfaceEvent(elanInstance, dpnInterfaces, dpId); + handleExternalInterfaceEvent(elanInstance, holder.dpnInterfaces, holder.dpId); } } - - if (isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) { - //update the remote-DPNs remoteBC group entry with Tunnels - LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance, dpId); - setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId); + if (holder.isFirstInterfaceInDpn) { + // ELAN's 1st ElanInterface added to this DPN + LOG.debug("Adding dpn into operational dpn list {}", holder.dpId); + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> { + operTx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId), + holder.dpnInterfaces, CREATE_MISSING_PARENTS); + })); + } else { + LOG.debug("Updated dpn into operational dpn list {}", holder.dpId); } - String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName); - InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey, - elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this); - jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES); + scheduleElanInterfaceWorkerAfterRemoteBcGroup(elanInstance, interfaceInfo, holder.dpnInterfaces, + holder.isFirstInterfaceInDpn, elanInterface); return futures; } + @SuppressWarnings("checkstyle:ForbidCertainMethod") List> setupEntriesForElanInterface(ElanInstance elanInstance, - ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) - throws ElanException { + ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) { String elanInstanceName = elanInstance.getElanInstanceName(); String interfaceName = elanInterface.getName(); - WriteTransaction tx = broker.newWriteOnlyTransaction(); - BigInteger dpId = interfaceInfo.getDpId(); - WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction(); - installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo, - isFirstInterfaceInDpn, tx, writeFlowGroupTx); - - List staticMacEntriesList = elanInterface.getStaticMacEntries(); - List staticMacAddresses = Lists.newArrayList(); - + List> futures = new ArrayList<>(); + Uint64 dpId = interfaceInfo.getDpId(); boolean isInterfaceOperational = isOperational(interfaceInfo); - if (ElanUtils.isNotEmpty(staticMacEntriesList)) { - for (StaticMacEntries staticMacEntry : staticMacEntriesList) { - InstanceIdentifier macId = getMacEntryOperationalDataPath(elanInstanceName, - staticMacEntry.getMacAddress()); - Optional existingMacEntry = ElanUtils.read(broker, - LogicalDatastoreType.OPERATIONAL, macId); - if (existingMacEntry.isPresent()) { - elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList( - elanInstanceName, interfaceName, existingMacEntry.get().getInterface(), - existingMacEntry.get(), tx); - } else { - elanForwardingEntriesHandler - .addElanInterfaceForwardingTableList(elanInstanceName, interfaceName, staticMacEntry, tx); - } + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> { + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> { + installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo, + isFirstInterfaceInDpn, confTx); + + List staticMacEntriesList = elanInterface.getStaticMacEntries(); + List staticMacAddresses = Lists.newArrayList(); + + if (ElanUtils.isNotEmpty(staticMacEntriesList)) { + for (StaticMacEntries staticMacEntry : staticMacEntriesList) { + InstanceIdentifier macId = getMacEntryOperationalDataPath(elanInstanceName, + staticMacEntry.getMacAddress()); + Optional existingMacEntry = ElanUtils.read(broker, + LogicalDatastoreType.OPERATIONAL, macId); + if (existingMacEntry.isPresent()) { + elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList( + elanInstanceName, interfaceName, existingMacEntry.get().getInterface(), + existingMacEntry.get(), operTx); + } else { + elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstanceName, + interfaceName, staticMacEntry, operTx); + } - if (isInterfaceOperational) { - // Setting SMAC, DMAC, UDMAC in this DPN and also in other - // DPNs - String macAddress = staticMacEntry.getMacAddress().getValue(); - LOG.info("programming smac and dmacs for {} on source and other DPNs for elan {} and interface {}", - macAddress, elanInstanceName, interfaceName); - elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT, - staticMacEntry.getMacAddress().getValue(), true, writeFlowGroupTx); - } - } + if (isInterfaceOperational) { + // Setting SMAC, DMAC, UDMAC in this DPN and also in other + // DPNs + String macAddress = staticMacEntry.getMacAddress().getValue(); + LOG.info( + "programming smac and dmacs for {} on source and other DPNs for elan {} and interface" + + " {}", + macAddress, elanInstanceName, interfaceName); + EVENT_LOGGER.debug("ELAN-MacFlows, ADD {} Instance {} Mac {}", + interfaceName, elanInstanceName, macAddress); + elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT, + staticMacEntry.getMacAddress().getValue(), true, confTx); + } + } - if (isInterfaceOperational) { - // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop - // on purpose. - for (StaticMacEntries staticMacEntry : staticMacEntriesList) { - staticMacAddresses.add(staticMacEntry.getMacAddress()); + if (isInterfaceOperational) { + // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop + // on purpose. + for (StaticMacEntries staticMacEntry : staticMacEntriesList) { + staticMacAddresses.add(staticMacEntry.getMacAddress()); + } + elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId, + staticMacAddresses); + } } - elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId, - staticMacAddresses); - } - } - List> futures = new ArrayList<>(); - futures.add(ElanUtils.waitForTransactionToComplete(tx)); - futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx)); + })); + })); + futures.forEach(ElanUtils::waitForTransactionToComplete); if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) { //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active try { @@ -798,35 +932,62 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) { + private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName, + Optional existingElanDpnInterfaces) { + String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName); + if (!existingElanDpnInterfaces.isPresent()) { + return true; + } + if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) { + return false; + } + DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get(); + int dummyInterfaceCount = 0; + List interfaces = dpnInterfaces.getInterfaces(); + if (interfaces == null) { + return true; + } + if (interfaces.contains(routerPortUuid)) { + dummyInterfaceCount++; + } + if (interfaces.contains(elanInstanceName)) { + dummyInterfaceCount++; + } + return interfaces.size() == dummyInterfaceCount; + } + + private static InstanceIdentifier getMacEntryOperationalDataPath(String elanName, + PhysAddress physAddress) { return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName)) .child(MacEntry.class, new MacEntryKey(physAddress)).build(); } private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface, - InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, WriteTransaction tx, - WriteTransaction writeFlowGroupTx) throws ElanException { + InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction confTx) { if (!isOperational(interfaceInfo)) { + LOG.warn("Interface {} is not operational", elanInterface.getName()); + EVENT_LOGGER.debug("ELAN-InterfaceEntries, ADD {} Instance {} Interface Status {}, returning", + elanInterface.getName(), elanInstance.getElanInstanceName(), interfaceInfo.getOpState()); return; } - BigInteger dpId = interfaceInfo.getDpId(); + Uint64 dpId = interfaceInfo.getDpId(); if (!elanUtils.isOpenstackVniSemanticsEnforced()) { - elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx); + elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx); } - setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx); + setupFilterEqualsTable(elanInstance, interfaceInfo, confTx); if (isFirstInterfaceInDpn) { // Terminating Service , UnknownDMAC Table. // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type // for ELAN Instance is VxLAN if (isVxlanNetworkOrVxlanSegment(elanInstance)) { - setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx); + setupTerminateServiceTable(elanInstance, dpId, confTx); } - setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx); + setupUnknownDMacTable(elanInstance, dpId, confTx); /* * Install remote DMAC flow. This is required since this DPN is * added later to the elan instance and remote DMACs of other @@ -836,30 +997,30 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase confTx) { if (!isOperational(interfaceInfo)) { + LOG.warn("Entries for interface on dpn {} not installed since interface {} is not operational", + dpnInterfaces.getDpId(), interfaceInfo.getInterfaceName()); + EVENT_LOGGER.debug("ELAN-1stInterfaceEntries, ADD {} Instance {} Interface Status {}, returning", + interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName(), interfaceInfo.getOpState()); return; } + EVENT_LOGGER.debug("ELAN-1stInterfaceEntries, ADD {} Instance {}", + interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName()); // LocalBroadcast Group creation with elan-Interfaces - setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo); + LOG.info("Installing entries for interface {} on dpn {}", interfaceInfo.getInterfaceName(), + dpnInterfaces.getDpId()); + setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx); if (isFirstInterfaceInDpn) { LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL); - BigInteger dpId = interfaceInfo.getDpId(); - // RemoteBroadcast Group creation - try { - Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL); - } catch (InterruptedException e1) { - LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo); - } - elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId); try { Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL); } catch (InterruptedException e1) { @@ -868,144 +1029,84 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase getGroupIid(ElanInstance elanInfo, Uint64 dpnId) { + long remoteBcGroupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag().toJava()); + return InstanceIdentifier.builder(Nodes.class) + .child(Node.class, new NodeKey(new org.opendaylight.yang.gen.v1.urn.opendaylight + .inventory.rev130819.NodeId("openflow:" + dpnId.toString()))) + .augmentation(FlowCapableNode.class) + .child(Group.class, new GroupKey(new GroupId(remoteBcGroupId))).build(); + } + + public void scheduleElanInterfaceWorkerAfterRemoteBcGroup(ElanInstance elanInfo, + InterfaceInfo interfaceInfo, + DpnInterfaces dpnInterfaces, + boolean isFirstInterfaceInDpn, + ElanInterface elanInterface) { + if (!isOperational(interfaceInfo)) { + LOG.debug("Interface {} is not operational", elanInterface.getName()); + return; + } + String elanInterfaceJobKey = ElanUtils.getElanInterfaceJobKey(interfaceInfo.getInterfaceName()); + InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(elanInterfaceJobKey, + elanInterface, interfaceInfo, elanInfo, isFirstInterfaceInDpn, this); + InstanceIdentifier groupInstanceId = getGroupIid(elanInfo, dpnInterfaces.getDpId()); + elanGroupCache.addJobToWaitList(groupInstanceId, () -> { + jobCoordinator.enqueueJob(elanInterfaceJobKey, addWorker, ElanConstants.JOB_MAX_RETRIES); + }); + } + public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo, - WriteTransaction writeFlowGroupTx) { + TypedWriteTransaction writeFlowGroupTx) { int ifTag = interfaceInfo.getInterfaceTag(); Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE, - getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0, - 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), + getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 11, elanInfo.getElanInstanceName(), + 0, 0, Uint64.valueOf(ElanConstants.COOKIE_ELAN_FILTER_EQUALS.toJava().add(BigInteger.valueOf(ifTag))), ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag), elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName())); - mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx); + mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow); + LOG.trace("Filter equals table(55) flow entry created on dpn: {} for interface port: {}", + interfaceInfo.getDpId(), interfaceInfo.getPortName()); Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE, - getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0, - 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), + getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 12, elanInfo.getElanInstanceName(), 0, + 0, Uint64.valueOf(ElanConstants.COOKIE_ELAN_FILTER_EQUALS.toJava().add(BigInteger.valueOf(ifTag))), getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop()); - mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx); + mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry); + LOG.trace("Filter equals table(55) drop flow entry created on dpn: {} for interface port: {}", + interfaceInfo.getDpId(), interfaceInfo.getPortName()); } public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo, - WriteTransaction deleteFlowGroupTx) { + TypedReadWriteTransaction flowTx) throws ExecutionException, InterruptedException { int ifTag = interfaceInfo.getInterfaceTag(); - Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE, - getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0, - 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), - ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag), - elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName())); - - mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx); - - Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE, - getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0, - 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), - getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop()); - - mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx); - } + Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE, + getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group")); - private List getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart, - InterfaceInfo interfaceInfo, long elanTag) { - return elanL2GatewayMulticastUtils.getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(), - bucketKeyStart, elanTag); - } - - private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId) { - int elanTag = elanInfo.getElanTag().intValue(); - long groupId = ElanUtils.getElanRemoteBCGId(elanTag); - setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId); - EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class); - if (etreeInstance != null) { - int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue(); - long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag); - setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId); - } - } - - @SuppressWarnings("checkstyle:IllegalCatch") - private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId) { - int bucketId = 0; - ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName()); - if (elanDpns != null) { - List dpnInterfaces = elanDpns.getDpnInterfaces(); - for (DpnInterfaces dpnInterface : dpnInterfaces) { - List remoteListBucketInfo = new ArrayList<>(); - if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId) - && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) { - List listAction = new ArrayList<>(); - int actionKey = 0; - listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey)); - remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, - MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP)); - bucketId++; - for (DpnInterfaces otherFes : dpnInterfaces) { - if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(), - dpnInterface.getDpId()) && otherFes.getInterfaces() != null - && !otherFes.getInterfaces().isEmpty()) { - try { - List remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction( - dpnInterface.getDpId(), otherFes.getDpId(), - elanUtils.isOpenstackVniSemanticsEnforced() - ? elanUtils.getVxlanSegmentationId(elanInfo) : elanTag); - if (!remoteListActionInfo.isEmpty()) { - remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil - .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP)); - bucketId++; - } - } catch (Exception ex) { - LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; " - + "Logical Group Interface not found between source Dpn - {}, " - + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex); - return; - } - } - } - List elanL2GwDevicesBuckets = elanL2GatewayMulticastUtils - .getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnInterface.getDpId(), bucketId); - remoteListBucketInfo.addAll(elanL2GwDevicesBuckets); + mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow); - if (remoteListBucketInfo.isEmpty()) { - LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId()); - continue; - } - Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, - MDSALUtil.buildBucketLists(remoteListBucketInfo)); - LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId()); - mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group); - } - } - try { - Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL); - } catch (InterruptedException e1) { - LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo); - } - } - } + Flow flowEntity = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE, + getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop")); - /** - * Returns the bucket info with the given interface as the only bucket. - */ - private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) { - return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart, - MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP); + mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity); } - private List buildMatchesForVni(Long vni) { + private static List buildMatchesForVni(Uint64 vni) { List mkMatches = new ArrayList<>(); - MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni)); + MatchInfo match = new MatchTunnelId(vni); mkMatches.add(match); return mkMatches; } - private List getInstructionsForOutGroup(long groupId) { + private static List getInstructionsForOutGroup(long groupId) { List mkInstructions = new ArrayList<>(); mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId)))); return mkInstructions; } - private List getMatchesForElanTag(long elanTag, boolean isSHFlagSet) { + private static List getMatchesForElanTag(long elanTag, boolean isSHFlagSet) { List mkMatches = new ArrayList<>(); // Matching metadata mkMatches.add(new MatchMetadata( @@ -1021,10 +1122,10 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase getInstructionsIntOrExtTunnelTable(Long elanTag) { + private static List getInstructionsIntOrExtTunnelTable(Uint32 elanTag) { List mkInstructions = new ArrayList<>(); - mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper - .getElanMetadataMask())); + mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()), + ElanHelper.getElanMetadataMask())); /* applicable for EXTERNAL_TUNNEL_TABLE only * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning */ @@ -1034,28 +1135,30 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo, - BigInteger dstDpId) throws ElanException { + Uint64 dstDpId) { String interfaceName = interfaceInfo.getInterfaceName(); ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName); if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) { List macEntries = elanInterfaceMac.getMacEntry(); - WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction(); - for (MacEntry macEntry : macEntries) { - String macAddress = macEntry.getMacAddress().getValue(); - LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress, interfaceName); - synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress, - interfaceInfo.getDpId())) { - LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation", macAddress); - elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, - writeFlowTx); - } - } - return Collections.singletonList(ElanUtils.waitForTransactionToComplete(writeFlowTx)); + return Collections.singletonList(ElanUtils.waitForTransactionToComplete( + txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { + for (MacEntry macEntry : macEntries) { + String macAddress = macEntry.getMacAddress().getValue(); + LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress, + interfaceName); + try (Acquired lock = ElanUtils.lockElanMacDPN(elanInfo.getElanTag().toJava(), macAddress, + interfaceInfo.getDpId())) { + LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation", + macAddress); + elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx); + } + } + }))); } - return Collections.emptyList(); + return emptyList(); } - private void createDropBucket(List listBucket) { + private static void createDropBucket(List listBucket) { List actionsInfos = new ArrayList<>(); actionsInfos.add(new ActionDrop().buildAction()); Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT, @@ -1063,20 +1166,25 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase confTx) { + if (!isOperational(interfaceInfo)) { + EVENT_LOGGER.debug("ELAN-LBG, ADD {} Instance {} Interface Status {}, returning", + interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName(), interfaceInfo.getOpState()); + return; + } + setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx); + setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx); } - public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface, - InterfaceInfo interfaceInfo) { + private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface, + InterfaceInfo interfaceInfo, TypedWriteTransaction confTx) { List listBucket = new ArrayList<>(); int bucketId = 0; - long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag()); + long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag().toJava()); List interfaces = new ArrayList<>(); - if (newDpnInterface != null) { + if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) { interfaces = newDpnInterface.getInterfaces(); } for (String ifName : interfaces) { @@ -1098,18 +1206,18 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase confTx) { + EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class); if (etreeInstance != null) { List listBucket = new ArrayList<>(); int bucketId = 0; List interfaces = new ArrayList<>(); - if (newDpnInterface != null) { + if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) { interfaces = newDpnInterface.getInterfaces(); } for (String ifName : interfaces) { @@ -1132,12 +1240,12 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase listBuckets = new ArrayList<>(); - int bucketId = 0; - listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId)); - // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1, - // interfaceInfo)); - Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, - MDSALUtil.buildBucketLists(listBuckets)); - LOG.trace("deleted the localBroadCast Group:{}", group); - mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx); + TypedReadWriteTransaction deleteFlowGroupTx) + throws ExecutionException, InterruptedException { + Uint64 dpnId = interfaceInfo.getDpId(); + long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag().toJava()); + LOG.trace("deleted the localBroadCast Group:{}", groupId); + mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId); } public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo, - WriteTransaction deleteFlowGroupTx) { - int bucketId = 0; - int actionKey = 0; - Long elanTag = elanInfo.getElanTag(); - List listBuckets = new ArrayList<>(); - List listAction = new ArrayList<>(); - listAction.add(new ActionGroup(++actionKey, ElanUtils.getElanLocalBCGId(elanTag)).buildAction()); - listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, - MDSALUtil.WATCH_GROUP)); - bucketId++; - listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanTag)); - BigInteger dpnId = interfaceInfo.getDpId(); - long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag()); - Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, - MDSALUtil.buildBucketLists(listBuckets)); - LOG.trace("deleting the remoteBroadCast group:{}", group); - mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx); + TypedReadWriteTransaction deleteFlowGroupTx) + throws ExecutionException, InterruptedException { + Uint64 dpnId = interfaceInfo.getDpId(); + long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag().toJava()); + LOG.trace("deleting the remoteBroadCast group:{}", groupId); + mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId); } /** * Installs a flow in the External Tunnel table consisting in translating * the VNI retrieved from the packet that came over a tunnel with a TOR into * elanTag that will be used later in the ELANs pipeline. - * - * @param dpnId - * the dpn id - * @param elanInfo - * the elan info + * @param dpnId the dpn id */ - public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) { - long elanTag = elanInfo.getElanTag(); + private void setExternalTunnelTable(Uint64 dpnId, ElanInstance elanInfo, + TypedWriteTransaction confTx) { + Uint32 elanTag = elanInfo.getElanTag(); FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE, - getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio + getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag.longValue()), 5, // prio elanInfo.getElanInstanceName(), // flowName 0, // idleTimeout 0, // hardTimeout - ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)), - buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)), + Uint64.valueOf(ITMConstants.COOKIE_ITM_EXTERNAL.toJava().add(BigInteger.valueOf(elanTag.longValue()))), + buildMatchesForVni(Uint64.valueOf(ElanUtils.getVxlanSegmentationId(elanInfo).longValue())), getInstructionsIntOrExtTunnelTable(elanTag)); - mdsalManager.installFlow(flowEntity); + mdsalManager.addFlow(confTx, flowEntity); } /** @@ -1216,126 +1304,136 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase confTx) throws ExecutionException, InterruptedException { // TODO: Use DataStoreJobCoordinator in order to avoid that removing the // last ElanInstance plus // adding a new one does (almost at the same time) are executed in that // exact order - String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag()); + String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag().toJava()); FlowEntity flowEntity = new FlowEntityBuilder() .setDpnId(dpnId) .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE) .setFlowId(flowId) .build(); - mdsalManager.removeFlow(flowEntity); + mdsalManager.removeFlow(confTx, flowEntity); } - public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) { + public void setupTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId, + TypedWriteTransaction writeFlowGroupTx) { setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx); setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx); } - public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag, - WriteTransaction writeFlowGroupTx) { + public void setupTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId, Uint32 elanTag, + TypedWriteTransaction writeFlowGroupTx) { List listMatchInfoBase; List instructionInfos; - long serviceId; + Uint32 serviceId; if (!elanUtils.isOpenstackVniSemanticsEnforced()) { serviceId = elanTag; - listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag); - instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)); + listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId(elanTag); + instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag.longValue())); } else { - serviceId = elanUtils.getVxlanSegmentationId(elanInfo); - listMatchInfoBase = buildMatchesForVni(serviceId); + serviceId = ElanUtils.getVxlanSegmentationId(elanInfo); + listMatchInfoBase = buildMatchesForVni(Uint64.valueOf(serviceId)); instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag); } FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, - getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ", - elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase, - instructionInfos); - mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx); - } - - private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, - WriteTransaction writeFlowGroupTx) { - EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class); + getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId.longValue()), 5, + String.format("%s:%s", "ITM Flow Entry ", elanTag.toString()), 0, 0, + Uint64.valueOf(ITMConstants.COOKIE_ITM.toJava().add(BigInteger.valueOf(elanTag.longValue()))), + listMatchInfoBase, instructionInfos); + mdsalManager.addFlow(writeFlowGroupTx, flowEntity); + LOG.info("Installed internal tunnel table (36) flow entry on dpn: {} for elan: {}, tag: {}", dpId, + elanInfo.getElanInstanceName(), elanTag); + } + + private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId, + TypedWriteTransaction writeFlowGroupTx) { + EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class); if (etreeInstance != null) { - setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx); + setupTerminateServiceTable(elanInfo, dpId, + etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx); } } - public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) { - long elanTag = elanInfo.getElanTag(); + public void setupUnknownDMacTable(ElanInstance elanInfo, Uint64 dpId, + TypedWriteTransaction writeFlowGroupTx) { + long elanTag = elanInfo.getElanTag().toJava(); installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx); installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx); setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx); } - private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag, - WriteTransaction writeFlowGroupTx) { + private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, Uint64 dpId, long elanTag, + TypedWriteTransaction writeFlowGroupTx) { EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); if (etreeLeafTag != null) { - long leafTag = etreeLeafTag.getEtreeLeafTag().getValue(); + long leafTag = etreeLeafTag.getEtreeLeafTag().getValue().toJava(); installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx); installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx); } } - private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag, - WriteTransaction writeFlowGroupTx) { + private void installLocalUnknownFlow(ElanInstance elanInfo, Uint64 dpId, long elanTag, + TypedWriteTransaction writeFlowGroupTx) { FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE, getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false), 5, elanInfo.getElanInstanceName(), 0, 0, - ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), + Uint64.valueOf(ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))), getMatchesForElanTag(elanTag, /* SH flag */false), getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag))); - mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx); + mdsalManager.addFlow(writeFlowGroupTx, flowEntity); + LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan: {}, tag: {}", + dpId, elanInfo.getElanInstanceName(), elanTag); } - private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag, - WriteTransaction writeFlowGroupTx) { + private void installRemoteUnknownFlow(ElanInstance elanInfo, Uint64 dpId, long elanTag, + TypedWriteTransaction writeFlowGroupTx) { // only if ELAN can connect to external network, perform the following if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) { FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE, getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true), 5, elanInfo.getElanInstanceName(), 0, 0, - ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), + Uint64.valueOf(ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))), getMatchesForElanTag(elanTag, /* SH flag */true), getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag))); - mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx); + mdsalManager.addFlow(writeFlowGroupTx, flowEntity); + LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan connected to " + + "external network: {}, tag: {}", dpId, elanInfo.getElanInstanceName(), elanTag); } } - private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx, - long elanTag) { + private void removeUnknownDmacFlow(Uint64 dpId, ElanInstance elanInfo, + TypedReadWriteTransaction deleteFlowGroupTx, long elanTag) + throws ExecutionException, InterruptedException { Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build(); - mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx); + mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow); if (isVxlanNetworkOrVxlanSegment(elanInfo)) { Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE) .build(); - mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx); + mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2); } } - private void removeDefaultTermFlow(BigInteger dpId, long elanTag) { + private void removeDefaultTermFlow(Uint64 dpId, long elanTag) { elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag); } - private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, WriteTransaction tx) { + private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, + TypedWriteTransaction tx) { if (isStandardElanService(elanInterface)) { - bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), + bindElanService(elanInfo.getElanTag().toJava(), elanInfo.getElanInstanceName(), elanInterface.getName(), lportTag, tx); } else { // Etree service bindEtreeService(elanInfo, elanInterface, lportTag, tx); @@ -1343,7 +1441,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase tx) { int instructionKey = 0; List instructions = new ArrayList<>(); instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag), @@ -1367,70 +1465,72 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION, bindServiceId); if (!existingElanService.isPresent()) { - tx.put(LogicalDatastoreType.CONFIGURATION, bindServiceId, serviceInfo, - WriteTransaction.CREATE_MISSING_PARENTS); + tx.put(bindServiceId, serviceInfo, CREATE_MISSING_PARENTS); + LOG.trace("Done binding elan service for elan: {} for interface: {}", elanInstanceName, interfaceName); } } private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, - WriteTransaction tx) { - if (elanInterface.getAugmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) { - bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(), + TypedWriteTransaction tx) { + if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) { + bindElanService(elanInfo.getElanTag().toJava(), elanInfo.getElanInstanceName(), elanInterface.getName(), lportTag, tx); } else { - EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class); + EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class); if (etreeInstance == null) { LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}", elanInterface.getName(), elanInfo.getElanInstanceName()); } else { - bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(), + bindElanService(etreeInstance.getEtreeLeafTagVal().getValue().toJava(), elanInfo.getElanInstanceName(), elanInterface.getName(), lportTag, tx); } } } - private boolean isStandardElanService(ElanInterface elanInterface) { - return elanInterface.getAugmentation(EtreeInterface.class) == null; + private static boolean isStandardElanService(ElanInterface elanInterface) { + return elanInterface.augmentation(EtreeInterface.class) == null; } - protected void unbindService(String interfaceName, ReadWriteTransaction tx) throws ReadFailedException { + protected void unbindService(String interfaceName, TypedReadWriteTransaction tx) + throws ExecutionException, InterruptedException { short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX); InstanceIdentifier bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex); - if (tx.read(LogicalDatastoreType.CONFIGURATION, bindServiceId).checkedGet().isPresent()) { - tx.delete(LogicalDatastoreType.CONFIGURATION, bindServiceId); + if (tx.read(bindServiceId).get().isPresent()) { + tx.delete(bindServiceId); } } - private String getFlowRef(long tableId, long elanTag) { + private static String getFlowRef(long tableId, long elanTag) { return String.valueOf(tableId) + elanTag; } - private String getFlowRef(long tableId, long elanTag, String flowName) { - return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag) + private static String getFlowRef(long tableId, long elanTag, String flowName) { + return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag) .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString(); } - private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) { + private static String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) { return String.valueOf(tableId) + elanTag + shFlag; } - private List getInterfacePortActions(InterfaceInfo interfaceInfo) { + private static List getInterfacePortActions(InterfaceInfo interfaceInfo) { List listAction = new ArrayList<>(); int actionKey = 0; listAction.add( - new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey)); + new ActionSetFieldTunnelId(Uint64.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey)); actionKey++; listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey)); return listAction; } - private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId, - List interfaceNames, WriteTransaction tx) { + private static DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, Uint64 dpId, + List interfaceNames, TypedWriteTransaction tx) { DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames) - .setKey(new DpnInterfacesKey(dpId)).build(); - tx.put(LogicalDatastoreType.OPERATIONAL, - ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface, - WriteTransaction.CREATE_MISSING_PARENTS); + .withKey(new DpnInterfacesKey(dpId)).build(); + tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface, + CREATE_MISSING_PARENTS); + LOG.trace("Updated operational dpn interfaces for elan: {} with interfaces: {}", elanInstanceName, + interfaceNames); return dpnInterface; } @@ -1442,89 +1542,70 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase tx) throws ExecutionException, InterruptedException { InstanceIdentifier dpnInterfacesId = ElanUtils .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId); - Optional dpnInterfaces = ElanUtils.read(broker, - LogicalDatastoreType.OPERATIONAL, dpnInterfacesId); + Optional dpnInterfaces = tx.read(dpnInterfacesId).get(); if (dpnInterfaces.isPresent()) { - tx.delete(LogicalDatastoreType.OPERATIONAL, dpnInterfacesId); + tx.delete(dpnInterfacesId); } } - private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId, - WriteTransaction tx) { + private static DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, + Uint64 dpId, TypedWriteTransaction tx) { List interfaceNames = new ArrayList<>(); interfaceNames.add(interfaceName); DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames) - .setKey(new DpnInterfacesKey(dpId)).build(); - tx.put(LogicalDatastoreType.OPERATIONAL, - ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface, - WriteTransaction.CREATE_MISSING_PARENTS); + .withKey(new DpnInterfacesKey(dpId)).build(); return dpnInterface; } - private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) { - InstanceIdentifier elanInterfaceMacTables = ElanUtils - .getElanInterfaceMacEntriesOperationalDataPath(interfaceName); - Optional interfaceMacTables = ElanUtils.read(broker, - LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables); - // Adding new Elan Interface Port to the operational DataStore without - // Static-Mac Entries.. - if (!interfaceMacTables.isPresent()) { - ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName) - .setKey(new ElanInterfaceMacKey(interfaceName)).build(); - tx.put(LogicalDatastoreType.OPERATIONAL, - ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable, - WriteTransaction.CREATE_MISSING_PARENTS); - } - } - - private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) { + private static void createElanStateList(String elanInstanceName, String interfaceName, + TypedReadWriteTransaction tx) throws ExecutionException, InterruptedException { InstanceIdentifier elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName); - Optional elanInterfaceLists = ElanUtils.read(broker, - LogicalDatastoreType.OPERATIONAL, elanInstance); + Optional elanInterfaceLists = tx.read(elanInstance).get(); // Adding new Elan Interface Port to the operational DataStore without // Static-Mac Entries.. if (elanInterfaceLists.isPresent()) { - List interfaceLists = elanInterfaceLists.get().getElanInterfaces(); - if (interfaceLists == null) { - interfaceLists = new ArrayList<>(); - } + List interfaceLists = new ArrayList<>(); interfaceLists.add(interfaceName); + List existingInterfaceLists = elanInterfaceLists.get().getElanInterfaces(); + if (existingInterfaceLists != null && !existingInterfaceLists.isEmpty()) { + existingInterfaceLists.forEach(iface -> interfaceLists.add(iface)); + } + Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists) - .setKey(new ElanKey(elanInstanceName)).build(); - tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), - elanState, WriteTransaction.CREATE_MISSING_PARENTS); + .withKey(new ElanKey(elanInstanceName)).build(); + tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, CREATE_MISSING_PARENTS); + LOG.trace("Updated operational elan state for elan: {} with interfaces: {}", elanInstanceName, + interfaceLists); } } - private boolean isOperational(InterfaceInfo interfaceInfo) { - if (interfaceInfo == null) { - return false; - } - return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED; + private static boolean isOperational(InterfaceInfo interfaceInfo) { + return interfaceInfo != null && interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED; } @SuppressWarnings("checkstyle:IllegalCatch") - public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) { + public void handleInternalTunnelStateEvent(Uint64 srcDpId, Uint64 dstDpId) { ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList(); LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}" + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists); if (dpnInterfaceLists == null) { return; } - List elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList(); + List elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList(); for (ElanDpnInterfacesList elanDpns : elanDpnIf) { int cnt = 0; String elanName = elanDpns.getElanInstanceName(); - ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull(); + ElanInstance elanInfo = elanInstanceCache.get(elanName).orElse(null); if (elanInfo == null) { LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, " + "skipping this ELAN for tunnel handling", elanName); continue; } - if (ElanUtils.isFlat(elanInfo) || ElanUtils.isVlan(elanInfo)) { + if (!isVxlanNetworkOrVxlanSegment(elanInfo)) { LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName); continue; } @@ -1534,10 +1615,10 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId, + confTx)).get(); } catch (RuntimeException e) { LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId); } @@ -1562,10 +1645,10 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList(); + List elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList(); for (ElanDpnInterfacesList elanDpns : elanDpnIf) { String elanName = elanDpns.getElanInstanceName(); - ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull(); + ElanInstance elanInfo = elanInstanceCache.get(elanName).orElse(null); DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId); if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null @@ -1617,7 +1699,10 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG, + "Error setting up ELAN BGs"); // install L2gwDevices local macs in dpn. elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName()); // Install dpn macs on external device @@ -1643,7 +1728,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase lstElanInterfaceNames, BigInteger dpnId, + private void installDpnMacsInL2gwDevice(String elanName, Set lstElanInterfaceNames, Uint64 dpnId, NodeId externalNodeId) { L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, externalNodeId.getValue()); @@ -1665,7 +1750,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames); if (phyLocAlreadyExists) { @@ -1707,24 +1792,21 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase getMatchesForFilterEqualsLPortTag(int lportTag) { + private static List getMatchesForFilterEqualsLPortTag(int lportTag) { List mkMatches = new ArrayList<>(); // Matching metadata mkMatches.add( new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG)); - mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag))); + mkMatches.add(new MatchTunnelId(Uint64.valueOf(lportTag))); return mkMatches; } - @Override - protected ElanInterfaceManager getDataTreeChangeListener() { - return this; - } - public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces, - BigInteger dpId) { + Uint64 dpId) { LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName()); - elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId); + addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, + confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId, + confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName()); try { Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL); } catch (InterruptedException e) {