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.genius.infra.Datastore.CONFIGURATION;
12 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
14 import com.google.common.base.Optional;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.math.BigInteger;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Objects;
25 import javax.inject.Inject;
26 import javax.inject.Singleton;
27 import org.eclipse.jdt.annotation.NonNull;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
32 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
33 import org.opendaylight.genius.infra.Datastore;
34 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
35 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
36 import org.opendaylight.genius.infra.TypedWriteTransaction;
37 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
38 import org.opendaylight.genius.mdsalutil.MDSALUtil;
39 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
40 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
41 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
42 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
43 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
44 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
45 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
46 import org.opendaylight.netvirt.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
47 import org.opendaylight.netvirt.elan.l2gw.jobs.McastUpdateJob;
48 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
49 import org.opendaylight.netvirt.elan.utils.ElanConstants;
50 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
51 import org.opendaylight.netvirt.elan.utils.ElanUtils;
52 import org.opendaylight.netvirt.elan.utils.Scheduler;
53 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
54 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
83 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
84 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
85 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
86 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
87 import org.slf4j.Logger;
88 import org.slf4j.LoggerFactory;
91 * The utility class to handle ELAN L2 Gateway related to multicast.
94 public class ElanL2GatewayMulticastUtils {
96 /** The Constant LOG. */
97 private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
100 private final DataBroker broker;
101 private final ManagedNewTransactionRunner txRunner;
103 private final ElanItmUtils elanItmUtils;
104 private final JobCoordinator jobCoordinator;
105 private final ElanUtils elanUtils;
106 private final IMdsalApiManager mdsalManager;
107 private final IInterfaceManager interfaceManager;
108 private final ElanRefUtil elanRefUtil;
109 private final ElanClusterUtils elanClusterUtils;
110 private final Scheduler scheduler;
114 public ElanL2GatewayMulticastUtils(ElanItmUtils elanItmUtils, ElanUtils elanUtils, IMdsalApiManager mdsalManager,
115 IInterfaceManager interfaceManager, ElanRefUtil elanRefUtil) {
116 this.elanRefUtil = elanRefUtil;
117 this.broker = elanRefUtil.getDataBroker();
118 this.txRunner = new ManagedNewTransactionRunnerImpl(elanRefUtil.getDataBroker());
119 this.elanItmUtils = elanItmUtils;
120 this.jobCoordinator = elanRefUtil.getJobCoordinator();
121 this.elanUtils = elanUtils;
122 this.mdsalManager = mdsalManager;
123 this.interfaceManager = interfaceManager;
124 this.elanClusterUtils = elanRefUtil.getElanClusterUtils();
125 this.scheduler = elanRefUtil.getScheduler();
129 * Handle mcast for elan l2 gw device add.
130 * @param elanName the elan name
131 * @param device the device
133 public void handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
134 InstanceIdentifier<ExternalTeps> tepPath = buildExternalTepPath(elanName, device.getTunnelIp());
135 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
136 tx -> tx.put(tepPath, buildExternalTeps(device))), LOG, "Failed to write to config external tep {}",
138 updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
141 public static InstanceIdentifier<ExternalTeps> buildExternalTepPath(String elan, IpAddress tepIp) {
142 return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elan))
143 .child(ExternalTeps.class, new ExternalTepsKey(tepIp)).build();
146 protected ExternalTeps buildExternalTeps(L2GatewayDevice device) {
147 return new ExternalTepsBuilder().setTepIp(device.getTunnelIp()).setNodeid(device.getHwvtepNodeId()).build();
151 * Updates the remote mcast mac table for all the devices in this elan
152 * includes all the dpn tep ips and other devices tep ips in broadcast
156 * the elan to be updated
158 public void updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
159 for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName)) {
160 prepareRemoteMcastMacUpdateOnDevice(elanName, device, false, null);
164 public void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
165 HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(this, elanName,device);
166 jobCoordinator.enqueueJob(job.getJobKey(), job);
170 * Update remote mcast mac on elan l2 gw device.
177 public void updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
178 prepareRemoteMcastMacUpdateOnDevice(elanName, device, false, null);
181 public ListenableFuture<Void> prepareRemoteMcastMacUpdateOnDevice(String elanName, L2GatewayDevice device,
182 boolean addCase, IpAddress removedDstTep) {
183 NodeId dstNodeId = new NodeId(device.getHwvtepNodeId());
184 RemoteMcastMacs existingMac = null;
186 Optional<RemoteMcastMacs> mac = elanRefUtil.getConfigMcastCache().get(getRemoteMcastIid(dstNodeId,
188 if (mac.isPresent()) {
189 existingMac = mac.get();
191 } catch (ReadFailedException e) {
192 LOG.error("Failed to read iid for elan {}", elanName, e);
195 if (!addCase && 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 Collection<L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
204 Collection<DpnInterfaces> dpns = elanRefUtil.getElanInstanceDpnsCache().get(elanName);
205 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
206 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
207 return prepareRemoteMcastMacEntry(elanName, device, dpnsTepIps, l2GwDevicesTepIps, addCase);
210 private ListenableFuture<Void> deleteLocatorFromMcast(String elanName, NodeId dstNodeId,
211 IpAddress removedDstTep,
212 RemoteMcastMacs existingMac) {
213 InstanceIdentifier<RemoteMcastMacs> macIid = HwvtepSouthboundUtils
214 .createRemoteMcastMacsInstanceIdentifier(dstNodeId, existingMac.key());
215 LocatorSet tobeDeleted = buildLocatorSet(dstNodeId, removedDstTep);
216 RemoteMcastMacsBuilder newMacBuilder = new RemoteMcastMacsBuilder(existingMac);
217 newMacBuilder.getLocatorSet().remove(tobeDeleted);
218 RemoteMcastMacs mac = newMacBuilder.build();
219 //configMcastCache.add(macIid, mac);
220 return ResourceBatchingManager.getInstance().put(
221 ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, macIid, mac);
224 LocatorSet buildLocatorSet(NodeId nodeId, IpAddress tepIp) {
225 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
226 .createHwvtepPhysicalLocatorAugmentation(tepIp.stringValue());
227 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
228 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
229 return new LocatorSetBuilder().setLocatorRef(phyLocRef).build();
233 * Update mcast macs for this elan.
234 * for all dpns in this elan recompute and update broadcast group
235 * for all l2gw devices in this elan recompute and update remote mcast mac entry
241 * @param updateThisDevice
242 * the update this device
244 public void updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
245 boolean updateThisDevice) {
246 if (updateThisDevice) {
247 McastUpdateJob.updateAllMcastsForConnectionAdd(elanName, this, elanClusterUtils);
249 McastUpdateJob.updateAllMcastsForConnectionDelete(elanName, this, elanClusterUtils, device);
253 public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo,
254 TypedWriteTransaction<Datastore.Configuration> confTx) {
255 List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
256 for (DpnInterfaces dpn : dpns) {
257 setupElanBroadcastGroups(elanInfo, dpn.getDpId(), confTx);
261 public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId,
262 TypedWriteTransaction<Datastore.Configuration> confTx) {
263 setupElanBroadcastGroups(elanInfo, null, dpnId, confTx);
266 public void setupElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, BigInteger dpnId,
267 TypedWriteTransaction<Datastore.Configuration> confTx) {
268 setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
269 setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
272 public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
273 BigInteger dpnId, TypedWriteTransaction<Datastore.Configuration> confTx) {
274 List<Bucket> listBucket = new ArrayList<>();
277 Long elanTag = elanInfo.getElanTag();
278 List<Action> listAction = new ArrayList<>();
279 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
280 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
281 MDSALUtil.WATCH_GROUP));
283 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId, elanTag);
284 listBucket.addAll(listBucketInfoRemote);
285 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
286 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
287 MDSALUtil.buildBucketLists(listBucket));
288 LOG.trace("Installing the remote BroadCast Group:{}", group);
289 mdsalManager.addGroup(confTx, dpnId, group);
292 public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
293 BigInteger dpnId, TypedWriteTransaction<Datastore.Configuration> confTx) {
294 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
295 if (etreeInstance != null) {
296 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
297 List<Bucket> listBucket = new ArrayList<>();
300 List<Action> listAction = new ArrayList<>();
301 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag)).buildAction(++actionKey));
302 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
303 MDSALUtil.WATCH_GROUP));
305 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
307 listBucket.addAll(listBucketInfoRemote);
308 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
309 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
310 MDSALUtil.buildBucketLists(listBucket));
311 LOG.trace("Installing the remote BroadCast Group:{}", group);
312 mdsalManager.addGroup(confTx, dpnId, group);
317 private static DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) {
318 if (elanDpns != null) {
319 for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces()) {
320 if (Objects.equals(dpnInterface.getDpId(), dpnId)) {
328 private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns,
329 DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
330 DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
331 if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
332 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
335 List<Bucket> listBucketInfo = new ArrayList<>();
336 for (String interfaceName : currDpnInterfaces.getInterfaces()) {
337 if (interfaceManager.isExternalInterface(interfaceName)) {
338 List<Action> listActionInfo = elanItmUtils.getExternalPortItmEgressAction(interfaceName);
339 if (!listActionInfo.isEmpty()) {
340 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
341 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
346 return listBucketInfo;
350 public List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
351 BigInteger dpnId, int bucketId, long elanTag) {
352 List<Bucket> listBucketInfo = new ArrayList<>();
353 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
355 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
356 listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId,
357 elanUtils.isOpenstackVniSemanticsEnforced()
358 ? ElanUtils.getVxlanSegmentationId(elanInfo) : elanTag));
360 listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId,
361 getNextAvailableBucketId(listBucketInfo.size())));
362 listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanExternalTeps(elanInfo, dpnId,
363 getNextAvailableBucketId(listBucketInfo.size())));
364 return listBucketInfo;
367 public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
369 List<Bucket> listBucketInfo = new ArrayList<>();
370 for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInfo.getElanInstanceName())) {
371 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
372 device.getHwvtepNodeId());
373 if (interfaceName == null) {
376 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
377 ElanUtils.getVxlanSegmentationId(elanInfo), true);
378 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
379 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
382 return listBucketInfo;
385 public List<Bucket> getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, BigInteger dpnId,
387 ElanInstance operElanInstance = null;
389 operElanInstance = new SingleTransactionDataBroker(broker).syncReadOptional(
390 LogicalDatastoreType.OPERATIONAL,
391 InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, elanInfo.key())
393 } catch (ReadFailedException e) {
394 LOG.error("Failed to read elan instance operational path {}", elanInfo, e);
397 if (operElanInstance == null) {
400 List<ExternalTeps> teps = operElanInstance.getExternalTeps();
401 if (teps == null || teps.isEmpty()) {
404 List<Bucket> listBucketInfo = new ArrayList<>();
405 for (ExternalTeps tep : teps) {
406 String externalTep = tep.getNodeid() != null ? tep.getNodeid() : tep.getTepIp().toString();
407 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
409 if (interfaceName == null) {
410 LOG.error("Could not get interface name to ext tunnel {} {}", dpnId, tep.getTepIp());
413 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
414 ElanUtils.getVxlanSegmentationId(elanInfo), false);
415 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
416 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
419 return listBucketInfo;
422 private static int getNextAvailableBucketId(int bucketSize) {
423 return bucketSize + 1;
426 @SuppressWarnings("checkstyle:IllegalCatch")
427 private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
429 List<Bucket> listBucketInfo = new ArrayList<>();
430 if (elanDpns != null) {
431 for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces()) {
432 if (!Objects.equals(dpnInterface.getDpId(), dpnId) && dpnInterface.getInterfaces() != null
433 && !dpnInterface.getInterfaces().isEmpty()) {
435 List<Action> listActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(dpnId,
436 dpnInterface.getDpId(), elanTagOrVni);
437 if (listActionInfo.isEmpty()) {
440 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
441 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
443 } catch (Exception ex) {
444 LOG.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
445 dpnId, dpnInterface.getDpId(), ex);
450 return listBucketInfo;
454 * Update remote mcast mac.
462 * @param l2GwDevicesTepIps
463 * the l2 gw devices tep ips
464 * @return the write transaction
466 private ListenableFuture<Void> prepareRemoteMcastMacEntry(String elanName,
467 L2GatewayDevice device, List<IpAddress> dpnsTepIps,
468 List<IpAddress> l2GwDevicesTepIps, boolean addCase) {
469 NodeId nodeId = new NodeId(device.getHwvtepNodeId());
471 ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
472 remoteTepIps.remove(device.getTunnelIp());
473 remoteTepIps.addAll(dpnsTepIps);
474 IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
475 if (dpnsTepIps.isEmpty()) {
476 // If no dpns in elan, configure dhcp designated switch Tep Ip as a
477 // physical locator in l2 gw device
478 if (dhcpDesignatedSwitchTepIp != null) {
479 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
481 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
482 .createHwvtepPhysicalLocatorAugmentation(dhcpDesignatedSwitchTepIp);
483 InstanceIdentifier<TerminationPoint> iid =
484 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug);
485 TerminationPoint terminationPoint = new TerminationPointBuilder()
486 .withKey(HwvtepSouthboundUtils.getTerminationPointKey(phyLocatorAug))
487 .addAugmentation(HwvtepPhysicalLocatorAugmentation.class, phyLocatorAug).build();
488 ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
489 iid, terminationPoint);
490 LOG.info("Adding PhysicalLocator for node: {} with Dhcp designated switch Tep Ip {} "
491 + "as physical locator, elan {}", device.getHwvtepNodeId(),
492 dhcpDesignatedSwitchTepIp.stringValue(), elanName);
494 LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
495 device.getHwvtepNodeId(), elanName);
498 if (dhcpDesignatedSwitchTepIp != null && !remoteTepIps.contains(dhcpDesignatedSwitchTepIp)) {
499 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
501 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
502 LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
504 return putRemoteMcastMac(nodeId, logicalSwitchName, remoteTepIps, addCase);
508 * Put remote mcast mac in config DS.
512 * @param logicalSwitchName
513 * the logical switch name
517 private ListenableFuture<Void> putRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
518 ArrayList<IpAddress> tepIps, boolean addCase) {
519 List<LocatorSet> locators = new ArrayList<>();
520 for (IpAddress tepIp : tepIps) {
521 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
522 .createHwvtepPhysicalLocatorAugmentation(tepIp);
523 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
524 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
525 locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
528 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
529 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
530 RemoteMcastMacs newRemoteMcastMac = new RemoteMcastMacsBuilder()
531 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
532 .setLocatorSet(locators).build();
533 InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
534 newRemoteMcastMac.key());
535 RemoteMcastMacs existingRemoteMcastMac = null;
537 Optional<RemoteMcastMacs> mac = elanRefUtil.getConfigMcastCache().get(iid);
538 if (mac.isPresent()) {
539 existingRemoteMcastMac = mac.get();
541 } catch (ReadFailedException e) {
542 LOG.error("Failed to read iid {}", iid, e);
545 if (addCase && areLocatorsAlreadyConfigured(existingRemoteMcastMac, newRemoteMcastMac)) {
546 return Futures.immediateFuture(null);
549 return ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
550 iid, newRemoteMcastMac);
554 private boolean areLocatorsAlreadyConfigured(RemoteMcastMacs existingMac, RemoteMcastMacs newMac) {
555 if (existingMac == null) {
558 Set existingLocators = new HashSet<>(existingMac.getLocatorSet());
559 List newLocators = newMac.getLocatorSet();
560 return existingLocators.containsAll(newLocators);
563 private InstanceIdentifier<RemoteMcastMacs> getRemoteMcastIid(NodeId nodeId, String logicalSwitchName) {
564 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
565 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
566 RemoteMcastMacs remoteMcastMac = new RemoteMcastMacsBuilder()
567 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
569 return HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
570 remoteMcastMac.key());
574 * Gets all the tep ips of dpns.
580 * @return the all tep ips of dpns and devices
582 private List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, Collection<DpnInterfaces> dpns) {
583 List<IpAddress> tepIps = new ArrayList<>();
584 for (DpnInterfaces dpn : dpns) {
585 IpAddress internalTunnelIp = elanItmUtils.getSourceDpnTepIp(dpn.getDpId(),
586 new NodeId(l2GwDevice.getHwvtepNodeId()));
587 if (internalTunnelIp != null) {
588 tepIps.add(internalTunnelIp);
595 * Gets the all tep ips of l2 gw devices.
599 * @return the all tep ips of l2 gw devices
601 private static List<IpAddress> getAllTepIpsOfL2GwDevices(Collection<L2GatewayDevice> devices) {
602 List<IpAddress> tepIps = new ArrayList<>();
603 for (L2GatewayDevice otherDevice : devices) {
604 // There is no need to add the same tep ip to the list.
605 if (!tepIps.contains(otherDevice.getTunnelIp())) {
606 tepIps.add(otherDevice.getTunnelIp());
613 * Handle mcast for elan l2 gw device delete.
616 * the elan instance name
617 * @param l2GatewayDevice
618 * the l2 gateway device
619 * @return the listenable future
621 public List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(String elanName,
622 L2GatewayDevice l2GatewayDevice) {
623 ListenableFuture<Void> deleteTepFuture =
624 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
625 tx -> tx.delete(buildExternalTepPath(elanName, l2GatewayDevice.getTunnelIp())));
626 updateMcastMacsForAllElanDevices(elanName, l2GatewayDevice, false/* updateThisDevice */);
627 ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
628 new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName);
629 return Arrays.asList(deleteRemoteMcastMacFuture, deleteTepFuture);
633 * Delete remote mcast mac from Hwvtep node.
637 * @param logicalSwitchName
638 * the logical switch name
639 * @return the listenable future
641 public ListenableFuture<Void> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
642 InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
643 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
644 RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
645 new MacAddress(ElanConstants.UNKNOWN_DMAC));
647 LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
649 return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
653 * Gets the tep ip of designated switch for external tunnel.
657 * @param elanInstanceName
658 * the elan instance name
659 * @return the tep ip of designated switch for external tunnel
661 public IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
662 String elanInstanceName) {
663 IpAddress tepIp = null;
664 if (l2GwDevice.getTunnelIp() == null) {
665 LOG.warn("Tunnel IP not found for {}", l2GwDevice.getDeviceName());
668 DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
670 if (desgSwitch != null) {
671 tepIp = elanItmUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
672 new NodeId(l2GwDevice.getHwvtepNodeId()));
678 * Gets the designated switch for external tunnel.
682 * @param elanInstanceName
683 * the elan instance name
684 * @return the designated switch for external tunnel
686 public DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
687 String elanInstanceName) {
688 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
689 .builder(DesignatedSwitchesForExternalTunnels.class)
690 .child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
692 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier).orNull();