X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=elanmanager%2Fimpl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetvirt%2Felan%2Fl2gw%2Futils%2FElanL2GatewayMulticastUtils.java;h=dd289aa192acd3fa2003840afbe0b467153df20f;hb=refs%2Fchanges%2F60%2F89660%2F34;hp=97dfa4922d9790e4c5bbaa0a664db8d34c498835;hpb=85a5359612deb86016401ad2a089b485fb9cb34e;p=netvirt.git diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java index 97dfa4922d..dd289aa192 100644 --- a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java +++ b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java @@ -10,24 +10,24 @@ package org.opendaylight.netvirt.elan.l2gw.utils; import static java.util.Collections.emptyList; import static org.opendaylight.genius.infra.Datastore.CONFIGURATION; import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment; -import static org.opendaylight.netvirt.elan.utils.ElanUtils.requireNonNullElse; +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.SettableFuture; -import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; +import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentMap; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutionException; import javax.inject.Inject; import javax.inject.Singleton; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +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.ManagedNewTransactionRunner; @@ -41,11 +41,18 @@ import org.opendaylight.genius.utils.batching.ResourceBatchingManager; import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils; import org.opendaylight.genius.utils.hwvtep.HwvtepUtils; import org.opendaylight.infrautils.jobcoordinator.JobCoordinator; -import org.opendaylight.infrautils.utils.concurrent.JdkFutures; +import org.opendaylight.infrautils.utils.concurrent.LoggingFutures; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.common.api.CommitInfo; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.mdsal.common.api.ReadFailedException; import org.opendaylight.netvirt.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob; +import org.opendaylight.netvirt.elan.l2gw.jobs.McastUpdateJob; +import org.opendaylight.netvirt.elan.utils.ElanClusterUtils; import org.opendaylight.netvirt.elan.utils.ElanConstants; import org.opendaylight.netvirt.elan.utils.ElanItmUtils; import org.opendaylight.netvirt.elan.utils.ElanUtils; +import org.opendaylight.netvirt.elan.utils.Scheduler; import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils; import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; @@ -80,6 +87,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology. import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Uint64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -101,17 +109,24 @@ public class ElanL2GatewayMulticastUtils { private final ElanUtils elanUtils; private final IMdsalApiManager mdsalManager; private final IInterfaceManager interfaceManager; + private final ElanRefUtil elanRefUtil; + private final ElanClusterUtils elanClusterUtils; + private final Scheduler scheduler; + @Inject - public ElanL2GatewayMulticastUtils(DataBroker broker, ElanItmUtils elanItmUtils, JobCoordinator jobCoordinator, - ElanUtils elanUtils, IMdsalApiManager mdsalManager, IInterfaceManager interfaceManager) { - this.broker = broker; - this.txRunner = new ManagedNewTransactionRunnerImpl(broker); + public ElanL2GatewayMulticastUtils(ElanItmUtils elanItmUtils, ElanUtils elanUtils, IMdsalApiManager mdsalManager, + IInterfaceManager interfaceManager, ElanRefUtil elanRefUtil) { + this.elanRefUtil = elanRefUtil; + this.broker = elanRefUtil.getDataBroker(); + this.txRunner = new ManagedNewTransactionRunnerImpl(elanRefUtil.getDataBroker()); this.elanItmUtils = elanItmUtils; - this.jobCoordinator = jobCoordinator; + this.jobCoordinator = elanRefUtil.getJobCoordinator(); this.elanUtils = elanUtils; this.mdsalManager = mdsalManager; this.interfaceManager = interfaceManager; + this.elanClusterUtils = elanRefUtil.getElanClusterUtils(); + this.scheduler = elanRefUtil.getScheduler(); } /** @@ -121,7 +136,7 @@ public class ElanL2GatewayMulticastUtils { */ public void handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) { InstanceIdentifier tepPath = buildExternalTepPath(elanName, device.getTunnelIp()); - JdkFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, + LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.put(tepPath, buildExternalTeps(device))), LOG, "Failed to write to config external tep {}", tepPath); updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */); @@ -145,8 +160,8 @@ public class ElanL2GatewayMulticastUtils { * the elan to be updated */ public void updateRemoteMcastMacOnElanL2GwDevices(String elanName) { - for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) { - prepareRemoteMcastMacUpdateOnDevice(elanName, device); + for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName)) { + prepareRemoteMcastMacUpdateOnDevice(elanName, device, false, null); } } @@ -164,17 +179,62 @@ public class ElanL2GatewayMulticastUtils { * the device */ public void updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) { - prepareRemoteMcastMacUpdateOnDevice(elanName, device); + prepareRemoteMcastMacUpdateOnDevice(elanName, device, false, null); } - public void prepareRemoteMcastMacUpdateOnDevice(String elanName, - L2GatewayDevice device) { - ConcurrentMap elanL2gwDevices = ElanL2GwCacheUtils - .getInvolvedL2GwDevices(elanName); - List dpns = elanUtils.getElanDPNByName(elanName); + public ListenableFuture prepareRemoteMcastMacUpdateOnDevice(String elanName, L2GatewayDevice device, + boolean addCase, IpAddress removedDstTep) { + NodeId dstNodeId = new NodeId(device.getHwvtepNodeId()); + RemoteMcastMacs existingMac = null; + try { + Optional mac = elanRefUtil.getConfigMcastCache().get(getRemoteMcastIid(dstNodeId, + elanName)); + if (mac.isPresent()) { + existingMac = mac.get(); + } + } catch (ReadFailedException e) { + LOG.error("Failed to read iid for elan {}", elanName, e); + } + + if (!addCase && removedDstTep != null) { + LOG.debug(" RemoteMcast update delete tep {} of elan {} ", removedDstTep.getIpv4Address().getValue(), + elanName); + //incase of dpn flap immediately after cluster reboot just remove its tep alone + if (existingMac != null) { + return deleteLocatorFromMcast(elanName, dstNodeId, removedDstTep, existingMac); + } + } + Collection elanL2gwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName); + Collection dpns = elanRefUtil.getElanInstanceDpnsCache().get(elanName); List dpnsTepIps = getAllTepIpsOfDpns(device, dpns); List l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices); - prepareRemoteMcastMacEntry(elanName, device, dpnsTepIps, l2GwDevicesTepIps); + return prepareRemoteMcastMacEntry(elanName, device, dpnsTepIps, l2GwDevicesTepIps, addCase); + } + + private ListenableFuture deleteLocatorFromMcast(String elanName, NodeId dstNodeId, + IpAddress removedDstTep, + RemoteMcastMacs existingMac) { + + LocatorSet tobeDeleted = buildLocatorSet(dstNodeId, removedDstTep); + RemoteMcastMacsBuilder newMacBuilder = new RemoteMcastMacsBuilder(existingMac); + + List locatorList = new ArrayList<>(existingMac.nonnullLocatorSet()); + locatorList.remove(tobeDeleted); + newMacBuilder.setLocatorSet(locatorList); + RemoteMcastMacs mac = newMacBuilder.build(); + //configMcastCache.add(macIid, mac); + InstanceIdentifier macIid = HwvtepSouthboundUtils + .createRemoteMcastMacsInstanceIdentifier(dstNodeId, existingMac.key()); + return ResourceBatchingManager.getInstance().put( + ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, macIid, mac); + } + + LocatorSet buildLocatorSet(NodeId nodeId, IpAddress tepIp) { + HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils + .createHwvtepPhysicalLocatorAugmentation(tepIp.stringValue()); + HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef( + HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug)); + return new LocatorSetBuilder().setLocatorRef(phyLocRef).build(); } /** @@ -189,62 +249,45 @@ public class ElanL2GatewayMulticastUtils { * @param updateThisDevice * the update this device */ - private void updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device, + public void updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device, boolean updateThisDevice) { - - SettableFuture ft = SettableFuture.create(); - ft.set(null); - - List dpns = elanUtils.getElanDPNByName(elanName); - - ConcurrentMap devices = ElanL2GwCacheUtils - .getInvolvedL2GwDevices(elanName); - - List dpnsTepIps = getAllTepIpsOfDpns(device, dpns); - List l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices); - // if (allTepIps.size() < 2) { - // LOG.debug("no other devices are found in the elan {}", elanName); - // return ft; - // } - if (updateThisDevice) { - prepareRemoteMcastMacEntry(elanName, device, dpnsTepIps, l2GwDevicesTepIps); - } - - // TODO: Need to revisit below logic as logical switches might not be - // present to configure RemoteMcastMac entry - for (L2GatewayDevice otherDevice : devices.values()) { - if (!otherDevice.getDeviceName().equals(device.getDeviceName())) { - prepareRemoteMcastMacEntry(elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps); - } + McastUpdateJob.updateAllMcastsForConnectionAdd(elanName, this, elanClusterUtils); + } else { + McastUpdateJob.updateAllMcastsForConnectionDelete(elanName, this, elanClusterUtils, device); } } - public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo, + public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo, boolean createCase, TypedWriteTransaction confTx) { List dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName()); for (DpnInterfaces dpn : dpns) { - setupElanBroadcastGroups(elanInfo, dpn.getDpId(), confTx); + setupStandardElanBroadcastGroups(elanInfo, null, dpn.getDpId(), createCase, confTx); } } - public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId, + public void setupElanBroadcastGroups(ElanInstance elanInfo, Uint64 dpnId, TypedWriteTransaction confTx) { setupElanBroadcastGroups(elanInfo, null, dpnId, confTx); } - public void setupElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, BigInteger dpnId, - TypedWriteTransaction confTx) { + public void setupElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, Uint64 dpnId, + TypedWriteTransaction confTx) { setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx); setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx); } + public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, Uint64 dpnId, + TypedWriteTransaction confTx) { + setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, true, confTx); + } + public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, - BigInteger dpnId, TypedWriteTransaction confTx) { + Uint64 dpnId, boolean createCase, TypedWriteTransaction confTx) { List listBucket = new ArrayList<>(); int bucketId = 0; int actionKey = 0; - Long elanTag = elanInfo.getElanTag(); + Long elanTag = elanInfo.getElanTag().toJava(); List listAction = new ArrayList<>(); listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey)); listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, @@ -256,14 +299,18 @@ public class ElanL2GatewayMulticastUtils { Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket)); LOG.trace("Installing the remote BroadCast Group:{}", group); - mdsalManager.addGroup(confTx, dpnId, group); + if (createCase) { + elanUtils.syncUpdateGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND, confTx); + } else { + mdsalManager.addGroup(confTx, dpnId, group); + } } public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, - BigInteger dpnId, TypedWriteTransaction confTx) { + Uint64 dpnId, TypedWriteTransaction confTx) { EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class); if (etreeInstance != null) { - long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue(); + long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava(); List listBucket = new ArrayList<>(); int bucketId = 0; int actionKey = 0; @@ -284,10 +331,9 @@ public class ElanL2GatewayMulticastUtils { } @Nullable - private DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) { + private static DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, Uint64 dpnId) { if (elanDpns != null) { - for (DpnInterfaces dpnInterface : requireNonNullElse(elanDpns.getDpnInterfaces(), - Collections.emptyList())) { + for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces().values()) { if (Objects.equals(dpnInterface.getDpId(), dpnId)) { return dpnInterface; } @@ -297,7 +343,7 @@ public class ElanL2GatewayMulticastUtils { } private List getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns, - DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) { + DpnInterfaces dpnInterfaces, Uint64 dpnId, int bucketId) { DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId); if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId()) || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) { @@ -317,16 +363,18 @@ public class ElanL2GatewayMulticastUtils { return listBucketInfo; } - @Nonnull + @NonNull public List getRemoteBCGroupBuckets(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, - BigInteger dpnId, int bucketId, long elanTag) { + Uint64 dpnId, int bucketId, long elanTag) { List listBucketInfo = new ArrayList<>(); ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName()); if (isVxlanNetworkOrVxlanSegment(elanInfo)) { + // Adding 270000 to avoid collision between LPort and elan for broadcast group actions listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId, elanUtils.isOpenstackVniSemanticsEnforced() - ? ElanUtils.getVxlanSegmentationId(elanInfo) : elanTag)); + ? ElanUtils.getVxlanSegmentationId(elanInfo).longValue() : elanTag + + ElanConstants.ELAN_TAG_ADDEND)); } listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId, getNextAvailableBucketId(listBucketInfo.size()))); @@ -335,19 +383,17 @@ public class ElanL2GatewayMulticastUtils { return listBucketInfo; } - public List getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId, + public List getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, Uint64 dpnId, int bucketId) { List listBucketInfo = new ArrayList<>(); - ConcurrentMap map = ElanL2GwCacheUtils - .getInvolvedL2GwDevices(elanInfo.getElanInstanceName()); - for (L2GatewayDevice device : map.values()) { + for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInfo.getElanInstanceName())) { String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId), device.getHwvtepNodeId()); if (interfaceName == null) { continue; } List listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName, - ElanUtils.getVxlanSegmentationId(elanInfo), true); + ElanUtils.getVxlanSegmentationId(elanInfo).longValue(), true); listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP)); bucketId++; @@ -355,27 +401,27 @@ public class ElanL2GatewayMulticastUtils { return listBucketInfo; } - public List getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, BigInteger dpnId, + public List getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, Uint64 dpnId, int bucketId) { ElanInstance operElanInstance = null; try { operElanInstance = new SingleTransactionDataBroker(broker).syncReadOptional( LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, elanInfo.key()) - .build()).orNull(); - } catch (ReadFailedException e) { + .build()).orElse(null); + } catch (InterruptedException | ExecutionException e) { LOG.error("Failed to read elan instance operational path {}", elanInfo, e); return emptyList(); } if (operElanInstance == null) { return emptyList(); } - List teps = operElanInstance.getExternalTeps(); + Map teps = operElanInstance.getExternalTeps(); if (teps == null || teps.isEmpty()) { return emptyList(); } List listBucketInfo = new ArrayList<>(); - for (ExternalTeps tep : teps) { + for (ExternalTeps tep : teps.values()) { String externalTep = tep.getNodeid() != null ? tep.getNodeid() : tep.getTepIp().toString(); String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId), externalTep); @@ -384,7 +430,7 @@ public class ElanL2GatewayMulticastUtils { continue; } List listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName, - ElanUtils.getVxlanSegmentationId(elanInfo), false); + ElanUtils.getVxlanSegmentationId(elanInfo).longValue(), false); listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP)); bucketId++; @@ -392,22 +438,23 @@ public class ElanL2GatewayMulticastUtils { return listBucketInfo; } - private int getNextAvailableBucketId(int bucketSize) { + private static int getNextAvailableBucketId(int bucketSize) { return bucketSize + 1; } @SuppressWarnings("checkstyle:IllegalCatch") - private List getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId, + private List getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, Uint64 dpnId, int bucketId, long elanTagOrVni) { List listBucketInfo = new ArrayList<>(); if (elanDpns != null) { - for (DpnInterfaces dpnInterface : requireNonNullElse(elanDpns.getDpnInterfaces(), - Collections.emptyList())) { - if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpnId) - && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) { + for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces().values()) { + if (!Objects.equals(dpnInterface.getDpId(), dpnId) && dpnInterface.getInterfaces() != null + && !dpnInterface.getInterfaces().isEmpty()) { try { List listActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(dpnId, dpnInterface.getDpId(), elanTagOrVni); + LOG.trace("configuring broadcast group for elan {} for source DPN {} and destination DPN {} " + + "with actions {}", elanTagOrVni, dpnId, dpnInterface.getDpId(), listActionInfo); if (listActionInfo.isEmpty()) { continue; } @@ -437,9 +484,9 @@ public class ElanL2GatewayMulticastUtils { * the l2 gw devices tep ips * @return the write transaction */ - private void prepareRemoteMcastMacEntry(String elanName, + private ListenableFuture prepareRemoteMcastMacEntry(String elanName, L2GatewayDevice device, List dpnsTepIps, - List l2GwDevicesTepIps) { + List l2GwDevicesTepIps, boolean addCase) { NodeId nodeId = new NodeId(device.getHwvtepNodeId()); ArrayList remoteTepIps = new ArrayList<>(l2GwDevicesTepIps); @@ -473,9 +520,9 @@ public class ElanL2GatewayMulticastUtils { remoteTepIps.add(dhcpDesignatedSwitchTepIp); } String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName); - putRemoteMcastMac(nodeId, logicalSwitchName, remoteTepIps); LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(), remoteTepIps); + return putRemoteMcastMac(nodeId, logicalSwitchName, remoteTepIps, addCase); } /** @@ -488,8 +535,8 @@ public class ElanL2GatewayMulticastUtils { * @param tepIps * the tep ips */ - private static void putRemoteMcastMac(NodeId nodeId, String logicalSwitchName, - ArrayList tepIps) { + private ListenableFuture putRemoteMcastMac(NodeId nodeId, String logicalSwitchName, + ArrayList tepIps, boolean addCase) { List locators = new ArrayList<>(); for (IpAddress tepIp : tepIps) { HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils @@ -501,16 +548,49 @@ public class ElanL2GatewayMulticastUtils { HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName))); - RemoteMcastMacs remoteMcastMac = new RemoteMcastMacsBuilder() + RemoteMcastMacs newRemoteMcastMac = new RemoteMcastMacsBuilder() .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef) .setLocatorSet(locators).build(); InstanceIdentifier iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId, - remoteMcastMac.key()); - ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, - iid, remoteMcastMac); + newRemoteMcastMac.key()); + RemoteMcastMacs existingRemoteMcastMac = null; + try { + Optional mac = elanRefUtil.getConfigMcastCache().get(iid); + if (mac.isPresent()) { + existingRemoteMcastMac = mac.get(); + } + } catch (ReadFailedException e) { + LOG.error("Failed to read iid {}", iid, e); + } + + if (addCase && areLocatorsAlreadyConfigured(existingRemoteMcastMac, newRemoteMcastMac)) { + return Futures.immediateFuture(null); + } + + return ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, + iid, newRemoteMcastMac); } + private boolean areLocatorsAlreadyConfigured(RemoteMcastMacs existingMac, RemoteMcastMacs newMac) { + if (existingMac == null) { + return false; + } + Set existingLocators = new HashSet<>(existingMac.getLocatorSet()); + List newLocators = newMac.getLocatorSet(); + return existingLocators.containsAll(newLocators); + } + + private InstanceIdentifier getRemoteMcastIid(NodeId nodeId, String logicalSwitchName) { + HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils + .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName))); + RemoteMcastMacs remoteMcastMac = new RemoteMcastMacsBuilder() + .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef) + .build(); + return HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId, + remoteMcastMac.key()); + } + /** * Gets all the tep ips of dpns. * @@ -520,7 +600,7 @@ public class ElanL2GatewayMulticastUtils { * the dpns * @return the all tep ips of dpns and devices */ - private List getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List dpns) { + private List getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, Collection dpns) { List tepIps = new ArrayList<>(); for (DpnInterfaces dpn : dpns) { IpAddress internalTunnelIp = elanItmUtils.getSourceDpnTepIp(dpn.getDpId(), @@ -539,9 +619,9 @@ public class ElanL2GatewayMulticastUtils { * the devices * @return the all tep ips of l2 gw devices */ - private static List getAllTepIpsOfL2GwDevices(ConcurrentMap devices) { + private static List getAllTepIpsOfL2GwDevices(Collection devices) { List tepIps = new ArrayList<>(); - for (L2GatewayDevice otherDevice : devices.values()) { + for (L2GatewayDevice otherDevice : devices) { // There is no need to add the same tep ip to the list. if (!tepIps.contains(otherDevice.getTunnelIp())) { tepIps.add(otherDevice.getTunnelIp()); @@ -559,13 +639,13 @@ public class ElanL2GatewayMulticastUtils { * the l2 gateway device * @return the listenable future */ - public List> handleMcastForElanL2GwDeviceDelete(String elanName, + public List> handleMcastForElanL2GwDeviceDelete(String elanName, L2GatewayDevice l2GatewayDevice) { - ListenableFuture deleteTepFuture = + FluentFuture deleteTepFuture = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.delete(buildExternalTepPath(elanName, l2GatewayDevice.getTunnelIp()))); updateMcastMacsForAllElanDevices(elanName, l2GatewayDevice, false/* updateThisDevice */); - ListenableFuture deleteRemoteMcastMacFuture = deleteRemoteMcastMac( + FluentFuture deleteRemoteMcastMacFuture = deleteRemoteMcastMac( new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName); return Arrays.asList(deleteRemoteMcastMacFuture, deleteTepFuture); } @@ -579,7 +659,7 @@ public class ElanL2GatewayMulticastUtils { * the logical switch name * @return the listenable future */ - private ListenableFuture deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) { + public FluentFuture deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) { InstanceIdentifier logicalSwitch = HwvtepSouthboundUtils .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)); RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch), @@ -609,7 +689,7 @@ public class ElanL2GatewayMulticastUtils { DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(), elanInstanceName); if (desgSwitch != null) { - tepIp = elanItmUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()), + tepIp = elanItmUtils.getSourceDpnTepIp(Uint64.valueOf(desgSwitch.getDpId()), new NodeId(l2GwDevice.getHwvtepNodeId())); } return tepIp; @@ -626,11 +706,22 @@ public class ElanL2GatewayMulticastUtils { */ public DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp, String elanInstanceName) { - InstanceIdentifier instanceIdentifier = InstanceIdentifier + try { + InstanceIdentifier instanceIdentifier = InstanceIdentifier .builder(DesignatedSwitchesForExternalTunnels.class) - .child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp)) + .child(DesignatedSwitchForTunnel.class, + new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp)) .build(); - return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier).orNull(); + return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier) + .orElse(null); + } catch (ExecutionException e) { + LOG.error("Exception while retriving DesignatedSwitch for elan {} and tunnel {}", + elanInstanceName, tunnelIp, e); + } catch (InterruptedException e) { + LOG.error("Exception while retriving DesignatedSwitch for elan {} and tunnel {}", + elanInstanceName, tunnelIp, e); + } + return null; } }