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.vpnservice.elan.l2gw.utils;
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.ConcurrentMap;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
19 import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
20 import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
21 import org.opendaylight.vpnservice.elan.internal.ElanInterfaceManager;
22 import org.opendaylight.vpnservice.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
23 import org.opendaylight.vpnservice.elan.utils.ElanConstants;
24 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
25 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
26 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
27 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
28 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 import com.google.common.base.Optional;
52 import com.google.common.collect.Lists;
53 import com.google.common.util.concurrent.ListenableFuture;
54 import com.google.common.util.concurrent.SettableFuture;
57 * The utility class to handle ELAN L2 Gateway related to multicast.
59 public class ElanL2GatewayMulticastUtils {
61 /** The Constant LOG. */
62 private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
65 private static DataBroker broker;
67 /** The elan instance manager. */
68 private static ElanInstanceManager elanInstanceManager;
70 /** The elan interface manager. */
71 private static ElanInterfaceManager elanInterfaceManager;
73 static DataStoreJobCoordinator dataStoreJobCoordinator;
75 public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
76 dataStoreJobCoordinator = ds;
85 public static void setBroker(DataBroker broker) {
86 ElanL2GatewayMulticastUtils.broker = broker;
90 * Sets the elan instance manager.
93 * the new elan instance manager
95 public static void setElanInstanceManager(ElanInstanceManager elanMgr) {
96 ElanL2GatewayMulticastUtils.elanInstanceManager = elanMgr;
100 * Sets the elan interface manager.
102 * @param interfaceMgr
103 * the new elan interface manager
105 public static void setElanInterfaceManager(ElanInterfaceManager interfaceMgr) {
106 elanInterfaceManager = interfaceMgr;
110 * Handle mcast for elan l2 gw device add.
116 * @return the listenable future
118 public static ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
119 return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
123 * Updates the remote mcast mac table for all the devices in this elan
124 * includes all the dpn tep ips and other devices tep ips in broadcast
128 * the elan to be updated
129 * @return the listenable future
131 public static ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
132 SettableFuture<Void> future = SettableFuture.create();
135 WriteTransaction transaction = broker.newWriteOnlyTransaction();
136 for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
137 prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
139 return transaction.submit();
140 } catch (Throwable e) {
141 LOG.error("Failed to configure mcast mac on elan " + elanName, e);
146 public static void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
147 HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(elanName,device);
148 dataStoreJobCoordinator.enqueueJob(job.getJobKey(), job);
152 * Update remote mcast mac on elan l2 gw device.
158 * @return the listenable future
160 public static ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
161 WriteTransaction transaction = broker.newWriteOnlyTransaction();
162 prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
163 return transaction.submit();
166 public static void prepareRemoteMcastMacUpdateOnDevice(WriteTransaction transaction,String elanName,
167 L2GatewayDevice device) {
168 ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils
169 .getInvolvedL2GwDevices(elanName);
170 List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
171 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
172 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
173 preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
177 * Update mcast macs for this elan.
178 * for all dpns in this elan recompute and update broadcast group
179 * for all l2gw devices in this elan recompute and update remote mcast mac entry
185 * @param updateThisDevice
186 * the update this device
187 * @return the listenable future
189 public static ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
190 boolean updateThisDevice) {
192 SettableFuture<Void> ft = SettableFuture.create();
195 ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName);
196 elanInterfaceManager.updateRemoteBroadcastGroupForAllElanDpns(elanInstance);
198 List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
200 ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
201 .getInvolvedL2GwDevices(elanName);
203 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
204 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices);
205 // if (allTepIps.size() < 2) {
206 // LOG.debug("no other devices are found in the elan {}", elanName);
210 WriteTransaction transaction = broker.newWriteOnlyTransaction();
211 if (updateThisDevice) {
212 preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
215 // TODO: Need to revisit below logic as logical switches might not be
216 // present to configure RemoteMcastMac entry
217 for (L2GatewayDevice otherDevice : devices.values()) {
218 if (!otherDevice.getDeviceName().equals(device.getDeviceName())) {
219 preapareRemoteMcastMacEntry(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
222 return transaction.submit();
227 * Update remote mcast mac.
237 * @param l2GwDevicesTepIps
238 * the l2 gw devices tep ips
239 * @return the write transaction
241 private static void preapareRemoteMcastMacEntry(WriteTransaction transaction, String elanName,
242 L2GatewayDevice device, List<IpAddress> dpnsTepIps,
243 List<IpAddress> l2GwDevicesTepIps) {
244 NodeId nodeId = new NodeId(device.getHwvtepNodeId());
245 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
247 ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
248 remoteTepIps.remove(device.getTunnelIp());
249 remoteTepIps.addAll(dpnsTepIps);
250 if (dpnsTepIps.isEmpty()) {
251 // If no dpns in elan, configure dhcp designated switch Tep Ip as a
252 // physical locator in l2 gw device
253 IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
254 if (dhcpDesignatedSwitchTepIp != null) {
255 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
257 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
258 .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
259 HwvtepUtils.putPhysicalLocator(transaction, nodeId, phyLocatorAug);
262 "Adding PhysicalLocator for node: {} with Dhcp designated switch Tep Ip {} as physical locator, elan {}",
263 device.getHwvtepNodeId(), String.valueOf(dhcpDesignatedSwitchTepIp.getValue()), elanName);
265 LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
266 device.getHwvtepNodeId(), elanName);
270 putRemoteMcastMac(transaction, nodeId, logicalSwitchName, remoteTepIps);
271 LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
276 * Put remote mcast mac in config DS.
282 * @param logicalSwitchName
283 * the logical switch name
287 private static void putRemoteMcastMac(WriteTransaction transaction, NodeId nodeId, String logicalSwitchName,
288 ArrayList<IpAddress> tepIps) {
289 List<LocatorSet> locators = new ArrayList<>();
290 for (IpAddress tepIp : tepIps) {
291 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
292 .createHwvtepPhysicalLocatorAugmentation(String.valueOf(tepIp.getValue()));
293 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
294 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
295 locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
298 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
299 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
300 RemoteMcastMacs remoteUcastMac = new RemoteMcastMacsBuilder()
301 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
302 .setLocatorSet(locators).build();
303 HwvtepUtils.putRemoteMcastMac(transaction, nodeId, remoteUcastMac);
307 * Gets all the tep ips of dpns.
313 * @return the all tep ips of dpns and devices
315 private static List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
316 List<IpAddress> tepIps = new ArrayList<>();
317 for (DpnInterfaces dpn : dpns) {
318 IpAddress internalTunnelIp = ElanL2GatewayUtils.getSourceDpnTepIp(dpn.getDpId(),
319 new NodeId(l2GwDevice.getHwvtepNodeId()));
320 if (internalTunnelIp != null) {
321 tepIps.add(internalTunnelIp);
328 * Gets the all tep ips of l2 gw devices.
332 * @return the all tep ips of l2 gw devices
334 private static List<IpAddress> getAllTepIpsOfL2GwDevices(ConcurrentMap<String, L2GatewayDevice> devices) {
335 List<IpAddress> tepIps = new ArrayList<>();
336 for (L2GatewayDevice otherDevice : devices.values()) {
337 tepIps.add(otherDevice.getTunnelIp());
343 * Handle mcast for elan l2 gw device delete.
345 * @param elanInstance
347 * @param l2GatewayDevice
348 * the l2 gateway device
349 * @return the listenable future
351 public static List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(ElanInstance elanInstance,
352 L2GatewayDevice l2GatewayDevice) {
353 ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacsForAllElanDevices(elanInstance.getElanInstanceName(),
354 l2GatewayDevice, false/* updateThisDevice */);
355 ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
356 new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanInstance.getElanInstanceName());
357 return Lists.newArrayList(updateMcastMacsFuture, deleteRemoteMcastMacFuture);
361 * Delete remote mcast mac from Hwvtep node.
365 * @param logicalSwitchName
366 * the logical switch name
367 * @return the listenable future
369 private static ListenableFuture<Void> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
370 InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
371 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
372 RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
373 new MacAddress(ElanConstants.UNKNOWN_DMAC));
375 RemoteMcastMacs remoteMcast = HwvtepUtils.getRemoteMcastMac(broker, LogicalDatastoreType.OPERATIONAL, nodeId,
377 if (remoteMcast != null) {
378 LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
380 return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
383 SettableFuture<Void> future = SettableFuture.create();
389 * Gets the tep ip of designated switch for external tunnel.
393 * @param elanInstanceName
394 * the elan instance name
395 * @return the tep ip of designated switch for external tunnel
397 public static IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
398 String elanInstanceName) {
399 IpAddress tepIp = null;
400 DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
402 if (desgSwitch != null) {
403 tepIp = ElanL2GatewayUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
404 new NodeId(l2GwDevice.getHwvtepNodeId()));
410 * Gets the designated switch for external tunnel.
414 * @param elanInstanceName
415 * the elan instance name
416 * @return the designated switch for external tunnel
418 public static DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
419 String elanInstanceName) {
420 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
421 .builder(DesignatedSwitchesForExternalTunnels.class)
422 .child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
424 Optional<DesignatedSwitchForTunnel> designatedSwitchForTunnelOptional = MDSALUtil.read(broker,
425 LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
426 if (designatedSwitchForTunnelOptional.isPresent()) {
427 return designatedSwitchForTunnelOptional.get();