X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=elanmanager%2Fimpl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetvirt%2Felan%2Futils%2FElanUtils.java;h=975c12d8806cf10401f5469e8dfae825619c7794;hb=cf1ea9172b94fc17e45391b62bf4ca24ac5c5fe0;hp=7d1888b7f5f06ed5c2aedd892c6b51bdc539b52f;hpb=82fc8f6178fa492fc7aa52219a56f85f78316492;p=netvirt.git diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java index 7d1888b7f5..975c12d880 100755 --- a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java +++ b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java @@ -7,40 +7,55 @@ */ package org.opendaylight.netvirt.elan.utils; -import com.google.common.base.Optional; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.opendaylight.genius.infra.Datastore.CONFIGURATION; + import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.primitives.Ints; -import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import edu.umd.cs.findbugs.annotations.CheckReturnValue; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Singleton; import org.apache.commons.lang3.StringUtils; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; -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.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker; +import org.opendaylight.genius.infra.Datastore; +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.TypedReadTransaction; +import org.opendaylight.genius.infra.TypedReadWriteTransaction; +import org.opendaylight.genius.infra.TypedWriteTransaction; import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo; -import org.opendaylight.genius.interfacemanager.globals.InterfaceServiceUtil; import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; +import org.opendaylight.genius.itm.api.IITMProvider; import org.opendaylight.genius.itm.globals.ITMConstants; import org.opendaylight.genius.mdsalutil.ActionInfo; import org.opendaylight.genius.mdsalutil.FlowEntity; @@ -62,11 +77,18 @@ import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId; import org.opendaylight.genius.mdsalutil.packet.ARP; import org.opendaylight.genius.mdsalutil.packet.Ethernet; import org.opendaylight.genius.mdsalutil.packet.IPv4; -import org.opendaylight.infrautils.utils.concurrent.JdkFutures; -import org.opendaylight.infrautils.utils.concurrent.ListenableFutures; -import org.opendaylight.netvirt.elan.ElanException; +import org.opendaylight.infrautils.utils.concurrent.LoggingFutures; +import org.opendaylight.infrautils.utils.concurrent.NamedLocks; +import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.ReadTransaction; +import org.opendaylight.mdsal.binding.api.WriteTransaction; +import org.opendaylight.mdsal.common.api.CommitInfo; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.mdsal.common.api.TransactionCommitFailedException; import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil; import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache; +import org.opendaylight.netvirt.elan.internal.ElanGroupCache; import org.opendaylight.netvirt.elanmanager.api.ElanHelper; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder; @@ -84,6 +106,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput; @@ -118,6 +141,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.I import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId; +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; +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.group.buckets.BucketBuilder; +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.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; @@ -133,7 +164,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev16061 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagNameBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaceForwardingEntries; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanState; @@ -153,6 +183,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegments; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegmentsKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries; @@ -172,13 +203,45 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.Uint32; +import org.opendaylight.yangtools.yang.common.Uint64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class ElanUtils { + private static final class ElanLockName { + private final String macAddress; + private final Uint64 dpnId; + private final long elanTag; + + ElanLockName(long elanTag, String macAddress, Uint64 dpnId) { + this.elanTag = elanTag; + this.macAddress = macAddress; + this.dpnId = dpnId; + } + + @Override + public int hashCode() { + return 31 * Long.hashCode(elanTag) + Objects.hash(macAddress, dpnId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ElanLockName)) { + return false; + } + final ElanLockName other = (ElanLockName) obj; + return elanTag == other.elanTag && Objects.equals(macAddress, other.macAddress) + && Objects.equals(dpnId, other.dpnId); + } + } private static final Logger LOG = LoggerFactory.getLogger(ElanUtils.class); + private static final NamedLocks ELAN_LOCKS = new NamedLocks<>(); private final DataBroker broker; private final ManagedNewTransactionRunner txRunner; @@ -190,10 +253,21 @@ public class ElanUtils { private final ElanItmUtils elanItmUtils; private final ElanEtreeUtils elanEtreeUtils; private final ElanInterfaceCache elanInterfaceCache; + private final IITMProvider iitmProvider; + private final ElanGroupCache elanGroupCache; + + private static final Function TO_BUCKET_WITHOUT_ID = (bucket) -> new BucketBuilder(bucket) + .setBucketId(new BucketId(0L)) + .build(); + + private static final BiFunction TO_BUCKET_WITH_ID = (bucket, id) + -> new BucketBuilder(bucket) + .setBucketId(new BucketId(id.incrementAndGet())) + .build(); - public static final FutureCallback DEFAULT_CALLBACK = new FutureCallback() { + public static final FutureCallback DEFAULT_CALLBACK = new FutureCallback() { @Override - public void onSuccess(Void result) { + public void onSuccess(CommitInfo result) { LOG.debug("Success in Datastore operation"); } @@ -207,7 +281,7 @@ public class ElanUtils { public ElanUtils(DataBroker dataBroker, IMdsalApiManager mdsalManager, OdlInterfaceRpcService interfaceManagerRpcService, ItmRpcService itmRpcService, ElanConfig elanConfig, IInterfaceManager interfaceManager, ElanEtreeUtils elanEtreeUtils, ElanItmUtils elanItmUtils, - ElanInterfaceCache elanInterfaceCache) { + ElanInterfaceCache elanInterfaceCache, IITMProvider iitmProvider, ElanGroupCache elanGroupCache) { this.broker = dataBroker; this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker); this.mdsalManager = mdsalManager; @@ -218,6 +292,8 @@ public class ElanUtils { this.elanEtreeUtils = elanEtreeUtils; this.elanItmUtils = elanItmUtils; this.elanInterfaceCache = elanInterfaceCache; + this.iitmProvider = iitmProvider; + this.elanGroupCache = elanGroupCache; } public final Boolean isOpenstackVniSemanticsEnforced() { @@ -234,7 +310,7 @@ public class ElanUtils { * the id key * @return the integer */ - public static Long retrieveNewElanTag(IdManagerService idManager, String idKey) { + public static Uint32 retrieveNewElanTag(IdManagerService idManager, String idKey) { AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME) .setIdKey(idKey).build(); @@ -250,12 +326,12 @@ public class ElanUtils { } catch (InterruptedException | ExecutionException e) { LOG.warn("Exception when Allocating Id", e); } - return 0L; + return Uint32.valueOf(0L); } public static void releaseId(IdManagerService idManager, String poolName, String idKey) { ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build(); - JdkFutures.addErrorLogging(idManager.releaseId(releaseIdInput), LOG, "Release Id"); + LoggingFutures.addErrorLogging(idManager.releaseId(releaseIdInput), LOG, "Release Id"); } /** @@ -271,41 +347,30 @@ public class ElanUtils { */ @Deprecated @SuppressWarnings("checkstyle:IllegalCatch") - public static Optional read(@Nonnull DataBroker broker, + public static Optional read(@NonNull DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier path) { - try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) { + try (ReadTransaction tx = broker.newReadOnlyTransaction()) { return tx.read(datastoreType, path).get(); - } catch (Exception e) { + } catch (ExecutionException | InterruptedException e) { throw new RuntimeException(e); } } public Optional read2(LogicalDatastoreType datastoreType, InstanceIdentifier path) - throws ReadFailedException { - try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) { - CheckedFuture, ReadFailedException> checkedFuture = tx.read(datastoreType, path); - return checkedFuture.checkedGet(); + throws InterruptedException, ExecutionException { + try (ReadTransaction tx = broker.newReadOnlyTransaction()) { + FluentFuture> checkedFuture = tx.read(datastoreType, path); + return checkedFuture.get(); } } - @SuppressWarnings("checkstyle:ForbiddenMethod") - public static void delete(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path) { - WriteTransaction tx = broker.newWriteOnlyTransaction(); - tx.delete(datastoreType, path); - Futures.addCallback(tx.submit(), DEFAULT_CALLBACK, MoreExecutors.directExecutor()); - } - - @SuppressWarnings("checkstyle:ForbiddenMethod") + @SuppressWarnings("checkstyle:ForbidCertainMethod") public static void delete(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path, FutureCallback callback) { + InstanceIdentifier path) { WriteTransaction tx = broker.newWriteOnlyTransaction(); tx.delete(datastoreType, path); - Futures.addCallback(tx.submit(), callback, MoreExecutors.directExecutor()); - } - - public static InstanceIdentifier getElanInstanceIdentifier() { - return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class).build(); + FluentFuture future = tx.commit(); + future.addCallback(DEFAULT_CALLBACK, MoreExecutors.directExecutor()); } public static InstanceIdentifier getElanInterfaceConfigurationDataPathId(String interfaceName) { @@ -314,15 +379,23 @@ public class ElanUtils { } // elan-state Operational container + @Nullable public static Elan getElanByName(DataBroker broker, String elanInstanceName) { InstanceIdentifier elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName); - return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).orNull(); + try { + return SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.OPERATIONAL, + elanIdentifier).orElse(null); + } catch (ExecutionException | InterruptedException e) { + LOG.error("getElanByName: Exception while reading elan-instance DS for the elan instance {}", + elanInstanceName, e); + return null; + } } @Nullable - public static Elan getElanByName(ReadTransaction tx, String elanInstanceName) throws ReadFailedException { - return tx.read(LogicalDatastoreType.OPERATIONAL, - getElanInstanceOperationalDataPath(elanInstanceName)).checkedGet().orNull(); + public static Elan getElanByName(TypedReadTransaction tx, String elanInstanceName) + throws ExecutionException, InterruptedException { + return tx.read(getElanInstanceOperationalDataPath(elanInstanceName)).get().orElse(null); } public static InstanceIdentifier getElanInstanceOperationalDataPath(String elanInstanceName) { @@ -330,16 +403,17 @@ public class ElanUtils { } // grouping of forwarding-entries + @Nullable public MacEntry getInterfaceMacEntriesOperationalDataPath(String interfaceName, PhysAddress physAddress) { InstanceIdentifier existingMacEntryId = getInterfaceMacEntriesIdentifierOperationalDataPath( interfaceName, physAddress); - return read(broker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId).orNull(); + return read(broker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId).orElse(null); } - public MacEntry getInterfaceMacEntriesOperationalDataPathFromId(InstanceIdentifier identifier) { - Optional existingInterfaceMacEntry = read(broker, - LogicalDatastoreType.OPERATIONAL, identifier); - return existingInterfaceMacEntry.orNull(); + @Nullable + public MacEntry getInterfaceMacEntriesOperationalDataPathFromId(TypedReadTransaction tx, + InstanceIdentifier identifier) throws ExecutionException, InterruptedException { + return tx.read(identifier).get().orElse(null); } public static InstanceIdentifier getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName, @@ -356,16 +430,16 @@ public class ElanUtils { return read(broker, LogicalDatastoreType.OPERATIONAL, macId); } - public Optional getMacEntryForElanInstance(ReadTransaction tx, String elanName, PhysAddress physAddress) - throws ReadFailedException { + public Optional getMacEntryForElanInstance(TypedReadTransaction tx, String elanName, + PhysAddress physAddress) throws ExecutionException, InterruptedException { InstanceIdentifier macId = getMacEntryOperationalDataPath(elanName, physAddress); - return tx.read(LogicalDatastoreType.OPERATIONAL, macId).checkedGet(); + return tx.read(macId).get(); } - public MacEntry getMacEntryFromElanMacId(InstanceIdentifier identifier) { - Optional existingInterfaceMacEntry = read(broker, - LogicalDatastoreType.OPERATIONAL, identifier); - return existingInterfaceMacEntry.orNull(); + @Nullable + public MacEntry getMacEntryFromElanMacId(TypedReadTransaction tx, + InstanceIdentifier identifier) throws ExecutionException, InterruptedException { + return tx.read(identifier).get().orElse(null); } public static InstanceIdentifier getMacEntryOperationalDataPath(String elanName, @@ -388,26 +462,7 @@ public class ElanUtils { public static ElanInterfaceMac getElanInterfaceMacByInterfaceName(DataBroker dataBroker, String interfaceName) { InstanceIdentifier elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath( interfaceName); - return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orNull(); - } - - /** - * Gets the elan interface mac addresses. - * - * @param interfaceName - * the interface name - * @return the elan interface mac addresses - */ - public List getElanInterfaceMacAddresses(String interfaceName) { - List macAddresses = new ArrayList<>(); - ElanInterfaceMac elanInterfaceMac = getElanInterfaceMacByInterfaceName(interfaceName); - if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) { - List macEntries = elanInterfaceMac.getMacEntry(); - for (MacEntry macEntry : macEntries) { - macAddresses.add(macEntry.getMacAddress()); - } - } - return macAddresses; + return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orElse(null); } public static InstanceIdentifier getElanInterfaceMacEntriesOperationalDataPath( @@ -418,7 +473,7 @@ public class ElanUtils { /** * Returns the list of Interfaces that belong to an Elan on an specific DPN. - * Data retrieved from Elan's operational DS: elan-dpn-interfaces container + * Data retrieved from Elan's operational DS: elan-dpn-interfaces container. * * @param elanInstanceName * name of the Elan to which the interfaces must belong to @@ -426,10 +481,11 @@ public class ElanUtils { * Id of the DPN where the interfaces are located * @return the elan interface Info */ - public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) { + @Nullable + public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, Uint64 dpId) { InstanceIdentifier elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId); - return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId).orNull(); + return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId).orElse(null); } /** @@ -444,34 +500,36 @@ public class ElanUtils { * @return the elan dpn interface */ public static InstanceIdentifier getElanDpnInterfaceOperationalDataPath(String elanInstanceName, - BigInteger dpId) { + Uint64 dpId) { return InstanceIdentifier.builder(ElanDpnInterfaces.class) .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)) .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build(); } // elan-tag-name-map Operational Container - public ElanTagName getElanInfoByElanTag(long elanTag) { + @Nullable + public ElanTagName getElanInfoByElanTag(Uint32 elanTag) { InstanceIdentifier elanId = getElanInfoEntriesOperationalDataPath(elanTag); Optional existingElanInfo = read(broker, LogicalDatastoreType.OPERATIONAL, elanId); - return existingElanInfo.orNull(); + return existingElanInfo.orElse(null); } - public static InstanceIdentifier getElanInfoEntriesOperationalDataPath(long elanTag) { + public static InstanceIdentifier getElanInfoEntriesOperationalDataPath(Uint32 elanTag) { return InstanceIdentifier.builder(ElanTagNameMap.class).child(ElanTagName.class, new ElanTagNameKey(elanTag)) .build(); } // interface-index-tag operational container - public Optional getInterfaceInfoByInterfaceTag(long interfaceTag) { + public Optional getInterfaceInfoByInterfaceTag(Uint32 interfaceTag) { InstanceIdentifier interfaceId = getInterfaceInfoEntriesOperationalDataPath(interfaceTag); return read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId); } - public static InstanceIdentifier getInterfaceInfoEntriesOperationalDataPath(long interfaceTag) { + public static InstanceIdentifier getInterfaceInfoEntriesOperationalDataPath(Uint32 interfaceTag) { return InstanceIdentifier.builder(IfIndexesInterfaceMap.class) - .child(IfIndexInterface.class, new IfIndexInterfaceKey((int) interfaceTag)).build(); + .child(IfIndexInterface.class, + new IfIndexInterfaceKey(Integer.valueOf(interfaceTag.intValue()))).build(); } public static InstanceIdentifier getElanDpnOperationDataPath(String elanInstanceName) { @@ -479,15 +537,17 @@ public class ElanUtils { .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build(); } + @Nullable public ElanDpnInterfacesList getElanDpnInterfacesList(String elanName) { InstanceIdentifier elanDpnInterfaceId = getElanDpnOperationDataPath(elanName); - return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull(); + return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orElse(null); } + @Nullable public ElanDpnInterfaces getElanDpnInterfacesList() { InstanceIdentifier elanDpnInterfaceId = InstanceIdentifier.builder(ElanDpnInterfaces.class) .build(); - return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull(); + return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orElse(null); } /** @@ -499,55 +559,22 @@ public class ElanUtils { * the elan instance name * @return list of dpIds */ - @Nonnull - public List getParticipatingDpnsInElanInstance(String elanInstanceName) { - List dpIds = new ArrayList<>(); + @NonNull + public List getParticipatingDpnsInElanInstance(String elanInstanceName) { + List dpIds = new ArrayList<>(); InstanceIdentifier elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName); Optional existingElanDpnInterfaces = read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId); if (!existingElanDpnInterfaces.isPresent()) { return dpIds; } - List dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces(); - for (DpnInterfaces dpnInterface : dpnInterfaces) { + Map dpnInterfaces = existingElanDpnInterfaces.get().nonnullDpnInterfaces(); + for (DpnInterfaces dpnInterface : dpnInterfaces.values()) { dpIds.add(dpnInterface.getDpId()); } return dpIds; } - /** - * To check given dpId is already present in Elan instance. This can be used - * to program flow entry in external tunnel table when a new access port - * added for first time into the ELAN instance - * - * @param dpId - * the dp id - * @param elanInstanceName - * the elan instance name - * @return true if dpId is already present, otherwise return false - */ - public boolean isDpnAlreadyPresentInElanInstance(BigInteger dpId, String elanInstanceName) { - InstanceIdentifier elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName); - Optional existingElanDpnInterfaces = read(broker, - LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId); - if (!existingElanDpnInterfaces.isPresent()) { - return false; - } - List dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces(); - for (DpnInterfaces dpnInterface : dpnInterfaces) { - if (dpnInterface.getDpId().equals(dpId)) { - return true; - } - } - return false; - } - - public ElanForwardingTables getElanForwardingList() { - InstanceIdentifier elanForwardingTableId = InstanceIdentifier - .builder(ElanForwardingTables.class).build(); - return read(broker, LogicalDatastoreType.OPERATIONAL, elanForwardingTableId).orNull(); - } - public static long getElanRemoteBroadCastGroupID(long elanTag) { return ElanConstants.ELAN_GID_MIN + elanTag % ElanConstants.ELAN_GID_MIN * 2; } @@ -559,6 +586,7 @@ public class ElanUtils { * the elan name * @return the elan mac table */ + @Nullable public MacTable getElanMacTable(String elanName) { return getElanMacTable(broker, elanName); } @@ -566,7 +594,7 @@ public class ElanUtils { @Nullable public static MacTable getElanMacTable(DataBroker dataBroker, String elanName) { InstanceIdentifier elanMacTableId = getElanMacTableOperationalDataPath(elanName); - return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanMacTableId).orNull(); + return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanMacTableId).orElse(null); } public static long getElanLocalBCGId(long elanTag) { @@ -585,9 +613,9 @@ public class ElanUtils { return ElanConstants.ELAN_GID_MIN + etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2; } - public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet) { + public static Uint64 getElanMetadataLabel(long elanTag, boolean isSHFlagSet) { int shBit = isSHFlagSet ? 1 : 0; - return BigInteger.valueOf(elanTag).shiftLeft(24).or(BigInteger.valueOf(shBit)); + return Uint64.valueOf(BigInteger.valueOf(elanTag).shiftLeft(24).or(BigInteger.valueOf(shBit))); } /** @@ -605,12 +633,11 @@ public class ElanUtils { * true if remote dmac flows should be configured as well * @param writeFlowGroupTx * the flow group tx - * @throws ElanException in case of issues creating the flow objects */ public void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout, String macAddress, boolean configureRemoteFlows, - WriteTransaction writeFlowGroupTx) throws ElanException { - synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) { + TypedWriteTransaction writeFlowGroupTx) { + try (Acquired lock = lockElanMacDPN(elanInfo.getElanTag().toJava(), macAddress, interfaceInfo.getDpId())) { setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalManager, writeFlowGroupTx); setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, configureRemoteFlows, mdsalManager, @@ -618,11 +645,12 @@ public class ElanUtils { } } - public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId, - String macAddress, WriteTransaction writeFlowTx) throws ElanException { + public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, Uint64 dstDpId, + String macAddress, TypedWriteTransaction writeFlowTx) { String elanInstanceName = elanInfo.getElanInstanceName(); - setupRemoteDmacFlow(dstDpId, interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag(), elanInfo.getElanTag(), - macAddress, elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName(), elanInfo); + setupRemoteDmacFlow(dstDpId, interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag(), + elanInfo.getElanTag(), macAddress, elanInstanceName, writeFlowTx, + interfaceInfo.getInterfaceName(), elanInfo); LOG.info("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and" + " mac address {} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId); @@ -633,9 +661,10 @@ public class ElanUtils { * learnt. */ private void setupKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout, - String macAddress, IMdsalApiManager mdsalApiManager, WriteTransaction writeFlowGroupTx) { + String macAddress, IMdsalApiManager mdsalApiManager, + TypedWriteTransaction writeFlowGroupTx) { FlowEntity flowEntity = buildKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress); - mdsalApiManager.addFlowToTx(flowEntity, writeFlowGroupTx); + mdsalApiManager.addFlow(writeFlowGroupTx, flowEntity); LOG.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}", elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress); } @@ -645,22 +674,22 @@ public class ElanUtils { int lportTag = interfaceInfo.getInterfaceTag(); // Matching metadata and eth_src fields List mkMatches = new ArrayList<>(); - mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanInfo.getElanTag(), lportTag), + mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanInfo.getElanTag().toJava(), lportTag), ElanHelper.getElanMetadataMask())); mkMatches.add(new MatchEthernetSource(new MacAddress(macAddress))); List mkInstructions = new ArrayList<>(); mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE)); - BigInteger dpId = interfaceInfo.getDpId(); - long elanTag = getElanTag(elanInfo, interfaceInfo); + Uint64 dpId = interfaceInfo.getDpId(); + Uint32 elanTag = getElanTag(elanInfo, interfaceInfo); return new FlowEntityBuilder() .setDpnId(dpId) .setTableId(NwConstants.ELAN_SMAC_TABLE) - .setFlowId(getKnownDynamicmacFlowRef(NwConstants.ELAN_SMAC_TABLE, dpId, lportTag, macAddress, elanTag)) + .setFlowId(getKnownDynamicmacFlowRef(elanTag, macAddress)) .setPriority(20) .setFlowName(elanInfo.getDescription()) .setIdleTimeOut((int) macTimeout) .setHardTimeOut(0) - .setCookie(ElanConstants.COOKIE_ELAN_KNOWN_SMAC.add(BigInteger.valueOf(elanTag))) + .setCookie(Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_SMAC.longValue() + elanTag.longValue())) .setMatchInfoList(mkMatches) .setInstructionInfoList(mkInstructions) .setStrictFlag(true) @@ -669,8 +698,9 @@ public class ElanUtils { .build(); } - private Long getElanTag(ElanInstance elanInfo, InterfaceInfo interfaceInfo) { - EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceInfo.getInterfaceName()).orNull(); + private Uint32 getElanTag(ElanInstance elanInfo, InterfaceInfo interfaceInfo) { + EtreeInterface etreeInterface = elanInterfaceCache + .getEtreeInterface(interfaceInfo.getInterfaceName()).orElse(null); if (etreeInterface == null || etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) { return elanInfo.getElanTag(); } else { // Leaf @@ -698,16 +728,16 @@ public class ElanUtils { * the writeFLowGroup tx */ public void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager, - WriteTransaction writeFlowGroupTx) { - BigInteger dpId = interfaceInfo.getDpId(); + TypedWriteTransaction writeFlowGroupTx) { + Uint64 dpId = interfaceInfo.getDpId(); int lportTag = interfaceInfo.getInterfaceTag(); Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, getIntTunnelTableFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, lportTag), 5, String.format("%s:%d", "ITM Flow Entry ", lportTag), 0, 0, - ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(lportTag)), + Uint64.valueOf(ITMConstants.COOKIE_ITM.longValue() + lportTag), getTunnelIdMatchForFilterEqualsLPortTag(lportTag), getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName())); - mdsalApiManager.addFlowToTx(dpId, flow, writeFlowGroupTx); + mdsalApiManager.addFlow(writeFlowGroupTx, dpId, flow); LOG.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}", dpId, interfaceInfo.getPortName()); } @@ -723,7 +753,7 @@ public class ElanUtils { * @return the Internal tunnel */ public static String getIntTunnelTableFlowRef(short tableId, int elanTag) { - return new StringBuffer().append(tableId).append(elanTag).toString(); + return new StringBuilder().append(tableId).append(elanTag).toString(); } /** @@ -737,7 +767,7 @@ public class ElanUtils { public static List getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) { List mkMatches = new ArrayList<>(); // Matching metadata - mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag))); + mkMatches.add(new MatchTunnelId(Uint64.valueOf(lportTag))); return mkMatches; } @@ -750,11 +780,12 @@ public class ElanUtils { * external) * @return the Instruction */ - public List getInstructionsInPortForOutGroup(String ifName) { - List mkInstructions = new ArrayList<>(); + public Map getInstructionsInPortForOutGroup(String ifName) { + int instructionsKey = 0; + Map mkInstructions = new HashMap<>(); List actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null); - mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); + mkInstructions.put(new InstructionKey(++instructionsKey), MDSALUtil.buildApplyActionsInstruction(actions)); return mkInstructions; } @@ -773,7 +804,8 @@ public class ElanUtils { * @return the egress actions for interface */ @SuppressWarnings("checkstyle:IllegalCatch") - public List getEgressActionsForInterface(String ifName, Long tunnelKey) { + @NonNull + public List getEgressActionsForInterface(String ifName, @Nullable Long tunnelKey) { List listAction = new ArrayList<>(); try { GetEgressActionsForInterfaceInput getEgressActionInput = new GetEgressActionsForInterfaceInputBuilder() @@ -785,8 +817,7 @@ public class ElanUtils { LOG.debug("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors()); } else { - List actions = rpcResult.getResult().getAction(); - listAction = actions; + listAction = new ArrayList(rpcResult.getResult().nonnullAction().values()); } } catch (Exception e) { LOG.warn("Exception when egress actions for interface {}", ifName, e); @@ -796,14 +827,13 @@ public class ElanUtils { private void setupOrigDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, boolean configureRemoteFlows, IMdsalApiManager mdsalApiManager, - WriteTransaction writeFlowGroupTx) - throws ElanException { - BigInteger dpId = interfaceInfo.getDpId(); + TypedWriteTransaction writeFlowGroupTx) { + Uint64 dpId = interfaceInfo.getDpId(); String ifName = interfaceInfo.getInterfaceName(); long ifTag = interfaceInfo.getInterfaceTag(); String elanInstanceName = elanInfo.getElanInstanceName(); - Long elanTag = elanInfo.getElanTag(); + Uint32 elanTag = elanInfo.getElanTag(); setupLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, mdsalApiManager, ifTag, writeFlowGroupTx); @@ -817,7 +847,7 @@ public class ElanUtils { List elanDpns = getInvolvedDpnsInElan(elanInstanceName); for (DpnInterfaces elanDpn : elanDpns) { - if (elanDpn.getDpId().equals(dpId)) { + if (Objects.equals(elanDpn.getDpId(), dpId)) { continue; } @@ -842,57 +872,54 @@ public class ElanUtils { // TODO: Make sure that the same is performed against the ElanDevices. } - @Nonnull + @NonNull public List getInvolvedDpnsInElan(String elanName) { return getElanDPNByName(elanName); } - @Nonnull + @NonNull public List getElanDPNByName(String elanInstanceName) { InstanceIdentifier elanIdentifier = getElanDpnOperationDataPath(elanInstanceName); - return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).toJavaUtil().map( - ElanDpnInterfacesList::getDpnInterfaces).orElse(Collections.emptyList()); + try { + return new ArrayList((SingleTransactionDataBroker.syncReadOptional(broker, + LogicalDatastoreType.OPERATIONAL, elanIdentifier).map(ElanDpnInterfacesList::getDpnInterfaces) + .orElse(emptyMap())).values()); + } catch (ExecutionException | InterruptedException e) { + LOG.error("getElanDPNByName: Exception while reading elanDpnInterfaceList DS for the elan " + + "instance {}", elanInstanceName, e); + return emptyList(); + } } - private void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress, - ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) { + private void setupLocalDmacFlow(Uint32 elanTag, Uint64 dpId, String ifName, String macAddress, + ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag, + TypedWriteTransaction writeFlowGroupTx) { Flow flowEntity = buildLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, elanInfo, ifTag); - mdsalApiManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx); - installEtreeLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, - ifTag, writeFlowGroupTx); + mdsalApiManager.addFlow(writeFlowGroupTx, dpId, flowEntity); + installEtreeLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, ifTag, writeFlowGroupTx); } - private void installEtreeLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress, - ElanInstance elanInfo, long ifTag, WriteTransaction writeFlowGroupTx) { - EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(ifName).orNull(); + private void installEtreeLocalDmacFlow(Uint32 elanTag, Uint64 dpId, String ifName, String macAddress, + ElanInstance elanInfo, long ifTag, TypedWriteTransaction writeFlowGroupTx) { + EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(ifName).orElse(null); if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) { - EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); + EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue()); if (etreeTagName == null) { LOG.warn("Interface {} seems like it belongs to Etree but etreeTagName from elanTag {} is null", ifName, elanTag); } else { - Flow flowEntity = buildLocalDmacFlowEntry(etreeTagName.getEtreeLeafTag().getValue(), dpId, ifName, - macAddress, elanInfo, ifTag); - mdsalManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx); + Flow flowEntity = buildLocalDmacFlowEntry(etreeTagName.getEtreeLeafTag().getValue(), dpId, + ifName, macAddress, elanInfo, ifTag); + mdsalManager.addFlow(writeFlowGroupTx, dpId, flowEntity); } } } - public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, long lporTag, String macAddress, - long elanTag) { - return String.valueOf(tableId) + elanTag + dpId + lporTag + macAddress; - } - - public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, BigInteger remoteDpId, - String macAddress, long elanTag) { - return String.valueOf(tableId) + elanTag + dpId + remoteDpId + macAddress; + public static String getKnownDynamicmacFlowRef(Uint32 elanTag, String macAddress) { + return new StringBuffer().append(elanTag).append(macAddress.toLowerCase(Locale.getDefault())).toString(); } - public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, String macAddress, long elanTag) { - return String.valueOf(tableId) + elanTag + dpId + macAddress; - } - - public static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId, + public static String getKnownDynamicmacFlowRef(short elanDmacTable, Uint64 dpId, String extDeviceNodeId, String dstMacAddress, long elanTag, boolean shFlag) { return String.valueOf(elanDmacTable) + elanTag + dpId + extDeviceNodeId + dstMacAddress + shFlag; } @@ -919,58 +946,60 @@ public class ElanUtils { * the if tag * @return the flow */ - public Flow buildLocalDmacFlowEntry(long elanTag, BigInteger dpId, String ifName, String macAddress, + public Flow buildLocalDmacFlowEntry(Uint32 elanTag, Uint64 dpId, String ifName, String macAddress, ElanInstance elanInfo, long ifTag) { List mkMatches = new ArrayList<>(); - mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); + mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()), + MetaDataUtil.METADATA_MASK_SERVICE)); mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress))); - List mkInstructions = new ArrayList<>(); + Map mkInstructions = new HashMap<>(); List actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null); - mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); + mkInstructions.put(new InstructionKey(0), MDSALUtil.buildApplyActionsInstruction(actions)); Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, - getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, ifTag, macAddress, elanTag), 20, - elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add( - BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); + getKnownDynamicmacFlowRef(elanTag, macAddress), 20, + elanInfo.getElanInstanceName(), 0, 0, + Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_DMAC.longValue() + elanTag.longValue()), + mkMatches, mkInstructions); return flow; } - public void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, String - macAddress, String displayName, WriteTransaction writeFlowGroupTx, String interfaceName, ElanInstance - elanInstance) throws ElanException { + public void setupRemoteDmacFlow(Uint64 srcDpId, Uint64 destDpId, int lportTag, Uint32 elanTag, + String macAddress, String displayName, TypedWriteTransaction writeFlowGroupTx, + String interfaceName, ElanInstance elanInstance) { if (interfaceManager.isExternalInterface(interfaceName)) { LOG.debug("Ignoring install remote DMAC {} flow on provider interface {} elan {}", macAddress, interfaceName, elanInstance.getElanInstanceName()); return; } - Flow flowEntity; // if openstack-vni-semantics are enforced, segmentation ID is passed as network VNI for VxLAN based provider // networks, 0 otherwise long lportTagOrVni = !isOpenstackVniSemanticsEnforced() ? lportTag : isVxlanNetworkOrVxlanSegment(elanInstance) - ? getVxlanSegmentationId(elanInstance) : 0; - flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, + ? getVxlanSegmentationId(elanInstance).longValue() : 0; + Flow flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, elanInstance); - mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx); + mdsalManager.addFlow(writeFlowGroupTx, srcDpId, flowEntity); setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, interfaceName, writeFlowGroupTx, elanInstance); } - private void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag, + private void setupEtreeRemoteDmacFlow(Uint64 srcDpId, Uint64 destDpId, long lportTagOrVni, Uint32 elanTag, String macAddress, String displayName, String interfaceName, - WriteTransaction writeFlowGroupTx, ElanInstance elanInstance) { + TypedWriteTransaction writeFlowGroupTx, + ElanInstance elanInstance) { Flow flowEntity; - EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName).orNull(); + EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName).orElse(null); if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) { - EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); + EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue()); if (etreeTagName == null) { LOG.warn("Interface {} seems like it belongs to Etree but etreeTagName from elanTag {} is null.", interfaceName, elanTag); } else { flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, etreeTagName.getEtreeLeafTag().getValue(), macAddress, displayName, elanInstance); - mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx); + mdsalManager.addFlow(writeFlowGroupTx, srcDpId, flowEntity); } } } @@ -998,122 +1027,134 @@ public class ElanUtils { * @return the flow remote Dmac */ @SuppressWarnings("checkstyle:IllegalCatch") - public Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag, + public Flow buildRemoteDmacFlowEntry(Uint64 srcDpId, Uint64 destDpId, long lportTagOrVni, Uint32 elanTag, String macAddress, String displayName, ElanInstance elanInstance) { List mkMatches = new ArrayList<>(); - mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); + mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()), + MetaDataUtil.METADATA_MASK_SERVICE)); mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress))); - List mkInstructions = new ArrayList<>(); + Map mkInstructions = new HashMap<>(); // List of Action for the provided Source and Destination DPIDs try { List actions = null; - if (isVlan(elanInstance) || isFlat(elanInstance)) { + if (isVxlanNetworkOrVxlanSegment(elanInstance)) { + actions = elanItmUtils.getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTagOrVni); + } else if (isVlan(elanInstance) || isFlat(elanInstance)) { String interfaceName = getExternalElanInterface(elanInstance.getElanInstanceName(), srcDpId); if (null == interfaceName) { LOG.info("buildRemoteDmacFlowEntry: Could not find interfaceName for {} {}", srcDpId, - elanInstance); + elanInstance); } actions = getEgressActionsForInterface(interfaceName, null); - } else if (isVxlanNetworkOrVxlanSegment(elanInstance)) { - actions = elanItmUtils.getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTagOrVni); } - mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); + mkInstructions.put(new InstructionKey(0), MDSALUtil.buildApplyActionsInstruction(actions)); } catch (Exception e) { LOG.error("Could not get egress actions to add to flow for srcDpId {}, destDpId {}, lportTag/VNI {}", srcDpId, destDpId, lportTagOrVni, e); } Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, - getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcDpId, destDpId, macAddress, elanTag), + getKnownDynamicmacFlowRef(elanTag, macAddress), 20, /* prio */ displayName, 0, /* idleTimeout */ 0, /* hardTimeout */ - ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); + Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_DMAC.longValue() + elanTag.longValue()), + mkMatches, mkInstructions); return flow; } public void deleteMacFlows(@Nullable ElanInstance elanInfo, @Nullable InterfaceInfo interfaceInfo, - MacEntry macEntry, WriteTransaction deleteFlowGroupTx) { + MacEntry macEntry, TypedReadWriteTransaction flowTx) + throws ExecutionException, InterruptedException { if (elanInfo == null || interfaceInfo == null) { return; } String macAddress = macEntry.getMacAddress().getValue(); - synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) { - deleteMacFlows(elanInfo, interfaceInfo, macAddress, /* alsoDeleteSMAC */ true, deleteFlowGroupTx); + try (Acquired lock = lockElanMacDPN(elanInfo.getElanTag().toJava(), + macAddress, interfaceInfo.getDpId())) { + deleteMacFlows(elanInfo, interfaceInfo, macAddress, /* alsoDeleteSMAC */ true, flowTx); } } public void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, - boolean deleteSmac, WriteTransaction deleteFlowGroupTx) { + boolean deleteSmac, TypedReadWriteTransaction flowTx) + throws ExecutionException, InterruptedException { String elanInstanceName = elanInfo.getElanInstanceName(); List remoteFEs = getInvolvedDpnsInElan(elanInstanceName); - BigInteger srcdpId = interfaceInfo.getDpId(); + Uint64 srcdpId = interfaceInfo.getDpId(); boolean isFlowsRemovedInSrcDpn = false; for (DpnInterfaces dpnInterface : remoteFEs) { - Long elanTag = elanInfo.getElanTag(); - BigInteger dstDpId = dpnInterface.getDpId(); + Uint32 elanTag = elanInfo.getElanTag(); + Uint64 dstDpId = dpnInterface.getDpId(); if (executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId, - elanTag, dstDpId, deleteFlowGroupTx)) { + elanTag, dstDpId, flowTx)) { isFlowsRemovedInSrcDpn = true; } executeEtreeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId, - elanTag, dstDpId, deleteFlowGroupTx); + elanTag, dstDpId, flowTx); } if (!isFlowsRemovedInSrcDpn) { - deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, deleteFlowGroupTx); + deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, flowTx); } } private void executeEtreeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, - boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId, - WriteTransaction deleteFlowGroupTx) { - EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); + boolean deleteSmac, String elanInstanceName, Uint64 srcdpId, Uint32 elanTag, Uint64 dstDpId, + TypedReadWriteTransaction flowTx) throws ExecutionException, InterruptedException { + EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue()); if (etreeLeafTag != null) { executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId, - etreeLeafTag.getEtreeLeafTag().getValue(), dstDpId, deleteFlowGroupTx); + etreeLeafTag.getEtreeLeafTag().getValue(), dstDpId, flowTx); } } private boolean executeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, - boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId, - WriteTransaction deleteFlowGroupTx) { + boolean deleteSmac, String elanInstanceName, Uint64 srcdpId, Uint32 elanTag, Uint64 dstDpId, + TypedReadWriteTransaction flowTx) throws ExecutionException, InterruptedException { boolean isFlowsRemovedInSrcDpn = false; if (dstDpId.equals(srcdpId)) { isFlowsRemovedInSrcDpn = true; - deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, deleteFlowGroupTx); + deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, flowTx); } else if (isDpnPresent(dstDpId)) { mdsalManager - .removeFlowToTx(dstDpId, - MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef( - NwConstants.ELAN_DMAC_TABLE, dstDpId, srcdpId, macAddress, elanTag)), - deleteFlowGroupTx); + .removeFlow(flowTx, dstDpId, + MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef(elanTag, macAddress))); LOG.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId); } return isFlowsRemovedInSrcDpn; } + public void deleteSmacFlowOnly(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, + TypedReadWriteTransaction flowTx) throws ExecutionException, + InterruptedException { + Uint64 srcdpId = interfaceInfo.getDpId(); + Uint32 elanTag = elanInfo.getElanTag(); + LOG.debug("Deleting SMAC flow with id {}", getKnownDynamicmacFlowRef(elanTag, macAddress)); + mdsalManager.removeFlow(flowTx, srcdpId, + MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, getKnownDynamicmacFlowRef(elanTag, macAddress))); + } + private void deleteSmacAndDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, - boolean deleteSmac, WriteTransaction deleteFlowGroupTx) { + boolean deleteSmac, TypedReadWriteTransaction flowTx) + throws ExecutionException, InterruptedException { String elanInstanceName = elanInfo.getElanInstanceName(); - long ifTag = interfaceInfo.getInterfaceTag(); - BigInteger srcdpId = interfaceInfo.getDpId(); - Long elanTag = elanInfo.getElanTag(); + Uint64 srcdpId = interfaceInfo.getDpId(); + Uint32 elanTag = elanInfo.getElanTag(); if (deleteSmac) { + LOG.debug("Deleting SMAC flow with id {}", getKnownDynamicmacFlowRef(elanTag, macAddress)); mdsalManager - .removeFlowToTx(srcdpId, - MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, getKnownDynamicmacFlowRef( - NwConstants.ELAN_SMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)), - deleteFlowGroupTx); + .removeFlow(flowTx, srcdpId, + MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, + getKnownDynamicmacFlowRef(elanTag, macAddress))); } - mdsalManager.removeFlowToTx(srcdpId, - MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, - getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)), - deleteFlowGroupTx); + mdsalManager.removeFlow(flowTx, srcdpId, + MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, + getKnownDynamicmacFlowRef(elanTag, macAddress))); LOG.debug("All the required flows deleted for elan:{}, logical Interface port:{} and MAC address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId); } @@ -1128,54 +1169,58 @@ public class ElanUtils { * the elan instance added * @param elanInterfaces * the elan interfaces - * @param tx + * @param operTx * transaction * * @return the updated ELAN instance. */ public static ElanInstance updateOperationalDataStore(IdManagerService idManager, - ElanInstance elanInstanceAdded, List elanInterfaces, WriteTransaction tx) { + ElanInstance elanInstanceAdded, List elanInterfaces, TypedWriteTransaction confTx, + TypedWriteTransaction operTx) { String elanInstanceName = elanInstanceAdded.getElanInstanceName(); - Long elanTag = elanInstanceAdded.getElanTag(); - if (elanTag == null || elanTag == 0L) { + Uint32 elanTag = elanInstanceAdded.getElanTag(); + if (elanTag == null || elanTag.longValue() == 0L) { elanTag = retrieveNewElanTag(idManager, elanInstanceName); } + if (elanTag.longValue() == 0L) { + LOG.error("ELAN tag creation failed for elan instance {}. Not updating the ELAN DS. " + + "Recreate network for recovery", elanInstanceName); + return null; + } Elan elanInfo = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(elanInterfaces) .withKey(new ElanKey(elanInstanceName)).build(); // Add the ElanState in the elan-state operational data-store - tx.put(LogicalDatastoreType.OPERATIONAL, getElanInstanceOperationalDataPath(elanInstanceName), - elanInfo, WriteTransaction.CREATE_MISSING_PARENTS); + operTx.mergeParentStructurePut(getElanInstanceOperationalDataPath(elanInstanceName), elanInfo); // Add the ElanMacTable in the elan-mac-table operational data-store MacTable elanMacTable = new MacTableBuilder().withKey(new MacTableKey(elanInstanceName)).build(); - tx.put(LogicalDatastoreType.OPERATIONAL, getElanMacTableOperationalDataPath(elanInstanceName), - elanMacTable, WriteTransaction.CREATE_MISSING_PARENTS); + operTx.mergeParentStructurePut(getElanMacTableOperationalDataPath(elanInstanceName), elanMacTable); ElanTagNameBuilder elanTagNameBuilder = new ElanTagNameBuilder().setElanTag(elanTag) .withKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName); - long etreeLeafTag = -1; + Uint32 etreeLeafTag = Uint32.valueOf(0L); if (isEtreeInstance(elanInstanceAdded)) { etreeLeafTag = retrieveNewElanTag(idManager,elanInstanceName + ElanConstants .LEAVES_POSTFIX); EtreeLeafTagName etreeLeafTagName = new EtreeLeafTagNameBuilder() .setEtreeLeafTag(new EtreeLeafTag(etreeLeafTag)).build(); elanTagNameBuilder.addAugmentation(EtreeLeafTagName.class, etreeLeafTagName); - addTheLeafTagAsElanTag(elanInstanceName, etreeLeafTag, tx); + addTheLeafTagAsElanTag(elanInstanceName, etreeLeafTag, operTx); } ElanTagName elanTagName = elanTagNameBuilder.build(); // Add the ElanTag to ElanName in the elan-tag-name Operational // data-store - tx.put(LogicalDatastoreType.OPERATIONAL, - getElanInfoEntriesOperationalDataPath(elanTag), elanTagName); + operTx.put(getElanInfoEntriesOperationalDataPath(elanTag), elanTagName); // Updates the ElanInstance Config DS by setting the just acquired // elanTag - ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName) + ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder(elanInstanceAdded) + .setElanInstanceName(elanInstanceName) .setDescription(elanInstanceAdded.getDescription()) .setMacTimeout(elanInstanceAdded.getMacTimeout() == null - ? Long.valueOf(ElanConstants.DEFAULT_MAC_TIME_OUT) : elanInstanceAdded.getMacTimeout()) + ? Uint32.valueOf(ElanConstants.DEFAULT_MAC_TIME_OUT) : elanInstanceAdded.getMacTimeout()) .withKey(elanInstanceAdded.key()).setElanTag(elanTag); if (isEtreeInstance(elanInstanceAdded)) { EtreeInstance etreeInstance = new EtreeInstanceBuilder().setEtreeLeafTagVal(new EtreeLeafTag(etreeLeafTag)) @@ -1183,23 +1228,25 @@ public class ElanUtils { elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance); } ElanInstance elanInstanceWithTag = elanInstanceBuilder.build(); - tx.merge(LogicalDatastoreType.CONFIGURATION, ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), - elanInstanceWithTag, WriteTransaction.CREATE_MISSING_PARENTS); + LOG.trace("Updated elan Operational DS for elan: {} with elanTag: {} and interfaces: {}", elanInstanceName, + elanTag, elanInterfaces); + confTx.mergeParentStructureMerge(ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), + elanInstanceWithTag); return elanInstanceWithTag; } - private static void addTheLeafTagAsElanTag(String elanInstanceName, long etreeLeafTag, WriteTransaction tx) { + private static void addTheLeafTagAsElanTag(String elanInstanceName,Uint32 etreeLeafTag, + TypedWriteTransaction tx) { ElanTagName etreeTagAsElanTag = new ElanTagNameBuilder().setElanTag(etreeLeafTag) .withKey(new ElanTagNameKey(etreeLeafTag)).setName(elanInstanceName).build(); - tx.put(LogicalDatastoreType.OPERATIONAL, - getElanInfoEntriesOperationalDataPath(etreeLeafTag), etreeTagAsElanTag); + tx.put(getElanInfoEntriesOperationalDataPath(etreeLeafTag), etreeTagAsElanTag); } private static boolean isEtreeInstance(ElanInstance elanInstanceAdded) { return elanInstanceAdded.augmentation(EtreeInstance.class) != null; } - public boolean isDpnPresent(BigInteger dpnId) { + public boolean isDpnPresent(Uint64 dpnId) { String dpn = String.format("%s:%s", "openflow", dpnId); NodeId nodeId = new NodeId(dpn); @@ -1208,17 +1255,12 @@ public class ElanUtils { return read(broker, LogicalDatastoreType.CONFIGURATION, node).isPresent(); } - public static ServicesInfo getServiceInfo(String elanInstanceName, String interfaceName) { - return InterfaceServiceUtil.buildServiceInfo(elanInstanceName + "." + interfaceName, - ElanConstants.ELAN_SERVICE_PRIORITY); - } - public static String getElanServiceName(String elanName, String interfaceName) { return "elan." + elanName + interfaceName; } public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority, - BigInteger cookie, List instructions) { + Uint64 cookie, List instructions) { StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority) .setInstruction(instructions); return new BoundServicesBuilder().withKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName) @@ -1232,15 +1274,16 @@ public class ElanUtils { .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build(); } - public static List getTunnelMatchesForServiceId(int elanTag) { + public static List getTunnelMatchesForServiceId(Uint32 elanTag) { List mkMatches = new ArrayList<>(); - // Matching metadata - mkMatches.add(new MatchTunnelId(BigInteger.valueOf(elanTag))); + + // Adding 270000 to avoid collision between LPort and elan tag for broadcast + mkMatches.add(new MatchTunnelId(Uint64.valueOf(elanTag.longValue() + ElanConstants.ELAN_TAG_ADDEND))); return mkMatches; } - public void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) { + public void removeTerminatingServiceAction(Uint64 destDpId, int serviceId) { RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder() .setDpnId(destDpId).setServiceId(serviceId).build(); Future> futureObject = @@ -1271,12 +1314,13 @@ public class ElanUtils { * the datastore type * @return the external tunnel */ + @Nullable public ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice, LogicalDatastoreType datastoreType) { Class tunType = TunnelTypeVxlan.class; InstanceIdentifier iid = InstanceIdentifier.builder(ExternalTunnelList.class) .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build(); - return read(broker, datastoreType, iid).orNull(); + return read(broker, datastoreType, iid).orElse(null); } /** @@ -1288,6 +1332,7 @@ public class ElanUtils { * the datastore type * @return the external tunnel */ + @Nullable public ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) { ExternalTunnel externalTunnel = null; List externalTunnels = getAllExternalTunnels(datastoreType); @@ -1309,8 +1354,8 @@ public class ElanUtils { */ public List getAllExternalTunnels(LogicalDatastoreType datastoreType) { InstanceIdentifier iid = InstanceIdentifier.builder(ExternalTunnelList.class).build(); - return read(broker, datastoreType, iid).toJavaUtil().map(ExternalTunnelList::getExternalTunnel).orElse( - Collections.emptyList()); + return new ArrayList(read(broker, datastoreType, iid).map(ExternalTunnelList + ::getExternalTunnel).orElse(Collections.emptyMap()).values()); } public static List buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) { @@ -1350,13 +1395,16 @@ public class ElanUtils { * the data broker * @return the interface state from oper ds */ - public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang - .ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS( - String interfaceName, DataBroker dataBroker) { - InstanceIdentifier ifStateId = createInterfaceStateInstanceIdentifier( - interfaceName); - return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId).orNull(); + public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state + .@Nullable Interface getInterfaceStateFromOperDS(String interfaceName, DataBroker dataBroker) { + try { + return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, + createInterfaceStateInstanceIdentifier(interfaceName)).orElse(null); + } catch (ExecutionException | InterruptedException e) { + LOG.error("getInterfaceStateFromOperDS: Exception while reading interface DS for the interface {}", + interfaceName, e); + return null; + } } /** @@ -1380,29 +1428,28 @@ public class ElanUtils { return idBuilder.build(); } - public static CheckedFuture waitForTransactionToComplete( - WriteTransaction tx) { - CheckedFuture futures = tx.submit(); + @CheckReturnValue + public static ListenableFuture waitForTransactionToComplete(ListenableFuture future) { try { - futures.get(); + future.get(); } catch (InterruptedException | ExecutionException e) { - // NETVIRT-1215: Do not log.error() here, only debug() + // NETVIRT-1215: Do not log.error() here, only debug(); but callers *MUST* @CheckReturnValue LOG.debug("Error writing to datastore", e); } - return futures; + return future; } public static boolean isVxlan(@Nullable ElanInstance elanInstance) { return elanInstance != null && elanInstance.getSegmentType() != null && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class) - && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0; + && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().toJava() != 0; } - private static boolean isVxlanSegment(ElanInstance elanInstance) { + private static boolean isVxlanSegment(@Nullable ElanInstance elanInstance) { if (elanInstance != null) { - List elanSegments = elanInstance.getElanSegments(); + Map elanSegments = elanInstance.getElanSegments(); if (elanSegments != null) { - for (ElanSegments segment : elanSegments) { + for (ElanSegments segment : elanSegments.values()) { if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class) && segment.getSegmentationId() != null && segment.getSegmentationId().longValue() != 0) { @@ -1414,12 +1461,12 @@ public class ElanUtils { return false; } - public static boolean isVxlanNetworkOrVxlanSegment(ElanInstance elanInstance) { + public static boolean isVxlanNetworkOrVxlanSegment(@Nullable ElanInstance elanInstance) { return isVxlan(elanInstance) || isVxlanSegment(elanInstance); } - public static Long getVxlanSegmentationId(ElanInstance elanInstance) { - Long segmentationId = 0L; + public static Uint32 getVxlanSegmentationId(ElanInstance elanInstance) { + Uint32 segmentationId = Uint32.ZERO; if (elanInstance == null) { return segmentationId; } @@ -1429,7 +1476,7 @@ public class ElanUtils { && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().longValue() != 0) { segmentationId = elanInstance.getSegmentationId(); } else { - for (ElanSegments segment: elanInstance.getElanSegments()) { + for (ElanSegments segment: elanInstance.getElanSegments().values()) { if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class) && segment.getSegmentationId() != null && segment.getSegmentationId().longValue() != 0) { @@ -1443,7 +1490,7 @@ public class ElanUtils { public static boolean isVlan(ElanInstance elanInstance) { return elanInstance != null && elanInstance.getSegmentType() != null && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVlan.class) - && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0; + && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().toJava() != 0; } public static boolean isFlat(ElanInstance elanInstance) { @@ -1451,40 +1498,45 @@ public class ElanUtils { && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeFlat.class); } - public void addDmacRedirectToDispatcherFlows(Long elanTag, String displayName, - String macAddress, List dpnIds) { - for (BigInteger dpId : dpnIds) { - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit( - tx -> mdsalManager.addFlowToTx( - buildDmacRedirectToDispatcherFlow(dpId, macAddress, displayName, elanTag), tx)), LOG, + public void addDmacRedirectToDispatcherFlows(Uint32 elanTag, String displayName, + String macAddress, List dpnIds) { + for (Uint64 dpId : dpnIds) { + LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, + tx -> mdsalManager.addFlow(tx, buildDmacRedirectToDispatcherFlow(dpId, macAddress, displayName, + elanTag))), LOG, "Error adding DMAC redirect to dispatcher flows"); } } - public void removeDmacRedirectToDispatcherFlows(Long elanTag, String macAddress, List dpnIds) { - for (BigInteger dpId : dpnIds) { - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, macAddress, elanTag); - mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, flowId)); - } + public void removeDmacRedirectToDispatcherFlows(Uint32 elanTag, String macAddress, List dpnIds) { + LoggingFutures.addErrorLogging( + txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> { + for (Uint64 dpId : dpnIds) { + String flowId = getKnownDynamicmacFlowRef(elanTag, macAddress); + mdsalManager.removeFlow(tx, dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, flowId)); + } + }), LOG, "Error removing DMAC redirect to dispatcher flows"); } - public static FlowEntity buildDmacRedirectToDispatcherFlow(BigInteger dpId, String dstMacAddress, - String displayName, long elanTag) { + public static FlowEntity buildDmacRedirectToDispatcherFlow(Uint64 dpId, String dstMacAddress, + String displayName, Uint32 elanTag) { List matches = new ArrayList<>(); - matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); + matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()), + MetaDataUtil.METADATA_MASK_SERVICE)); matches.add(new MatchEthernetDestination(new MacAddress(dstMacAddress))); List instructions = new ArrayList<>(); List actions = new ArrayList<>(); actions.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE)); instructions.add(new InstructionApplyActions(actions)); - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, dstMacAddress, elanTag); + String flowId = getKnownDynamicmacFlowRef(elanTag, dstMacAddress); return MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_DMAC_TABLE, flowId, 20, displayName, 0, 0, - ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), + Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_DMAC.longValue() + elanTag.longValue()), matches, instructions); } - public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) { + @Nullable + public String getExternalElanInterface(String elanInstanceName, Uint64 dpnId) { DpnInterfaces dpnInterfaces = getElanInterfaceInfoByElanDpn(elanInstanceName, dpnId); if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null) { LOG.trace("Elan {} does not have interfaces in DPN {}", elanInstanceName, dpnId); @@ -1501,14 +1553,8 @@ public class ElanUtils { return null; } - public static String getElanMacDPNKey(long elanTag, String macAddress, BigInteger dpnId) { - String elanMacDmacDpnKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag + "DPN_ID-" + dpnId; - return elanMacDmacDpnKey.intern(); - } - - public static String getElanMacKey(long elanTag, String macAddress) { - String elanMacKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag; - return elanMacKey.intern(); + public static Acquired lockElanMacDPN(long elanTag, String macAddress, Uint64 dpnId) { + return ELAN_LOCKS.acquire(new ElanLockName(elanTag, macAddress, dpnId)); } public static List> @@ -1551,18 +1597,6 @@ public class ElanUtils { new StaticMacEntriesKey(new PhysAddress(macAddress))).build(); } - public static List getDeletedEntries(List originalStaticMacEntries, - List updatedStaticMacEntries) { - if (isEmpty(originalStaticMacEntries)) { - return Collections.EMPTY_LIST; - } - List deleted = Lists.newArrayList(originalStaticMacEntries); - if (isNotEmpty(updatedStaticMacEntries)) { - deleted.removeAll(updatedStaticMacEntries); - } - return deleted; - } - public static List diffOf(List orig, List updated) { if (isEmpty(orig)) { return Collections.EMPTY_LIST; @@ -1574,18 +1608,6 @@ public class ElanUtils { return diff; } - public static void segregateToBeDeletedAndAddEntries(List originalStaticMacEntries, - List updatedStaticMacEntries) { - if (isNotEmpty(updatedStaticMacEntries)) { - List existingClonedStaticMacEntries = new ArrayList<>(); - if (isNotEmpty(originalStaticMacEntries)) { - existingClonedStaticMacEntries.addAll(0, originalStaticMacEntries); - originalStaticMacEntries.removeAll(updatedStaticMacEntries); - updatedStaticMacEntries.removeAll(existingClonedStaticMacEntries); - } - } - } - public static boolean isEmpty(Collection collection) { return collection == null || collection.isEmpty(); } @@ -1595,7 +1617,7 @@ public class ElanUtils { } public Optional getSourceIpAddress(Ethernet ethernet) { - Optional srcIpAddress = Optional.absent(); + Optional srcIpAddress = Optional.empty(); if (ethernet.getPayload() == null) { return srcIpAddress; } @@ -1616,26 +1638,30 @@ public class ElanUtils { public List getElanMacEntries(String elanName) { MacTable macTable = getElanMacTable(elanName); if (macTable == null) { - return Collections.emptyList(); + return emptyList(); } - return macTable.getMacEntry(); + return new ArrayList(macTable.getMacEntry().values()); } public boolean isTunnelInLogicalGroup(String interfaceName) { org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang .ietf.interfaces.rev140508.interfaces.Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName); + if (configIface == null) { + configIface = iitmProvider.getInterface(interfaceName); + } + if (configIface == null) { + return false; + } IfTunnel ifTunnel = configIface.augmentation(IfTunnel.class); if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) { ParentRefs refs = configIface.augmentation(ParentRefs.class); - if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) { - return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated - } + return refs != null && !Strings.isNullOrEmpty(refs.getParentInterface()); } return false; } - public static InstanceIdentifier getFlowIid(Flow flow, BigInteger dpnId) { + public static InstanceIdentifier getFlowIid(Flow flow, Uint64 dpnId) { FlowKey flowKey = new FlowKey(new FlowId(flow.getId())); org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId = new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId("openflow:" + dpnId); @@ -1651,18 +1677,21 @@ public class ElanUtils { return "elaninterface-" + interfaceName; } - public void removeArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress, + public void removeArpResponderFlow(Uint64 dpnId, String ingressInterfaceName, String ipAddress, int lportTag) { LOG.info("Removing the ARP responder flow on DPN {} of Interface {} with IP {}", dpnId, ingressInterfaceName, ipAddress); - ArpResponderUtil.removeFlow(mdsalManager, dpnId, ArpResponderUtil.getFlowId(lportTag, ipAddress)); + LoggingFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, + tx -> mdsalManager.removeFlow(tx, dpnId, ArpResponderUtil.getFlowId(lportTag, ipAddress), + NwConstants.ARP_RESPONDER_TABLE)), LOG, "Error removing ARP responder flow"); } + @Nullable public static String getRouterPordIdFromElanInstance(DataBroker dataBroker, String elanInstanceName) { Optional subnetMapsData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, buildSubnetMapsWildCardPath()); if (subnetMapsData.isPresent()) { - List subnetMapList = subnetMapsData.get().getSubnetmap(); + List subnetMapList = new ArrayList<>(subnetMapsData.get().getSubnetmap().values()); if (subnetMapList != null && !subnetMapList.isEmpty()) { for (Subnetmap subnet : subnetMapList) { if (subnet.getNetworkId().getValue().equals(elanInstanceName)) { @@ -1676,9 +1705,81 @@ public class ElanUtils { return null; } + protected Node buildDpnNode(Uint64 dpnId) { + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId = + new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819 + .NodeId("openflow:" + dpnId); + Node nodeDpn = new NodeBuilder().setId(nodeId).withKey(new NodeKey(nodeId)).build(); + return nodeDpn; + } + + public void syncUpdateGroup(Uint64 dpnId, Group newGroup, long delayTime, + TypedWriteTransaction confTx) { + Node nodeDpn = buildDpnNode(dpnId); + long groupIdInfo = newGroup.getGroupId().getValue().toJava(); + GroupKey groupKey = new GroupKey(new GroupId(groupIdInfo)); + InstanceIdentifier groupInstanceId = InstanceIdentifier.builder(Nodes.class) + .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class) + .child(Group.class, groupKey).build(); + LOG.trace("Performing merge operation for remote BC group for node {} with group {}", nodeDpn, newGroup); + Optional existingGroupOpt = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION, groupInstanceId); + if (!existingGroupOpt.isPresent()) { + LOG.debug("Group {} doesn't exist. Performing syncInstall", groupIdInfo); + mdsalManager.addGroup(confTx, dpnId, newGroup); + return; + } + Buckets existingGroup = existingGroupOpt.get().getBuckets(); + if (existingGroup == null) { + LOG.debug("Bucket doesn't exist for group {}. Performing syncInstall", groupIdInfo); + mdsalManager.addGroup(confTx, dpnId, newGroup); + return; + } + if (newGroup.getBuckets() == null) { + LOG.debug("Buckets are not sent for group {}. Skipping merge operation", groupIdInfo); + return; + } + List newBuckets = new ArrayList(newGroup.getBuckets().getBucket().values()); + List existingBuckets = new ArrayList(existingGroup.getBucket().values()); + Set toMergeBucketsWithoutId = new LinkedHashSet<>(); + + existingBuckets.stream() + .map(TO_BUCKET_WITHOUT_ID) + .forEach(bucketWithoutId -> toMergeBucketsWithoutId.add(bucketWithoutId)); + + newBuckets.stream() + .map(TO_BUCKET_WITHOUT_ID) + .forEach(bucketWithoutId -> toMergeBucketsWithoutId.add(bucketWithoutId)); + + if (toMergeBucketsWithoutId.size() == existingBuckets.size()) { + //no new buckets got added + //size matched and no extra buckets in existing buckets , rewrite the group + LOG.debug("Buckets did not change group {}. Skipping merge operation", groupIdInfo); + return; + } + LOG.debug("Old group buckets size {} New group buckets size {} Dpn id {} Group id {} ", + existingBuckets.size(), toMergeBucketsWithoutId.size(), dpnId, groupIdInfo); + AtomicLong bucketIdValue = new AtomicLong(-1); + //Change the bucket id of existing buckets + List bucketsToBeAdded = toMergeBucketsWithoutId.stream() + .map(bucketWithoutId -> TO_BUCKET_WITH_ID.apply(bucketWithoutId, bucketIdValue)) + .collect(Collectors.toList()); + + Group group = MDSALUtil.buildGroup(newGroup.getGroupId().getValue().toJava(), newGroup.getGroupName(), + GroupTypes.GroupAll, MDSALUtil.buildBucketLists(bucketsToBeAdded)); + mdsalManager.addGroup(confTx, dpnId, group); + LOG.trace("Installed remote BC group for node {} with group {}", nodeDpn, group); + } + static InstanceIdentifier buildSubnetMapsWildCardPath() { return InstanceIdentifier.create(Subnetmaps.class); } -} + public static InstanceIdentifier getGroupInstanceid(Uint64 dpnId, long groupId) { + return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId("openflow:" + dpnId))) + .augmentation(FlowCapableNode.class).child(Group.class, new GroupKey(new GroupId(groupId))).build(); + } + public static String getBcGroupUpdateKey(String elanName) { + return "bc.group.update." + elanName; + } +}