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.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Objects;
23 import java.util.concurrent.ConcurrentMap;
24 import java.util.concurrent.ExecutionException;
25 import java.util.concurrent.TimeUnit;
26 import javax.annotation.PostConstruct;
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.mdsal.binding.api.DataBroker;
41 import org.opendaylight.mdsal.binding.util.Datastore;
42 import org.opendaylight.mdsal.binding.util.Datastore.Configuration;
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.LogicalDatastoreType;
47 import org.opendaylight.netvirt.elan.cache.ConfigMcastCache;
48 import org.opendaylight.netvirt.elan.cache.ElanInstanceDpnsCache;
49 import org.opendaylight.netvirt.elan.l2gw.jobs.McastUpdateJob;
50 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
51 import org.opendaylight.netvirt.elan.utils.ElanConstants;
52 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
53 import org.opendaylight.netvirt.elan.utils.ElanUtils;
54 import org.opendaylight.netvirt.elan.utils.Scheduler;
55 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
56 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsKey;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
85 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
86 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
87 import org.opendaylight.yangtools.yang.common.Uint64;
88 import org.slf4j.Logger;
89 import org.slf4j.LoggerFactory;
92 * The utility class to handle ELAN L2 Gateway related to multicast.
95 public class ElanL2GatewayMulticastUtils {
97 /** The Constant LOG. */
98 private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
99 private static final Logger EVENT_LOGGER = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
102 private final DataBroker broker;
103 private final ManagedNewTransactionRunner txRunner;
105 private final ElanItmUtils elanItmUtils;
106 private final ElanUtils elanUtils;
107 private final IMdsalApiManager mdsalManager;
108 private final IInterfaceManager interfaceManager;
109 private final ConfigMcastCache configMcastCache;
110 private final ElanInstanceDpnsCache elanInstanceDpnsCache;
111 private final Scheduler scheduler;
112 private final ElanRefUtil elanRefUtil;
113 private final ElanClusterUtils elanClusterUtils;
114 private final JobCoordinator jobCoordinator;
116 private volatile boolean immediatelyAfterClusterReboot = true;
120 public ElanL2GatewayMulticastUtils(DataBroker broker, ElanItmUtils elanItmUtils, ElanUtils elanUtils,
121 IMdsalApiManager mdsalManager, IInterfaceManager interfaceManager,
122 ConfigMcastCache configMcastCache,
123 ElanInstanceDpnsCache elanInstanceDpnsCache,
124 ElanRefUtil elanRefUtil,
125 ElanClusterUtils elanClusterUtils,
126 JobCoordinator jobCoordinator,
127 Scheduler scheduler) {
128 this.broker = broker;
129 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
130 this.elanItmUtils = elanItmUtils;
131 this.elanUtils = elanUtils;
132 this.mdsalManager = mdsalManager;
133 this.interfaceManager = interfaceManager;
134 this.configMcastCache = configMcastCache;
135 this.scheduler = scheduler;
136 this.elanInstanceDpnsCache = elanInstanceDpnsCache;
137 this.elanRefUtil = elanRefUtil;
138 this.elanClusterUtils = elanClusterUtils;
139 this.jobCoordinator = jobCoordinator;
144 scheduler.getScheduledExecutorService().schedule(() -> {
145 immediatelyAfterClusterReboot = false;
146 }, 60, TimeUnit.MINUTES);
149 public static InstanceIdentifier<ExternalTeps> buildExternalTepPath(String elan, IpAddress tepIp) {
150 return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elan))
151 .child(ExternalTeps.class, new ExternalTepsKey(tepIp)).build();
154 protected ExternalTeps buildExternalTeps(L2GatewayDevice device) {
155 return new ExternalTepsBuilder().setTepIp(device.getTunnelIp()).setNodeid(device.getHwvtepNodeId()).build();
158 public IInterfaceManager getInterfaceManager() {
159 return interfaceManager;
163 * Updates the remote mcast mac table for all the devices in this elan
164 * includes all the dpn tep ips and other devices tep ips in broadcast
168 * the elan to be updated
170 public void updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
171 for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
172 prepareRemoteMcastMacUpdateOnDevice(elanName, device, false, null);
177 * Update remote mcast mac on elan l2 gw device.
184 public void updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
185 prepareRemoteMcastMacUpdateOnDevice(elanName, device, false, null);
188 public ListenableFuture<Void> prepareRemoteMcastMacUpdateOnDevice(String elanName,
189 L2GatewayDevice dstDevice,
191 IpAddress removedDstTep) {
192 NodeId dstNodeId = new NodeId(dstDevice.getHwvtepNodeId());
193 RemoteMcastMacs existingMac = configMcastCache.getMac(HwvtepSouthboundUtils
194 .createLogicalSwitchesInstanceIdentifier(dstNodeId, new HwvtepNodeName(elanName)));
195 if (!addCase && immediatelyAfterClusterReboot && removedDstTep != null) {
196 LOG.debug(" RemoteMcast update delete tep {} of elan {} ", removedDstTep.getIpv4Address().getValue(),
198 //incase of dpn flap immediately after cluster reboot just remove its tep alone
199 if (existingMac != null) {
200 return deleteLocatorFromMcast(elanName, dstNodeId, removedDstTep, existingMac);
203 ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
204 Collection<DpnInterfaces> elanDpns = elanInstanceDpnsCache.get(elanName);
205 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(dstDevice, new ArrayList<DpnInterfaces>(elanDpns));
206 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
208 return preapareRemoteMcastMacEntry(elanName, dstDevice, dpnsTepIps, l2GwDevicesTepIps, addCase);
211 private ListenableFuture<Void> deleteLocatorFromMcast(String elanName, NodeId dstNodeId,
212 IpAddress removedDstTep,
213 RemoteMcastMacs existingMac) {
214 InstanceIdentifier<RemoteMcastMacs> macIid = HwvtepSouthboundUtils
215 .createRemoteMcastMacsInstanceIdentifier(dstNodeId, existingMac.key());
216 LocatorSet tobeDeleted = buildLocatorSet(dstNodeId, removedDstTep);
217 RemoteMcastMacsBuilder newMacBuilder = new RemoteMcastMacsBuilder(existingMac);
218 List<LocatorSet> locatorList = new ArrayList<>(existingMac.nonnullLocatorSet());
219 locatorList.remove(tobeDeleted);
220 newMacBuilder.setLocatorSet(locatorList);
221 RemoteMcastMacs mac = newMacBuilder.build();
222 //configMcastCache.added(macIid, mac);
223 return ResourceBatchingManager.getInstance().put(
224 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, macIid, mac);
227 LocatorSet buildLocatorSet(NodeId nodeId, IpAddress tepIp) {
228 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
229 .createHwvtepPhysicalLocatorAugmentation(tepIp.stringValue());
230 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
231 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
232 return new LocatorSetBuilder().setLocatorRef(phyLocRef).build();
236 * Update mcast macs for this elan.
237 * for all dpns in this elan recompute and update broadcast group
238 * for all l2gw devices in this elan recompute and update remote mcast mac entry
245 * the update this device
246 * @return the listenable future
248 public List<ListenableFuture<Void>> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
249 boolean createCase) {
250 /*BcGroupUpdateJob.updateAllBcGroups(elanName, createCase, null, device,
251 elanRefUtil, this, mdsalManager,
252 elanInstanceDpnsCache, elanItmUtils); */
254 McastUpdateJob.updateAllMcastsForConnectionAdd(elanName, this, elanClusterUtils, scheduler,
257 McastUpdateJob.updateAllMcastsForConnectionDelete(elanName, this, elanClusterUtils, scheduler,
258 jobCoordinator, device);
260 return Collections.emptyList();
263 public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo, boolean createCase,
265 //TODO cache this read
266 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
267 //List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
268 Collection<DpnInterfaces> dpns = elanInstanceDpnsCache.get(elanInfo.getElanInstanceName());
269 LOG.trace("Invoking method ELAN Broadcast Groups for ELAN {}",
270 elanInfo.getElanInstanceName());
271 if (createCase == true && addedDpn != null) {
272 setupStandardElanBroadcastGroups(elanInfo, null, addedDpn, createCase,
275 for (DpnInterfaces dpn : dpns) {
276 if (!dpn.getDpId().equals(addedDpn)) {
277 setupStandardElanBroadcastGroups(elanInfo, null, dpn.getDpId(), createCase, confTx);
283 public void setupElanBroadcastGroups(ElanInstance elanInfo, Uint64 dpnId,
284 TypedWriteTransaction<Configuration> confTx) {
285 LOG.debug("Setting up ELAN Broadcast Group for ELAN Instance {} for DPN {} ", elanInfo, dpnId);
286 setupElanBroadcastGroups(elanInfo, null, dpnId, confTx);
289 public void setupElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces,
290 Uint64 dpnId, TypedWriteTransaction<Datastore.Configuration> confTx) {
291 setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
292 setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
295 public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces,
296 Uint64 dpnId, TypedWriteTransaction<Datastore.Configuration> confTx) {
297 setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, true, confTx);
300 public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
301 Uint64 dpnId, boolean createCase, TypedWriteTransaction<Datastore.Configuration> confTx) {
302 List<Bucket> listBucket = new ArrayList<>();
305 Long elanTag = elanInfo.getElanTag().toJava();
306 List<Action> listAction = new ArrayList<>();
307 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
308 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
309 MDSALUtil.WATCH_GROUP));
310 LOG.debug("Configured ELAN Broadcast Group with Action {} ", listAction);
312 LOG.info("Constructing RemoteBCGroupBuckets for {} on dpn {} ", elanInfo.getElanInstanceName(), dpnId);
313 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId, elanTag);
314 listBucket.addAll(listBucketInfoRemote);
315 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
316 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
317 MDSALUtil.buildBucketLists(listBucket));
318 LOG.info("Installing the remote BroadCast Group:{}", group);
319 EVENT_LOGGER.debug("ELAN-RBG, ADD {} Elan Instance {} Dpn Id {}", group.getGroupId().getValue(),
320 elanInfo.getElanInstanceName(), dpnId);
322 elanUtils.syncUpdateGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND, confTx);
324 mdsalManager.addGroup(confTx, dpnId, group);
328 public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
329 Uint64 dpnId, TypedWriteTransaction<Configuration> confTx) {
330 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
331 if (etreeInstance != null) {
332 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava();
333 List<Bucket> listBucket = new ArrayList<>();
336 List<Action> listAction = new ArrayList<>();
337 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag)).buildAction(++actionKey));
338 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
339 MDSALUtil.WATCH_GROUP));
341 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
343 listBucket.addAll(listBucketInfoRemote);
344 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
345 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
346 MDSALUtil.buildBucketLists(listBucket));
347 LOG.trace("Installing the remote BroadCast Group:{}", group);
348 mdsalManager.addGroup(confTx, dpnId, group);
353 private DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, Uint64 dpnId) {
354 if (elanDpns != null) {
355 for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces().values()) {
356 LOG.trace("List of DpnInterfaces present in DS {} ", dpnInterface);
357 if (dpnInterface.getDpId().equals(dpnId)) {
362 LOG.debug("DPN {} missing in DpnInterfaces list {}", dpnId, elanDpns);
366 private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns,
367 DpnInterfaces dpnInterfaces, Uint64 dpnId, int bucketId) {
368 DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
369 if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
370 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
371 LOG.debug("Returning empty Bucket list for DPN {}", dpnId);
374 List<Bucket> listBucketInfo = new ArrayList<>();
375 for (String interfaceName : currDpnInterfaces.getInterfaces()) {
376 if (interfaceManager.isExternalInterface(interfaceName)) {
377 List<Action> listActionInfo = elanItmUtils.getExternalPortItmEgressAction(interfaceName);
378 if (!listActionInfo.isEmpty()) {
379 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
380 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
385 LOG.debug("Configured RemoteBCGroupExternalPortBuckets {} for DPN {}", listBucketInfo, dpnId);
386 return listBucketInfo;
390 public List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
391 Uint64 dpnId, int bucketId, long elanTag) {
392 List<Bucket> listBucketInfo = new ArrayList<>();
393 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
395 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
396 // Adding 270000 to avoid collision between LPort and elan for broadcast group actions
397 listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId,
398 elanUtils.isOpenstackVniSemanticsEnforced()
399 ? elanUtils.getVxlanSegmentationId(elanInfo).longValue()
400 : elanTag + ElanConstants.ELAN_TAG_ADDEND));
402 listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId,
403 getNextAvailableBucketId(listBucketInfo.size())));
404 listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanExternalTeps(elanInfo, dpnId,
405 getNextAvailableBucketId(listBucketInfo.size())));
406 listBucketInfo.addAll(getRemoteBCGroupBucketsOfL2gwDevices(elanInfo, dpnId,
407 getNextAvailableBucketId(listBucketInfo.size())));
408 LOG.debug("Configured ELAN Remote BC Group with Bucket Info {}", listBucketInfo);
409 return listBucketInfo;
412 public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, Uint64 dpnId,
414 List<Bucket> listBucketInfo = new ArrayList<>();
415 ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
416 .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
417 for (L2GatewayDevice device : map.values()) {
418 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
419 device.getHwvtepNodeId());
420 if (interfaceName == null) {
421 LOG.debug("RPC returned with empty response for getExternalTunnelInterfaceName {}"
422 + " for DPN {}, bucketID {} ",elanInfo.getElanInstanceName() ,dpnId, bucketId);
425 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
426 ElanUtils.getVxlanSegmentationId(elanInfo).longValue(), true);
427 if (listActionInfo.isEmpty()) {
428 LOG.debug("Retrieved empty egress action for interface {} for elan {} on DPN {}",
429 interfaceName, elanInfo.getElanInstanceName(), dpnId);
432 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
433 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
436 LOG.debug("Configured RemoteBCGroupBucketsOfElanL2GwDevices {} for DPN {} of ELAN {}",
437 listBucketInfo, dpnId, elanInfo.getElanInstanceName());
438 return listBucketInfo;
441 public List<Bucket> getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, Uint64 dpnId,
443 ElanInstance operElanInstance = null;
445 operElanInstance = new SingleTransactionDataBroker(broker).syncReadOptional(
446 LogicalDatastoreType.CONFIGURATION,
447 InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, elanInfo.key())
448 .build()).orElse(null);
449 } catch (ExecutionException | InterruptedException e) {
450 LOG.error("Failed to read elan instance operational path {}", elanInfo, e);
453 if (operElanInstance == null) {
456 List<ExternalTeps> teps = new ArrayList<>(operElanInstance.nonnullExternalTeps().values());
457 if (teps == null || teps.isEmpty()) {
460 List<Bucket> listBucketInfo = new ArrayList<>();
461 for (ExternalTeps tep : teps) {
462 String externalTep = tep.getNodeid() != null ? tep.getNodeid() : tep.getTepIp().toString();
463 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
465 if (interfaceName == null) {
466 LOG.error("Could not get interface name to ext tunnel {} {}", dpnId, tep.getTepIp());
469 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
470 elanUtils.getVxlanSegmentationId(elanInfo).longValue(), false);
471 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
472 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
475 return listBucketInfo;
478 public List<Bucket> getRemoteBCGroupBucketsOfL2gwDevices(ElanInstance elanInfo, Uint64 dpnId, int bucketId) {
479 ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils
480 .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
481 if (elanL2gwDevices == null || elanL2gwDevices.isEmpty()) {
482 return Collections.emptyList();
484 List<Bucket> listBucketInfo = new ArrayList<>();
485 for (L2GatewayDevice l2GatewayDevice : elanL2gwDevices.values()) {
486 if (l2GatewayDevice.getTunnelIp() == null) {
489 String externalTep = l2GatewayDevice.getTunnelIp().toString();
490 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
492 if (interfaceName == null) {
493 LOG.error("Could not get interface name to ext tunnel {} {}", dpnId, externalTep);
496 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
497 elanUtils.getVxlanSegmentationId(elanInfo).longValue(), false);
498 if (!listActionInfo.isEmpty()) {
499 LOG.debug("Adding Remote BC Group Bucket of tor - tunnel {} tun_id {}", interfaceName,
500 elanUtils.getVxlanSegmentationId(elanInfo));
502 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
503 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
506 return listBucketInfo;
509 private int getNextAvailableBucketId(int bucketSize) {
510 return bucketSize + 1;
513 @SuppressWarnings("checkstyle:IllegalCatch")
514 public List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, Uint64 dpnId, int bucketId,
516 List<Bucket> listBucketInfo = new ArrayList<>();
517 if (elanDpns != null) {
518 for (DpnInterfaces dpnInterface : elanDpns. nonnullDpnInterfaces().values()) {
519 if (!Objects.equals(dpnInterface.getDpId(), dpnId) && dpnInterface.getInterfaces() != null
520 && !dpnInterface.getInterfaces().isEmpty()) {
522 List<Action> listActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(dpnId,
523 dpnInterface.getDpId(), elanTagOrVni);
524 LOG.trace("configuring broadcast group for elan {} for source DPN {} and destination DPN {} "
525 + "with actions {}", elanTagOrVni, dpnId, dpnInterface.getDpId(), listActionInfo);
526 if (listActionInfo.isEmpty()) {
527 LOG.debug("getInternalTunnelItmEgressAction for src DPN {} "
528 + "and dest DPN {} for ELAN Tag or VNI {} returned empty",
529 dpnId, dpnInterface.getDpId(), elanTagOrVni);
532 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
533 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
535 } catch (Exception ex) {
536 LOG.error("Logical Group Interface not found between source Dpn - {}, "
537 + "destination Dpn - {} with exception", dpnId, dpnInterface.getDpId(), ex);
542 LOG.debug("Configured RemoteBCGroupTunnelBuckets Info {} for DPN {} for ELAN Tag or VNI{}",
543 listBucketInfo, dpnId, elanTagOrVni);
544 return listBucketInfo;
548 * Update remote mcast mac.
556 * @param l2GwDevicesTepIps
557 * the l2 gw devices tep ips
558 * @return the write transaction
560 private ListenableFuture<Void> preapareRemoteMcastMacEntry(String elanName,
561 L2GatewayDevice device, List<IpAddress> dpnsTepIps,
562 List<IpAddress> l2GwDevicesTepIps, boolean addCase) {
563 ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
564 remoteTepIps.remove(device.getTunnelIp());
565 remoteTepIps.addAll(dpnsTepIps);
566 IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
567 if (dhcpDesignatedSwitchTepIp != null && !remoteTepIps.contains(dhcpDesignatedSwitchTepIp)) {
568 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
570 return putRemoteMcastMac(new NodeId(device.getHwvtepNodeId()), elanName, remoteTepIps, addCase);
574 * Put remote mcast mac in config DS.
578 * @param logicalSwitchName
579 * the logical switch name
583 private ListenableFuture<Void> putRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
584 ArrayList<IpAddress> tepIps, boolean addCase) {
585 List<LocatorSet> locators = new ArrayList<>();
586 for (IpAddress tepIp : tepIps) {
587 locators.add(buildLocatorSet(nodeId, tepIp));
589 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
590 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
591 RemoteMcastMacs newMac = new RemoteMcastMacsBuilder()
592 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
593 .setLocatorSet(locators).build();
594 InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
596 RemoteMcastMacs existingMac = configMcastCache.getMac(newMac.getLogicalSwitchRef().getValue());
599 //proactively update the cache for delete cases do not wait for batch manager to delete from cache
600 //while the delete is in progress from the batch manager the below skip may trigger
601 //by updating the cache upfront the skip wont be triggered
602 configMcastCache.added(iid, newMac);
605 if (addCase && existingMac != null && existingMac.getLocatorSet() != null) {
606 Set existingLocators = new HashSet<>(existingMac.getLocatorSet());
607 List newLocators = newMac.getLocatorSet();
608 if (existingLocators.containsAll(newLocators)) {
609 return Futures.immediateFuture(null);
613 return ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
618 * Gets all the tep ips of dpns.
624 * @return the all tep ips of dpns and devices
626 private List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
627 List<IpAddress> tepIps = new ArrayList<>();
628 for (DpnInterfaces dpn : dpns) {
629 IpAddress internalTunnelIp = elanItmUtils.getSourceDpnTepIp(dpn.getDpId(),
630 new NodeId(l2GwDevice.getHwvtepNodeId()));
631 if (internalTunnelIp != null) {
632 tepIps.add(internalTunnelIp);
639 * Gets the all tep ips of l2 gw devices.
643 * @return the all tep ips of l2 gw devices
645 private static List<IpAddress> getAllTepIpsOfL2GwDevices(ConcurrentMap<String, L2GatewayDevice> devices) {
646 List<IpAddress> tepIps = new ArrayList<>();
647 for (L2GatewayDevice otherDevice : devices.values()) {
648 // There is no need to add the same tep ip to the list.
649 if (!tepIps.contains(otherDevice.getTunnelIp())) {
650 tepIps.add(otherDevice.getTunnelIp());
657 * Delete remote mcast mac from Hwvtep node.
661 * @param logicalSwitchName
662 * the logical switch name
663 * @return the listenable future
665 public ListenableFuture<?> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
666 InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
667 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
668 RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
669 new MacAddress(ElanConstants.UNKNOWN_DMAC));
671 LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
673 return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
677 * Gets the tep ip of designated switch for external tunnel.
681 * @param elanInstanceName
682 * the elan instance name
683 * @return the tep ip of designated switch for external tunnel
685 public IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
686 String elanInstanceName) {
687 IpAddress tepIp = null;
688 if (l2GwDevice.getTunnelIp() == null) {
689 LOG.warn("Tunnel IP not found for {}", l2GwDevice.getDeviceName());
692 DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
694 if (desgSwitch != null) {
695 tepIp = elanItmUtils.getSourceDpnTepIp(Uint64.valueOf(desgSwitch.getDpId()),
696 new NodeId(l2GwDevice.getHwvtepNodeId()));
702 * Gets the designated switch for external tunnel.
706 * @param elanInstanceName
707 * the elan instance name
708 * @return the designated switch for external tunnel
710 public DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
711 String elanInstanceName) {
713 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
714 .builder(DesignatedSwitchesForExternalTunnels.class)
715 .child(DesignatedSwitchForTunnel.class,new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
717 return new SingleTransactionDataBroker(broker).syncReadOptional(broker,
718 LogicalDatastoreType.CONFIGURATION, instanceIdentifier).orElse(null);
719 } catch (ExecutionException e) {
720 LOG.error("Exception while retriving DesignatedSwitch for elan {} and tunnel {}",
721 elanInstanceName, tunnelIp, e);
722 } catch (InterruptedException e) {
723 LOG.error("Exception while retriving DesignatedSwitch for elan {} and tunnel {}",
724 elanInstanceName, tunnelIp, e);