2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.elan.l2gw.utils;
10 import static java.util.Collections.emptyList;
11 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
12 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
14 import com.google.common.util.concurrent.FluentFuture;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collection;
20 import java.util.HashSet;
21 import java.util.List;
23 import java.util.Objects;
24 import java.util.Optional;
26 import java.util.concurrent.ExecutionException;
27 import javax.inject.Inject;
28 import javax.inject.Singleton;
29 import org.eclipse.jdt.annotation.NonNull;
30 import org.eclipse.jdt.annotation.Nullable;
31 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
32 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
33 import org.opendaylight.genius.mdsalutil.MDSALUtil;
34 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
35 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
36 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
37 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
38 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
39 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
40 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
41 import org.opendaylight.mdsal.binding.api.DataBroker;
42 import org.opendaylight.mdsal.binding.util.Datastore;
43 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
44 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
45 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
46 import org.opendaylight.mdsal.common.api.CommitInfo;
47 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
48 import org.opendaylight.mdsal.common.api.ReadFailedException;
49 import org.opendaylight.netvirt.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
50 import org.opendaylight.netvirt.elan.l2gw.jobs.McastUpdateJob;
51 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
52 import org.opendaylight.netvirt.elan.utils.ElanConstants;
53 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
54 import org.opendaylight.netvirt.elan.utils.ElanUtils;
55 import org.opendaylight.netvirt.elan.utils.Scheduler;
56 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
57 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
86 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
87 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
88 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
89 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
90 import org.opendaylight.yangtools.yang.common.Uint64;
91 import org.slf4j.Logger;
92 import org.slf4j.LoggerFactory;
95 * The utility class to handle ELAN L2 Gateway related to multicast.
98 public class ElanL2GatewayMulticastUtils {
100 /** The Constant LOG. */
101 private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
104 private final DataBroker broker;
105 private final ManagedNewTransactionRunner txRunner;
107 private final ElanItmUtils elanItmUtils;
108 private final JobCoordinator jobCoordinator;
109 private final ElanUtils elanUtils;
110 private final IMdsalApiManager mdsalManager;
111 private final IInterfaceManager interfaceManager;
112 private final ElanRefUtil elanRefUtil;
113 private final ElanClusterUtils elanClusterUtils;
114 private final Scheduler scheduler;
118 public ElanL2GatewayMulticastUtils(ElanItmUtils elanItmUtils, ElanUtils elanUtils, IMdsalApiManager mdsalManager,
119 IInterfaceManager interfaceManager, ElanRefUtil elanRefUtil) {
120 this.elanRefUtil = elanRefUtil;
121 this.broker = elanRefUtil.getDataBroker();
122 this.txRunner = new ManagedNewTransactionRunnerImpl(elanRefUtil.getDataBroker());
123 this.elanItmUtils = elanItmUtils;
124 this.jobCoordinator = elanRefUtil.getJobCoordinator();
125 this.elanUtils = elanUtils;
126 this.mdsalManager = mdsalManager;
127 this.interfaceManager = interfaceManager;
128 this.elanClusterUtils = elanRefUtil.getElanClusterUtils();
129 this.scheduler = elanRefUtil.getScheduler();
133 * Handle mcast for elan l2 gw device add.
134 * @param elanName the elan name
135 * @param device the device
137 public void handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
138 InstanceIdentifier<ExternalTeps> tepPath = buildExternalTepPath(elanName, device.getTunnelIp());
139 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
140 tx -> tx.put(tepPath, buildExternalTeps(device))), LOG, "Failed to write to config external tep {}",
142 updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
145 public static InstanceIdentifier<ExternalTeps> buildExternalTepPath(String elan, IpAddress tepIp) {
146 return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elan))
147 .child(ExternalTeps.class, new ExternalTepsKey(tepIp)).build();
150 protected ExternalTeps buildExternalTeps(L2GatewayDevice device) {
151 return new ExternalTepsBuilder().setTepIp(device.getTunnelIp()).setNodeid(device.getHwvtepNodeId()).build();
155 * Updates the remote mcast mac table for all the devices in this elan
156 * includes all the dpn tep ips and other devices tep ips in broadcast
160 * the elan to be updated
162 public void updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
163 for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName)) {
164 prepareRemoteMcastMacUpdateOnDevice(elanName, device, false, null);
168 public void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
169 HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(this, elanName,device);
170 jobCoordinator.enqueueJob(job.getJobKey(), job);
174 * Update remote mcast mac on elan l2 gw device.
181 public void updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
182 prepareRemoteMcastMacUpdateOnDevice(elanName, device, false, null);
185 public ListenableFuture<Void> prepareRemoteMcastMacUpdateOnDevice(String elanName, L2GatewayDevice device,
186 boolean addCase, IpAddress removedDstTep) {
187 NodeId dstNodeId = new NodeId(device.getHwvtepNodeId());
188 RemoteMcastMacs existingMac = null;
190 Optional<RemoteMcastMacs> mac = elanRefUtil.getConfigMcastCache().get(getRemoteMcastIid(dstNodeId,
192 if (mac.isPresent()) {
193 existingMac = mac.get();
195 } catch (ReadFailedException e) {
196 LOG.error("Failed to read iid for elan {}", elanName, e);
199 if (!addCase && removedDstTep != null) {
200 LOG.debug(" RemoteMcast update delete tep {} of elan {} ", removedDstTep.getIpv4Address().getValue(),
202 //incase of dpn flap immediately after cluster reboot just remove its tep alone
203 if (existingMac != null) {
204 return deleteLocatorFromMcast(elanName, dstNodeId, removedDstTep, existingMac);
207 Collection<L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
208 Collection<DpnInterfaces> dpns = elanRefUtil.getElanInstanceDpnsCache().get(elanName);
209 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
210 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
211 return prepareRemoteMcastMacEntry(elanName, device, dpnsTepIps, l2GwDevicesTepIps, addCase);
214 private ListenableFuture<Void> deleteLocatorFromMcast(String elanName, NodeId dstNodeId,
215 IpAddress removedDstTep,
216 RemoteMcastMacs existingMac) {
218 LocatorSet tobeDeleted = buildLocatorSet(dstNodeId, removedDstTep);
219 RemoteMcastMacsBuilder newMacBuilder = new RemoteMcastMacsBuilder(existingMac);
221 List<LocatorSet> locatorList = new ArrayList<>(existingMac.nonnullLocatorSet());
222 locatorList.remove(tobeDeleted);
223 newMacBuilder.setLocatorSet(locatorList);
224 RemoteMcastMacs mac = newMacBuilder.build();
225 //configMcastCache.add(macIid, mac);
226 InstanceIdentifier<RemoteMcastMacs> macIid = HwvtepSouthboundUtils
227 .createRemoteMcastMacsInstanceIdentifier(dstNodeId, existingMac.key());
228 return ResourceBatchingManager.getInstance().put(
229 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, macIid, mac);
232 LocatorSet buildLocatorSet(NodeId nodeId, IpAddress tepIp) {
233 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
234 .createHwvtepPhysicalLocatorAugmentation(tepIp.stringValue());
235 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
236 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
237 return new LocatorSetBuilder().setLocatorRef(phyLocRef).build();
241 * Update mcast macs for this elan.
242 * for all dpns in this elan recompute and update broadcast group
243 * for all l2gw devices in this elan recompute and update remote mcast mac entry
249 * @param updateThisDevice
250 * the update this device
252 public void updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
253 boolean updateThisDevice) {
254 if (updateThisDevice) {
255 McastUpdateJob.updateAllMcastsForConnectionAdd(elanName, this, elanClusterUtils);
257 McastUpdateJob.updateAllMcastsForConnectionDelete(elanName, this, elanClusterUtils, device);
261 public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo, boolean createCase,
262 TypedWriteTransaction<Datastore.Configuration> confTx) {
263 List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
264 for (DpnInterfaces dpn : dpns) {
265 setupStandardElanBroadcastGroups(elanInfo, null, dpn.getDpId(), createCase, confTx);
269 public void setupElanBroadcastGroups(ElanInstance elanInfo, Uint64 dpnId,
270 TypedWriteTransaction<Datastore.Configuration> confTx) {
271 setupElanBroadcastGroups(elanInfo, null, dpnId, confTx);
274 public void setupElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, Uint64 dpnId,
275 TypedWriteTransaction<Datastore.Configuration> confTx) {
276 setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
277 setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
280 public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, Uint64 dpnId,
281 TypedWriteTransaction<Datastore.Configuration> confTx) {
282 setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, true, confTx);
285 public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
286 Uint64 dpnId, boolean createCase, TypedWriteTransaction<Datastore.Configuration> confTx) {
287 List<Bucket> listBucket = new ArrayList<>();
290 Long elanTag = elanInfo.getElanTag().toJava();
291 List<Action> listAction = new ArrayList<>();
292 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
293 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
294 MDSALUtil.WATCH_GROUP));
296 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId, elanTag);
297 listBucket.addAll(listBucketInfoRemote);
298 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
299 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
300 MDSALUtil.buildBucketLists(listBucket));
301 LOG.trace("Installing the remote BroadCast Group:{}", group);
303 elanUtils.syncUpdateGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND, confTx);
305 mdsalManager.addGroup(confTx, dpnId, group);
309 public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
310 Uint64 dpnId, TypedWriteTransaction<Datastore.Configuration> confTx) {
311 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
312 if (etreeInstance != null) {
313 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava();
314 List<Bucket> listBucket = new ArrayList<>();
317 List<Action> listAction = new ArrayList<>();
318 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag)).buildAction(++actionKey));
319 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
320 MDSALUtil.WATCH_GROUP));
322 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
324 listBucket.addAll(listBucketInfoRemote);
325 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
326 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
327 MDSALUtil.buildBucketLists(listBucket));
328 LOG.trace("Installing the remote BroadCast Group:{}", group);
329 mdsalManager.addGroup(confTx, dpnId, group);
334 private static DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, Uint64 dpnId) {
335 if (elanDpns != null) {
336 for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces().values()) {
337 if (Objects.equals(dpnInterface.getDpId(), dpnId)) {
345 private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns,
346 DpnInterfaces dpnInterfaces, Uint64 dpnId, int bucketId) {
347 DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
348 if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
349 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
352 List<Bucket> listBucketInfo = new ArrayList<>();
353 for (String interfaceName : currDpnInterfaces.getInterfaces()) {
354 if (interfaceManager.isExternalInterface(interfaceName)) {
355 List<Action> listActionInfo = elanItmUtils.getExternalPortItmEgressAction(interfaceName);
356 if (!listActionInfo.isEmpty()) {
357 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
358 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
363 return listBucketInfo;
367 public List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
368 Uint64 dpnId, int bucketId, long elanTag) {
369 List<Bucket> listBucketInfo = new ArrayList<>();
370 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
372 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
373 // Adding 270000 to avoid collision between LPort and elan for broadcast group actions
374 listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId,
375 elanUtils.isOpenstackVniSemanticsEnforced()
376 ? ElanUtils.getVxlanSegmentationId(elanInfo).longValue() : elanTag
377 + ElanConstants.ELAN_TAG_ADDEND));
379 listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId,
380 getNextAvailableBucketId(listBucketInfo.size())));
381 listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanExternalTeps(elanInfo, dpnId,
382 getNextAvailableBucketId(listBucketInfo.size())));
383 return listBucketInfo;
386 public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, Uint64 dpnId,
388 List<Bucket> listBucketInfo = new ArrayList<>();
389 for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInfo.getElanInstanceName())) {
390 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
391 device.getHwvtepNodeId());
392 if (interfaceName == null) {
395 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
396 ElanUtils.getVxlanSegmentationId(elanInfo).longValue(), true);
397 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
398 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
401 return listBucketInfo;
404 public List<Bucket> getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, Uint64 dpnId,
406 ElanInstance operElanInstance = null;
408 operElanInstance = new SingleTransactionDataBroker(broker).syncReadOptional(
409 LogicalDatastoreType.OPERATIONAL,
410 InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, elanInfo.key())
411 .build()).orElse(null);
412 } catch (InterruptedException | ExecutionException e) {
413 LOG.error("Failed to read elan instance operational path {}", elanInfo, e);
416 if (operElanInstance == null) {
419 Map<ExternalTepsKey, ExternalTeps> teps = operElanInstance.nonnullExternalTeps();
420 if (teps == null || teps.isEmpty()) {
423 List<Bucket> listBucketInfo = new ArrayList<>();
424 for (ExternalTeps tep : teps.values()) {
425 String externalTep = tep.getNodeid() != null ? tep.getNodeid() : tep.getTepIp().toString();
426 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
428 if (interfaceName == null) {
429 LOG.error("Could not get interface name to ext tunnel {} {}", dpnId, tep.getTepIp());
432 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
433 ElanUtils.getVxlanSegmentationId(elanInfo).longValue(), false);
434 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
435 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
438 return listBucketInfo;
441 private static int getNextAvailableBucketId(int bucketSize) {
442 return bucketSize + 1;
445 @SuppressWarnings("checkstyle:IllegalCatch")
446 private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, Uint64 dpnId, int bucketId,
448 List<Bucket> listBucketInfo = new ArrayList<>();
449 if (elanDpns != null) {
450 for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces().values()) {
451 if (!Objects.equals(dpnInterface.getDpId(), dpnId) && dpnInterface.getInterfaces() != null
452 && !dpnInterface.getInterfaces().isEmpty()) {
454 List<Action> listActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(dpnId,
455 dpnInterface.getDpId(), elanTagOrVni);
456 LOG.trace("configuring broadcast group for elan {} for source DPN {} and destination DPN {} "
457 + "with actions {}", elanTagOrVni, dpnId, dpnInterface.getDpId(), listActionInfo);
458 if (listActionInfo.isEmpty()) {
461 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
462 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
464 } catch (Exception ex) {
465 LOG.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
466 dpnId, dpnInterface.getDpId(), ex);
471 return listBucketInfo;
475 * Update remote mcast mac.
483 * @param l2GwDevicesTepIps
484 * the l2 gw devices tep ips
485 * @return the write transaction
487 private ListenableFuture<Void> prepareRemoteMcastMacEntry(String elanName,
488 L2GatewayDevice device, List<IpAddress> dpnsTepIps,
489 List<IpAddress> l2GwDevicesTepIps, boolean addCase) {
490 NodeId nodeId = new NodeId(device.getHwvtepNodeId());
492 ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
493 remoteTepIps.remove(device.getTunnelIp());
494 remoteTepIps.addAll(dpnsTepIps);
495 IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
496 if (dpnsTepIps.isEmpty()) {
497 // If no dpns in elan, configure dhcp designated switch Tep Ip as a
498 // physical locator in l2 gw device
499 if (dhcpDesignatedSwitchTepIp != null) {
500 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
502 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
503 .createHwvtepPhysicalLocatorAugmentation(dhcpDesignatedSwitchTepIp);
504 InstanceIdentifier<TerminationPoint> iid =
505 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug);
506 TerminationPoint terminationPoint = new TerminationPointBuilder()
507 .withKey(HwvtepSouthboundUtils.getTerminationPointKey(phyLocatorAug))
508 .addAugmentation(HwvtepPhysicalLocatorAugmentation.class, phyLocatorAug).build();
509 ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
510 iid, terminationPoint);
511 LOG.info("Adding PhysicalLocator for node: {} with Dhcp designated switch Tep Ip {} "
512 + "as physical locator, elan {}", device.getHwvtepNodeId(),
513 dhcpDesignatedSwitchTepIp.stringValue(), elanName);
515 LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
516 device.getHwvtepNodeId(), elanName);
519 if (dhcpDesignatedSwitchTepIp != null && !remoteTepIps.contains(dhcpDesignatedSwitchTepIp)) {
520 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
522 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
523 LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
525 return putRemoteMcastMac(nodeId, logicalSwitchName, remoteTepIps, addCase);
529 * Put remote mcast mac in config DS.
533 * @param logicalSwitchName
534 * the logical switch name
538 private ListenableFuture<Void> putRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
539 ArrayList<IpAddress> tepIps, boolean addCase) {
540 List<LocatorSet> locators = new ArrayList<>();
541 for (IpAddress tepIp : tepIps) {
542 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
543 .createHwvtepPhysicalLocatorAugmentation(tepIp);
544 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
545 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
546 locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
549 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
550 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
551 RemoteMcastMacs newRemoteMcastMac = new RemoteMcastMacsBuilder()
552 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
553 .setLocatorSet(locators).build();
554 InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
555 newRemoteMcastMac.key());
556 RemoteMcastMacs existingRemoteMcastMac = null;
558 Optional<RemoteMcastMacs> mac = elanRefUtil.getConfigMcastCache().get(iid);
559 if (mac.isPresent()) {
560 existingRemoteMcastMac = mac.get();
562 } catch (ReadFailedException e) {
563 LOG.error("Failed to read iid {}", iid, e);
566 if (addCase && areLocatorsAlreadyConfigured(existingRemoteMcastMac, newRemoteMcastMac)) {
567 return Futures.immediateFuture(null);
570 return ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
571 iid, newRemoteMcastMac);
575 private boolean areLocatorsAlreadyConfigured(RemoteMcastMacs existingMac, RemoteMcastMacs newMac) {
576 if (existingMac == null) {
579 Set existingLocators = new HashSet<>(existingMac.getLocatorSet());
580 List newLocators = newMac.getLocatorSet();
581 return existingLocators.containsAll(newLocators);
584 private InstanceIdentifier<RemoteMcastMacs> getRemoteMcastIid(NodeId nodeId, String logicalSwitchName) {
585 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
586 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
587 RemoteMcastMacs remoteMcastMac = new RemoteMcastMacsBuilder()
588 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
590 return HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
591 remoteMcastMac.key());
595 * Gets all the tep ips of dpns.
601 * @return the all tep ips of dpns and devices
603 private List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, Collection<DpnInterfaces> dpns) {
604 List<IpAddress> tepIps = new ArrayList<>();
605 for (DpnInterfaces dpn : dpns) {
606 IpAddress internalTunnelIp = elanItmUtils.getSourceDpnTepIp(dpn.getDpId(),
607 new NodeId(l2GwDevice.getHwvtepNodeId()));
608 if (internalTunnelIp != null) {
609 tepIps.add(internalTunnelIp);
616 * Gets the all tep ips of l2 gw devices.
620 * @return the all tep ips of l2 gw devices
622 private static List<IpAddress> getAllTepIpsOfL2GwDevices(Collection<L2GatewayDevice> devices) {
623 List<IpAddress> tepIps = new ArrayList<>();
624 for (L2GatewayDevice otherDevice : devices) {
625 // There is no need to add the same tep ip to the list.
626 if (!tepIps.contains(otherDevice.getTunnelIp())) {
627 tepIps.add(otherDevice.getTunnelIp());
634 * Handle mcast for elan l2 gw device delete.
637 * the elan instance name
638 * @param l2GatewayDevice
639 * the l2 gateway device
640 * @return the listenable future
642 public List<FluentFuture<?>> handleMcastForElanL2GwDeviceDelete(String elanName,
643 L2GatewayDevice l2GatewayDevice) {
644 FluentFuture<?> deleteTepFuture =
645 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
646 tx -> tx.delete(buildExternalTepPath(elanName, l2GatewayDevice.getTunnelIp())));
647 updateMcastMacsForAllElanDevices(elanName, l2GatewayDevice, false/* updateThisDevice */);
648 FluentFuture<?> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
649 new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName);
650 return Arrays.asList(deleteRemoteMcastMacFuture, deleteTepFuture);
654 * Delete remote mcast mac from Hwvtep node.
658 * @param logicalSwitchName
659 * the logical switch name
660 * @return the listenable future
662 public FluentFuture<? extends @NonNull CommitInfo> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
663 InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
664 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
665 RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
666 new MacAddress(ElanConstants.UNKNOWN_DMAC));
668 LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
670 return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
674 * Gets the tep ip of designated switch for external tunnel.
678 * @param elanInstanceName
679 * the elan instance name
680 * @return the tep ip of designated switch for external tunnel
682 public IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
683 String elanInstanceName) {
684 IpAddress tepIp = null;
685 if (l2GwDevice.getTunnelIp() == null) {
686 LOG.warn("Tunnel IP not found for {}", l2GwDevice.getDeviceName());
689 DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
691 if (desgSwitch != null) {
692 tepIp = elanItmUtils.getSourceDpnTepIp(Uint64.valueOf(desgSwitch.getDpId()),
693 new NodeId(l2GwDevice.getHwvtepNodeId()));
699 * Gets the designated switch for external tunnel.
703 * @param elanInstanceName
704 * the elan instance name
705 * @return the designated switch for external tunnel
707 public DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
708 String elanInstanceName) {
710 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
711 .builder(DesignatedSwitchesForExternalTunnels.class)
712 .child(DesignatedSwitchForTunnel.class,
713 new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
715 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier)
717 } catch (ExecutionException e) {
718 LOG.error("Exception while retriving DesignatedSwitch for elan {} and tunnel {}",
719 elanInstanceName, tunnelIp, e);
720 } catch (InterruptedException e) {
721 LOG.error("Exception while retriving DesignatedSwitch for elan {} and tunnel {}",
722 elanInstanceName, tunnelIp, e);