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=8840664ca8c9410feac78e1e679f1897794b4f64;hpb=d94623901d6f6095db51162240ef766b55839dce;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 8840664ca8..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 @@ -8,15 +8,14 @@ package org.opendaylight.netvirt.elan.utils; import static java.util.Collections.emptyList; -import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS; +import static java.util.Collections.emptyMap; import static org.opendaylight.genius.infra.Datastore.CONFIGURATION; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.primitives.Ints; -import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -26,21 +25,26 @@ 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 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.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +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; @@ -74,8 +78,17 @@ 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.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; @@ -93,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; @@ -127,7 +141,12 @@ 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; @@ -164,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; @@ -183,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; @@ -202,10 +254,20 @@ public class ElanUtils { 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"); } @@ -219,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, IITMProvider iitmProvider) { + ElanInterfaceCache elanInterfaceCache, IITMProvider iitmProvider, ElanGroupCache elanGroupCache) { this.broker = dataBroker; this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker); this.mdsalManager = mdsalManager; @@ -231,6 +293,7 @@ public class ElanUtils { this.elanItmUtils = elanItmUtils; this.elanInterfaceCache = elanInterfaceCache; this.iitmProvider = iitmProvider; + this.elanGroupCache = elanGroupCache; } public final Boolean isOpenstackVniSemanticsEnforced() { @@ -247,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(); @@ -263,7 +326,7 @@ 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) { @@ -286,27 +349,28 @@ public class ElanUtils { @SuppressWarnings("checkstyle:IllegalCatch") 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:ForbidCertainMethod") public static void delete(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path) { + InstanceIdentifier path) { WriteTransaction tx = broker.newWriteOnlyTransaction(); tx.delete(datastoreType, path); - Futures.addCallback(tx.submit(), DEFAULT_CALLBACK, MoreExecutors.directExecutor()); + FluentFuture future = tx.commit(); + future.addCallback(DEFAULT_CALLBACK, MoreExecutors.directExecutor()); } public static InstanceIdentifier getElanInterfaceConfigurationDataPathId(String interfaceName) { @@ -318,13 +382,20 @@ public class ElanUtils { @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(TypedReadTransaction tx, String elanInstanceName) throws ExecutionException, InterruptedException { - return tx.read(getElanInstanceOperationalDataPath(elanInstanceName)).get().orNull(); + return tx.read(getElanInstanceOperationalDataPath(elanInstanceName)).get().orElse(null); } public static InstanceIdentifier getElanInstanceOperationalDataPath(String elanInstanceName) { @@ -336,13 +407,13 @@ public class ElanUtils { 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); } @Nullable public MacEntry getInterfaceMacEntriesOperationalDataPathFromId(TypedReadTransaction tx, InstanceIdentifier identifier) throws ExecutionException, InterruptedException { - return tx.read(identifier).get().orNull(); + return tx.read(identifier).get().orElse(null); } public static InstanceIdentifier getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName, @@ -368,7 +439,7 @@ public class ElanUtils { @Nullable public MacEntry getMacEntryFromElanMacId(TypedReadTransaction tx, InstanceIdentifier identifier) throws ExecutionException, InterruptedException { - return tx.read(identifier).get().orNull(); + return tx.read(identifier).get().orElse(null); } public static InstanceIdentifier getMacEntryOperationalDataPath(String elanName, @@ -391,7 +462,7 @@ public class ElanUtils { public static ElanInterfaceMac getElanInterfaceMacByInterfaceName(DataBroker dataBroker, String interfaceName) { InstanceIdentifier elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath( interfaceName); - return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orNull(); + return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orElse(null); } public static InstanceIdentifier getElanInterfaceMacEntriesOperationalDataPath( @@ -411,10 +482,10 @@ public class ElanUtils { * @return the elan interface Info */ @Nullable - public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) { + 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); } /** @@ -429,7 +500,7 @@ 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(); @@ -437,27 +508,28 @@ public class ElanUtils { // elan-tag-name-map Operational Container @Nullable - public ElanTagName getElanInfoByElanTag(long elanTag) { + 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) { @@ -468,14 +540,14 @@ public class ElanUtils { @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); } /** @@ -488,16 +560,16 @@ public class ElanUtils { * @return list of dpIds */ @NonNull - public List getParticipatingDpnsInElanInstance(String elanInstanceName) { - List dpIds = new ArrayList<>(); + 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().nonnullDpnInterfaces(); - for (DpnInterfaces dpnInterface : dpnInterfaces) { + Map dpnInterfaces = existingElanDpnInterfaces.get().nonnullDpnInterfaces(); + for (DpnInterfaces dpnInterface : dpnInterfaces.values()) { dpIds.add(dpnInterface.getDpId()); } return dpIds; @@ -522,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) { @@ -541,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))); } /** @@ -565,7 +637,7 @@ public class ElanUtils { public void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout, String macAddress, boolean configureRemoteFlows, TypedWriteTransaction writeFlowGroupTx) { - synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) { + try (Acquired lock = lockElanMacDPN(elanInfo.getElanTag().toJava(), macAddress, interfaceInfo.getDpId())) { setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalManager, writeFlowGroupTx); setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, configureRemoteFlows, mdsalManager, @@ -573,11 +645,12 @@ public class ElanUtils { } } - public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId, + 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); @@ -601,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) @@ -625,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 @@ -655,12 +729,12 @@ public class ElanUtils { */ public void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager, TypedWriteTransaction writeFlowGroupTx) { - BigInteger dpId = interfaceInfo.getDpId(); + 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.addFlow(writeFlowGroupTx, dpId, flow); @@ -679,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(); } /** @@ -693,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; } @@ -706,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; } @@ -742,7 +817,7 @@ public class ElanUtils { LOG.debug("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors()); } else { - listAction = rpcResult.getResult().nonnullAction(); + listAction = new ArrayList(rpcResult.getResult().nonnullAction().values()); } } catch (Exception e) { LOG.warn("Exception when egress actions for interface {}", ifName, e); @@ -753,12 +828,12 @@ public class ElanUtils { private void setupOrigDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, boolean configureRemoteFlows, IMdsalApiManager mdsalApiManager, TypedWriteTransaction writeFlowGroupTx) { - BigInteger dpId = interfaceInfo.getDpId(); + 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); @@ -805,11 +880,18 @@ public class ElanUtils { @NonNull public List getElanDPNByName(String elanInstanceName) { InstanceIdentifier elanIdentifier = getElanDpnOperationDataPath(elanInstanceName); - return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).toJavaUtil().map( - ElanDpnInterfacesList::getDpnInterfaces).orElse(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, + 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); @@ -817,37 +899,27 @@ public class ElanUtils { installEtreeLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, ifTag, writeFlowGroupTx); } - private void installEtreeLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress, + private void installEtreeLocalDmacFlow(Uint32 elanTag, Uint64 dpId, String ifName, String macAddress, ElanInstance elanInfo, long ifTag, TypedWriteTransaction writeFlowGroupTx) { - EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(ifName).orNull(); + 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); + 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; } @@ -874,25 +946,27 @@ 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, + 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)) { @@ -900,26 +974,25 @@ public class ElanUtils { 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.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, 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); @@ -954,13 +1027,14 @@ 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 { @@ -975,18 +1049,19 @@ public class ElanUtils { } actions = getEgressActionsForInterface(interfaceName, null); } - 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; @@ -999,7 +1074,8 @@ public class ElanUtils { return; } String macAddress = macEntry.getMacAddress().getValue(); - synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) { + try (Acquired lock = lockElanMacDPN(elanInfo.getElanTag().toJava(), + macAddress, interfaceInfo.getDpId())) { deleteMacFlows(elanInfo, interfaceInfo, macAddress, /* alsoDeleteSMAC */ true, flowTx); } } @@ -1009,11 +1085,11 @@ public class ElanUtils { 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, flowTx)) { isFlowsRemovedInSrcDpn = true; @@ -1027,9 +1103,9 @@ public class ElanUtils { } private void executeEtreeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, - boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId, + boolean deleteSmac, String elanInstanceName, Uint64 srcdpId, Uint32 elanTag, Uint64 dstDpId, TypedReadWriteTransaction flowTx) throws ExecutionException, InterruptedException { - EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); + EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue()); if (etreeLeafTag != null) { executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId, etreeLeafTag.getEtreeLeafTag().getValue(), dstDpId, flowTx); @@ -1037,7 +1113,7 @@ public class ElanUtils { } private boolean executeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, - boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId, + boolean deleteSmac, String elanInstanceName, Uint64 srcdpId, Uint32 elanTag, Uint64 dstDpId, TypedReadWriteTransaction flowTx) throws ExecutionException, InterruptedException { boolean isFlowsRemovedInSrcDpn = false; if (dstDpId.equals(srcdpId)) { @@ -1046,30 +1122,39 @@ public class ElanUtils { } else if (isDpnPresent(dstDpId)) { mdsalManager .removeFlow(flowTx, dstDpId, - MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef( - NwConstants.ELAN_DMAC_TABLE, dstDpId, srcdpId, macAddress, elanTag))); + 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, 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 .removeFlow(flowTx, srcdpId, - MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, getKnownDynamicmacFlowRef( - NwConstants.ELAN_SMAC_TABLE, srcdpId, ifTag, macAddress, elanTag))); + MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, + getKnownDynamicmacFlowRef(elanTag, macAddress))); } mdsalManager.removeFlow(flowTx, srcdpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, - getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag))); + 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); } @@ -1093,23 +1178,28 @@ public class ElanUtils { 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 - operTx.put(getElanInstanceOperationalDataPath(elanInstanceName), elanInfo, 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(); - operTx.put(getElanMacTableOperationalDataPath(elanInstanceName), elanMacTable, 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); @@ -1126,10 +1216,11 @@ public class ElanUtils { // 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)) @@ -1137,12 +1228,14 @@ public class ElanUtils { elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance); } ElanInstance elanInstanceWithTag = elanInstanceBuilder.build(); - confTx.merge(ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstanceWithTag, - 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, + private static void addTheLeafTagAsElanTag(String elanInstanceName,Uint32 etreeLeafTag, TypedWriteTransaction tx) { ElanTagName etreeTagAsElanTag = new ElanTagNameBuilder().setElanTag(etreeLeafTag) .withKey(new ElanTagNameKey(etreeLeafTag)).setName(elanInstanceName).build(); @@ -1153,7 +1246,7 @@ public class ElanUtils { 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); @@ -1167,7 +1260,7 @@ public class ElanUtils { } 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) @@ -1181,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 = @@ -1226,7 +1320,7 @@ public class ElanUtils { 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); } /** @@ -1260,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( - 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) { @@ -1303,8 +1397,14 @@ public class ElanUtils { */ 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) { - return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, - createInterfaceStateInstanceIdentifier(interfaceName)).orNull(); + 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; + } } /** @@ -1342,14 +1442,14 @@ public class ElanUtils { 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(@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) { @@ -1365,8 +1465,8 @@ public class ElanUtils { 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; } @@ -1376,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) { @@ -1390,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) { @@ -1398,9 +1498,9 @@ public class ElanUtils { && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeFlat.class); } - public void addDmacRedirectToDispatcherFlows(Long elanTag, String displayName, - String macAddress, List dpnIds) { - for (BigInteger dpId : dpnIds) { + 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, @@ -1408,34 +1508,35 @@ public class ElanUtils { } } - public void removeDmacRedirectToDispatcherFlows(Long elanTag, String macAddress, List dpnIds) { + public void removeDmacRedirectToDispatcherFlows(Uint32 elanTag, String macAddress, List dpnIds) { LoggingFutures.addErrorLogging( txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> { - for (BigInteger dpId : dpnIds) { - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, macAddress, elanTag); + 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); } @Nullable - public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) { + 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); @@ -1452,9 +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 Acquired lockElanMacDPN(long elanTag, String macAddress, Uint64 dpnId) { + return ELAN_LOCKS.acquire(new ElanLockName(elanTag, macAddress, dpnId)); } public static List> @@ -1517,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; } @@ -1540,7 +1640,7 @@ public class ElanUtils { if (macTable == null) { return emptyList(); } - return macTable.getMacEntry(); + return new ArrayList(macTable.getMacEntry().values()); } public boolean isTunnelInLogicalGroup(String interfaceName) { @@ -1561,7 +1661,7 @@ public class ElanUtils { 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); @@ -1577,7 +1677,7 @@ 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); @@ -1591,7 +1691,7 @@ public class ElanUtils { 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)) { @@ -1605,12 +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(BigInteger dpnId, long groupId) { + 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; + } }