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.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import com.google.common.util.concurrent.SettableFuture;
15 import java.math.BigInteger;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.List;
19 import java.util.Objects;
20 import java.util.concurrent.ConcurrentMap;
21 import javax.annotation.Nonnull;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
30 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
31 import org.opendaylight.genius.mdsalutil.MDSALUtil;
32 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
33 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
34 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
35 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
36 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
37 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
38 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
39 import org.opendaylight.netvirt.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
40 import org.opendaylight.netvirt.elan.utils.ElanConstants;
41 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
42 import org.opendaylight.netvirt.elan.utils.ElanUtils;
43 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
44 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
74 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
75 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
81 * The utility class to handle ELAN L2 Gateway related to multicast.
84 public class ElanL2GatewayMulticastUtils {
86 /** The Constant LOG. */
87 private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
90 private final DataBroker broker;
91 private final ManagedNewTransactionRunner txRunner;
93 private final ElanItmUtils elanItmUtils;
94 private final JobCoordinator jobCoordinator;
95 private final ElanUtils elanUtils;
96 private final IMdsalApiManager mdsalManager;
97 private final IInterfaceManager interfaceManager;
100 public ElanL2GatewayMulticastUtils(DataBroker broker, ElanItmUtils elanItmUtils, JobCoordinator jobCoordinator,
101 ElanUtils elanUtils, IMdsalApiManager mdsalManager, IInterfaceManager interfaceManager) {
102 this.broker = broker;
103 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
104 this.elanItmUtils = elanItmUtils;
105 this.jobCoordinator = jobCoordinator;
106 this.elanUtils = elanUtils;
107 this.mdsalManager = mdsalManager;
108 this.interfaceManager = interfaceManager;
112 * Handle mcast for elan l2 gw device add.
113 * @param elanName the elan name
114 * @param device the device
115 * @return the listenable future
117 public ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
118 InstanceIdentifier<ExternalTeps> tepPath = buildExternalTepPath(elanName, device.getTunnelIp());
119 JdkFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
120 tx.put(LogicalDatastoreType.CONFIGURATION, tepPath, buildExternalTeps(device));
121 }), LOG, "Failed to write to config external tep {}", tepPath);
122 return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
125 public static InstanceIdentifier<ExternalTeps> buildExternalTepPath(String elan, IpAddress tepIp) {
126 return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elan))
127 .child(ExternalTeps.class, new ExternalTepsKey(tepIp)).build();
130 protected ExternalTeps buildExternalTeps(L2GatewayDevice device) {
131 return new ExternalTepsBuilder().setTepIp(device.getTunnelIp()).setNodeid(device.getHwvtepNodeId()).build();
135 * Updates the remote mcast mac table for all the devices in this elan
136 * includes all the dpn tep ips and other devices tep ips in broadcast
140 * the elan to be updated
141 * @return the listenable future
143 @SuppressWarnings("checkstyle:IllegalCatch")
144 public ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
145 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
146 for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
147 prepareRemoteMcastMacUpdateOnDevice(elanName, device);
152 public void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
153 HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(this, elanName,device);
154 jobCoordinator.enqueueJob(job.getJobKey(), job);
158 * Update remote mcast mac on elan l2 gw device.
164 * @return the listenable future
166 public ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
167 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(
168 tx -> prepareRemoteMcastMacUpdateOnDevice(elanName, device));
171 public void prepareRemoteMcastMacUpdateOnDevice(String elanName,
172 L2GatewayDevice device) {
173 ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils
174 .getInvolvedL2GwDevices(elanName);
175 List<DpnInterfaces> dpns = elanUtils.getElanDPNByName(elanName);
176 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
177 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
178 preapareRemoteMcastMacEntry(elanName, device, dpnsTepIps, l2GwDevicesTepIps);
182 * Update mcast macs for this elan.
183 * for all dpns in this elan recompute and update broadcast group
184 * for all l2gw devices in this elan recompute and update remote mcast mac entry
190 * @param updateThisDevice
191 * the update this device
192 * @return the listenable future
194 private ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
195 boolean updateThisDevice) {
197 SettableFuture<Void> ft = SettableFuture.create();
200 List<DpnInterfaces> dpns = elanUtils.getElanDPNByName(elanName);
202 ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
203 .getInvolvedL2GwDevices(elanName);
205 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
206 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices);
207 // if (allTepIps.size() < 2) {
208 // LOG.debug("no other devices are found in the elan {}", elanName);
212 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
213 if (updateThisDevice) {
214 preapareRemoteMcastMacEntry(elanName, device, dpnsTepIps, l2GwDevicesTepIps);
217 // TODO: Need to revisit below logic as logical switches might not be
218 // present to configure RemoteMcastMac entry
219 for (L2GatewayDevice otherDevice : devices.values()) {
220 if (!otherDevice.getDeviceName().equals(device.getDeviceName())) {
221 preapareRemoteMcastMacEntry(elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
228 public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
229 List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
230 for (DpnInterfaces dpn : dpns) {
231 setupElanBroadcastGroups(elanInfo, dpn.getDpId());
235 public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
236 setupElanBroadcastGroups(elanInfo, null, dpnId);
239 public void setupElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
240 setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
241 setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
244 public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
245 List<Bucket> listBucket = new ArrayList<>();
248 Long elanTag = elanInfo.getElanTag();
249 List<Action> listAction = new ArrayList<>();
250 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
251 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
252 MDSALUtil.WATCH_GROUP));
254 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId, elanTag);
255 listBucket.addAll(listBucketInfoRemote);
256 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
257 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
258 MDSALUtil.buildBucketLists(listBucket));
259 LOG.trace("Installing the remote BroadCast Group:{}", group);
260 mdsalManager.syncInstallGroup(dpnId, group);
263 public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
264 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
265 if (etreeInstance != null) {
266 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
267 List<Bucket> listBucket = new ArrayList<>();
270 List<Action> listAction = new ArrayList<>();
271 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag)).buildAction(++actionKey));
272 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
273 MDSALUtil.WATCH_GROUP));
275 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
277 listBucket.addAll(listBucketInfoRemote);
278 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
279 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
280 MDSALUtil.buildBucketLists(listBucket));
281 LOG.trace("Installing the remote BroadCast Group:{}", group);
282 mdsalManager.syncInstallGroup(dpnId, group);
286 private DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) {
287 if (elanDpns != null) {
288 for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
289 if (dpnInterface.getDpId().equals(dpnId)) {
297 private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns,
298 DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
299 DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
300 if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
301 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
304 List<Bucket> listBucketInfo = new ArrayList<>();
305 for (String interfaceName : currDpnInterfaces.getInterfaces()) {
306 if (interfaceManager.isExternalInterface(interfaceName)) {
307 List<Action> listActionInfo = elanItmUtils.getExternalPortItmEgressAction(interfaceName);
308 if (!listActionInfo.isEmpty()) {
309 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
310 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
315 return listBucketInfo;
319 public List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId,
320 int bucketId, long elanTag) {
321 List<Bucket> listBucketInfo = new ArrayList<>();
322 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
324 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
325 listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId,
326 elanUtils.isOpenstackVniSemanticsEnforced()
327 ? elanUtils.getVxlanSegmentationId(elanInfo) : elanTag));
329 listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId,
330 getNextAvailableBucketId(listBucketInfo.size())));
331 listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanExternalTeps(elanInfo, dpnId,
332 getNextAvailableBucketId(listBucketInfo.size())));
333 return listBucketInfo;
336 public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
338 List<Bucket> listBucketInfo = new ArrayList<>();
339 ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
340 .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
341 for (L2GatewayDevice device : map.values()) {
342 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
343 device.getHwvtepNodeId());
344 if (interfaceName == null) {
347 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
348 ElanUtils.getVxlanSegmentationId(elanInfo), true);
349 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
350 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
353 return listBucketInfo;
356 public List<Bucket> getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, BigInteger dpnId,
358 ElanInstance operElanInstance = null;
360 operElanInstance = new SingleTransactionDataBroker(broker).syncReadOptional(
361 LogicalDatastoreType.OPERATIONAL,
362 InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, elanInfo.getKey())
364 } catch (ReadFailedException e) {
365 LOG.error("Failed to read elan instance operational path {}", elanInfo, e);
368 if (operElanInstance == null) {
371 List<ExternalTeps> teps = operElanInstance.getExternalTeps();
372 if (teps == null || teps.isEmpty()) {
375 List<Bucket> listBucketInfo = new ArrayList<>();
376 for (ExternalTeps tep : teps) {
377 String externalTep = tep.getNodeid() != null ? tep.getNodeid() : tep.getTepIp().toString();
378 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
380 if (interfaceName == null) {
381 LOG.error("Could not get interface name to ext tunnel {} {}", dpnId, tep.getTepIp());
384 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
385 elanUtils.getVxlanSegmentationId(elanInfo), false);
386 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
387 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
390 return listBucketInfo;
393 private int getNextAvailableBucketId(int bucketSize) {
394 return bucketSize + 1;
397 @SuppressWarnings("checkstyle:IllegalCatch")
398 private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
400 List<Bucket> listBucketInfo = new ArrayList<>();
401 if (elanDpns != null) {
402 for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
403 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpnId)
404 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
406 List<Action> listActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(dpnId,
407 dpnInterface.getDpId(), elanTagOrVni);
408 if (listActionInfo.isEmpty()) {
411 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
412 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
414 } catch (Exception ex) {
415 LOG.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
416 dpnId, dpnInterface.getDpId(), ex);
421 return listBucketInfo;
425 * Update remote mcast mac.
433 * @param l2GwDevicesTepIps
434 * the l2 gw devices tep ips
435 * @return the write transaction
437 private void preapareRemoteMcastMacEntry(String elanName,
438 L2GatewayDevice device, List<IpAddress> dpnsTepIps,
439 List<IpAddress> l2GwDevicesTepIps) {
440 NodeId nodeId = new NodeId(device.getHwvtepNodeId());
442 ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
443 remoteTepIps.remove(device.getTunnelIp());
444 remoteTepIps.addAll(dpnsTepIps);
445 IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
446 if (dpnsTepIps.isEmpty()) {
447 // If no dpns in elan, configure dhcp designated switch Tep Ip as a
448 // physical locator in l2 gw device
449 if (dhcpDesignatedSwitchTepIp != null) {
450 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
452 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
453 .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
454 InstanceIdentifier<TerminationPoint> iid =
455 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug);
456 TerminationPoint terminationPoint = new TerminationPointBuilder()
457 .setKey(HwvtepSouthboundUtils.getTerminationPointKey(phyLocatorAug))
458 .addAugmentation(HwvtepPhysicalLocatorAugmentation.class, phyLocatorAug).build();
459 ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
460 iid, terminationPoint);
461 LOG.info("Adding PhysicalLocator for node: {} with Dhcp designated switch Tep Ip {} "
462 + "as physical locator, elan {}", device.getHwvtepNodeId(),
463 String.valueOf(dhcpDesignatedSwitchTepIp.getValue()), elanName);
465 LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
466 device.getHwvtepNodeId(), elanName);
469 if (dhcpDesignatedSwitchTepIp != null && !remoteTepIps.contains(dhcpDesignatedSwitchTepIp)) {
470 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
472 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
473 putRemoteMcastMac(nodeId, logicalSwitchName, remoteTepIps);
474 LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
479 * Put remote mcast mac in config DS.
483 * @param logicalSwitchName
484 * the logical switch name
488 private static void putRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
489 ArrayList<IpAddress> tepIps) {
490 List<LocatorSet> locators = new ArrayList<>();
491 for (IpAddress tepIp : tepIps) {
492 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
493 .createHwvtepPhysicalLocatorAugmentation(String.valueOf(tepIp.getValue()));
494 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
495 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
496 locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
499 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
500 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
501 RemoteMcastMacs remoteMcastMac = new RemoteMcastMacsBuilder()
502 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
503 .setLocatorSet(locators).build();
504 InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
505 remoteMcastMac.getKey());
506 ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
507 iid, remoteMcastMac);
512 * Gets all the tep ips of dpns.
518 * @return the all tep ips of dpns and devices
520 private List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
521 List<IpAddress> tepIps = new ArrayList<>();
522 for (DpnInterfaces dpn : dpns) {
523 IpAddress internalTunnelIp = elanItmUtils.getSourceDpnTepIp(dpn.getDpId(),
524 new NodeId(l2GwDevice.getHwvtepNodeId()));
525 if (internalTunnelIp != null) {
526 tepIps.add(internalTunnelIp);
533 * Gets the all tep ips of l2 gw devices.
537 * @return the all tep ips of l2 gw devices
539 private static List<IpAddress> getAllTepIpsOfL2GwDevices(ConcurrentMap<String, L2GatewayDevice> devices) {
540 List<IpAddress> tepIps = new ArrayList<>();
541 for (L2GatewayDevice otherDevice : devices.values()) {
542 // There is no need to add the same tep ip to the list.
543 if (!tepIps.contains(otherDevice.getTunnelIp())) {
544 tepIps.add(otherDevice.getTunnelIp());
551 * Handle mcast for elan l2 gw device delete.
554 * the elan instance name
555 * @param l2GatewayDevice
556 * the l2 gateway device
557 * @return the listenable future
559 public List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(String elanName,
560 L2GatewayDevice l2GatewayDevice) {
561 ListenableFuture<Void> deleteTepFuture = txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
562 tx.delete(LogicalDatastoreType.CONFIGURATION,
563 buildExternalTepPath(elanName, l2GatewayDevice.getTunnelIp()));
565 ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacsForAllElanDevices(
566 elanName, l2GatewayDevice, false/* updateThisDevice */);
567 ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
568 new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName);
569 return Arrays.asList(updateMcastMacsFuture, deleteRemoteMcastMacFuture, deleteTepFuture);
573 * Delete remote mcast mac from Hwvtep node.
577 * @param logicalSwitchName
578 * the logical switch name
579 * @return the listenable future
581 private ListenableFuture<Void> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
582 InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
583 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
584 RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
585 new MacAddress(ElanConstants.UNKNOWN_DMAC));
587 LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
589 return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
593 * Gets the tep ip of designated switch for external tunnel.
597 * @param elanInstanceName
598 * the elan instance name
599 * @return the tep ip of designated switch for external tunnel
601 public IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
602 String elanInstanceName) {
603 IpAddress tepIp = null;
604 if (l2GwDevice.getTunnelIp() == null) {
605 LOG.warn("Tunnel IP not found for {}", l2GwDevice.getDeviceName());
608 DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
610 if (desgSwitch != null) {
611 tepIp = elanItmUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
612 new NodeId(l2GwDevice.getHwvtepNodeId()));
618 * Gets the designated switch for external tunnel.
622 * @param elanInstanceName
623 * the elan instance name
624 * @return the designated switch for external tunnel
626 public DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
627 String elanInstanceName) {
628 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
629 .builder(DesignatedSwitchesForExternalTunnels.class)
630 .child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
632 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier).orNull();