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 com.google.common.base.Optional;
11 import com.google.common.collect.Lists;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.SettableFuture;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.concurrent.ConcurrentMap;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
21 import org.opendaylight.genius.mdsalutil.MDSALUtil;
22 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
23 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
24 import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
25 import org.opendaylight.netvirt.elan.internal.ElanInterfaceManager;
26 import org.opendaylight.netvirt.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
27 import org.opendaylight.netvirt.elan.utils.ElanConstants;
28 import org.opendaylight.netvirt.elan.utils.ElanUtils;
29 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
30 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
54 * The utility class to handle ELAN L2 Gateway related to multicast.
56 public class ElanL2GatewayMulticastUtils {
58 /** The Constant LOG. */
59 private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
62 private final DataBroker broker;
64 /** The elan instance manager. */
65 private final ElanInstanceManager elanInstanceManager;
67 /** The elan interface manager. */
68 private final ElanInterfaceManager elanInterfaceManager;
70 private final ElanUtils elanUtils;
72 public ElanL2GatewayMulticastUtils(DataBroker broker, ElanInstanceManager elanInstanceManager,
73 ElanInterfaceManager elanInterfaceManager,
74 ElanUtils elanUtils) {
76 this.elanInstanceManager = elanInstanceManager;
77 this.elanInterfaceManager = elanInterfaceManager;
78 this.elanUtils = elanUtils;
82 * Handle mcast for elan l2 gw device add.
88 * @return the listenable future
90 public ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
91 return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
95 * Updates the remote mcast mac table for all the devices in this elan
96 * includes all the dpn tep ips and other devices tep ips in broadcast
100 * the elan to be updated
101 * @return the listenable future
103 public ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
104 SettableFuture<Void> future = SettableFuture.create();
107 WriteTransaction transaction = broker.newWriteOnlyTransaction();
108 for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
109 prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
111 return transaction.submit();
112 } catch (Throwable e) {
113 LOG.error("Failed to configure mcast mac on elan " + elanName, e);
118 public void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
119 HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(this, elanName,device);
120 DataStoreJobCoordinator.getInstance().enqueueJob(job.getJobKey(), job);
124 * Update remote mcast mac on elan l2 gw device.
130 * @return the listenable future
132 public ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
133 WriteTransaction transaction = broker.newWriteOnlyTransaction();
134 prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
135 return transaction.submit();
138 public void prepareRemoteMcastMacUpdateOnDevice(WriteTransaction transaction,String elanName,
139 L2GatewayDevice device) {
140 ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils
141 .getInvolvedL2GwDevices(elanName);
142 List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanName);
143 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
144 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
145 preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
149 * Update mcast macs for this elan.
150 * for all dpns in this elan recompute and update broadcast group
151 * for all l2gw devices in this elan recompute and update remote mcast mac entry
157 * @param updateThisDevice
158 * the update this device
159 * @return the listenable future
161 public ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
162 boolean updateThisDevice) {
164 SettableFuture<Void> ft = SettableFuture.create();
167 ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName);
168 elanInterfaceManager.updateRemoteBroadcastGroupForAllElanDpns(elanInstance);
170 List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanName);
172 ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
173 .getInvolvedL2GwDevices(elanName);
175 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
176 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices);
177 // if (allTepIps.size() < 2) {
178 // LOG.debug("no other devices are found in the elan {}", elanName);
182 WriteTransaction transaction = broker.newWriteOnlyTransaction();
183 if (updateThisDevice) {
184 preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
187 // TODO: Need to revisit below logic as logical switches might not be
188 // present to configure RemoteMcastMac entry
189 for (L2GatewayDevice otherDevice : devices.values()) {
190 if (!otherDevice.getDeviceName().equals(device.getDeviceName())) {
191 preapareRemoteMcastMacEntry(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
194 return transaction.submit();
199 * Update remote mcast mac.
209 * @param l2GwDevicesTepIps
210 * the l2 gw devices tep ips
211 * @return the write transaction
213 private void preapareRemoteMcastMacEntry(WriteTransaction transaction, String elanName,
214 L2GatewayDevice device, List<IpAddress> dpnsTepIps,
215 List<IpAddress> l2GwDevicesTepIps) {
216 NodeId nodeId = new NodeId(device.getHwvtepNodeId());
218 ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
219 remoteTepIps.remove(device.getTunnelIp());
220 remoteTepIps.addAll(dpnsTepIps);
221 if (dpnsTepIps.isEmpty()) {
222 // If no dpns in elan, configure dhcp designated switch Tep Ip as a
223 // physical locator in l2 gw device
224 IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
225 if (dhcpDesignatedSwitchTepIp != null) {
226 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
228 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
229 .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
230 HwvtepUtils.putPhysicalLocator(transaction, nodeId, phyLocatorAug);
232 LOG.info("Adding PhysicalLocator for node: {} with Dhcp designated switch Tep Ip {} "
233 + "as physical locator, elan {}", device.getHwvtepNodeId(),
234 String.valueOf(dhcpDesignatedSwitchTepIp.getValue()), elanName);
236 LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
237 device.getHwvtepNodeId(), elanName);
241 String logicalSwitchName = ""; // ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
242 putRemoteMcastMac(transaction, nodeId, logicalSwitchName, remoteTepIps);
243 LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
248 * Put remote mcast mac in config DS.
254 * @param logicalSwitchName
255 * the logical switch name
259 private static void putRemoteMcastMac(WriteTransaction transaction, NodeId nodeId, String logicalSwitchName,
260 ArrayList<IpAddress> tepIps) {
261 List<LocatorSet> locators = new ArrayList<>();
262 for (IpAddress tepIp : tepIps) {
263 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
264 .createHwvtepPhysicalLocatorAugmentation(String.valueOf(tepIp.getValue()));
265 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
266 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
267 locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
270 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
271 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
272 RemoteMcastMacs remoteUcastMac = new RemoteMcastMacsBuilder()
273 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
274 .setLocatorSet(locators).build();
275 HwvtepUtils.putRemoteMcastMac(transaction, nodeId, remoteUcastMac);
279 * Gets all the tep ips of dpns.
285 * @return the all tep ips of dpns and devices
287 private List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
288 List<IpAddress> tepIps = new ArrayList<>();
289 for (DpnInterfaces dpn : dpns) {
290 IpAddress internalTunnelIp = null;//elanL2GatewayUtils.getSourceDpnTepIp(dpn.getDpId(),
291 //new NodeId(l2GwDevice.getHwvtepNodeId()));
292 if (internalTunnelIp != null) {
293 tepIps.add(internalTunnelIp);
300 * Gets the all tep ips of l2 gw devices.
304 * @return the all tep ips of l2 gw devices
306 private static List<IpAddress> getAllTepIpsOfL2GwDevices(ConcurrentMap<String, L2GatewayDevice> devices) {
307 List<IpAddress> tepIps = new ArrayList<>();
308 for (L2GatewayDevice otherDevice : devices.values()) {
309 tepIps.add(otherDevice.getTunnelIp());
315 * Handle mcast for elan l2 gw device delete.
317 * @param elanInstance
319 * @param l2GatewayDevice
320 * the l2 gateway device
321 * @return the listenable future
323 public List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(ElanInstance elanInstance,
324 L2GatewayDevice l2GatewayDevice) {
325 ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacsForAllElanDevices(elanInstance.getElanInstanceName(),
326 l2GatewayDevice, false/* updateThisDevice */);
327 ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
328 new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanInstance.getElanInstanceName());
329 return Lists.newArrayList(updateMcastMacsFuture, deleteRemoteMcastMacFuture);
333 * Delete remote mcast mac from Hwvtep node.
337 * @param logicalSwitchName
338 * the logical switch name
339 * @return the listenable future
341 private ListenableFuture<Void> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
342 InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
343 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
344 RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
345 new MacAddress(ElanConstants.UNKNOWN_DMAC));
347 LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
349 return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
353 * Gets the tep ip of designated switch for external tunnel.
357 * @param elanInstanceName
358 * the elan instance name
359 * @return the tep ip of designated switch for external tunnel
361 public IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
362 String elanInstanceName) {
363 IpAddress tepIp = null;
364 if (l2GwDevice.getTunnelIp() == null) {
365 LOG.warn("Tunnel IP not found for {}", l2GwDevice.getDeviceName());
368 DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
370 if (desgSwitch != null) {
371 tepIp = null;//elanL2GatewayUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
372 //new NodeId(l2GwDevice.getHwvtepNodeId()));
378 * Gets the designated switch for external tunnel.
382 * @param elanInstanceName
383 * the elan instance name
384 * @return the designated switch for external tunnel
386 public DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
387 String elanInstanceName) {
388 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
389 .builder(DesignatedSwitchesForExternalTunnels.class)
390 .child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
392 Optional<DesignatedSwitchForTunnel> designatedSwitchForTunnelOptional = MDSALUtil.read(broker,
393 LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
394 if (designatedSwitchForTunnelOptional.isPresent()) {
395 return designatedSwitchForTunnelOptional.get();