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 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.netvirt.elan.internal.ElanInterfaceManager;
19 import org.opendaylight.netvirt.elan.utils.ElanUtils;
20 import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
21 import org.opendaylight.netvirt.elan.utils.ElanConstants;
22 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
23 import org.opendaylight.netvirt.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
24 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
25 import org.opendaylight.genius.mdsalutil.MDSALUtil;
26 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
27 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
28 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.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.netvirt.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.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 final DataBroker broker;
67 /** The elan instance manager. */
68 private final ElanInstanceManager elanInstanceManager;
70 /** The elan interface manager. */
71 private final ElanInterfaceManager elanInterfaceManager;
73 private final ElanL2GatewayUtils elanL2GatewayUtils;
75 private final ElanUtils elanUtils;
77 public ElanL2GatewayMulticastUtils(DataBroker broker, ElanInstanceManager elanInstanceManager,
78 ElanInterfaceManager elanInterfaceManager, ElanL2GatewayUtils elanL2GatewayUtils,
79 ElanUtils elanUtils) {
81 this.elanInstanceManager = elanInstanceManager;
82 this.elanInterfaceManager = elanInterfaceManager;
83 this.elanL2GatewayUtils = elanL2GatewayUtils;
84 this.elanUtils = elanUtils;
88 * Handle mcast for elan l2 gw device add.
94 * @return the listenable future
96 public ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
97 return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
101 * Updates the remote mcast mac table for all the devices in this elan
102 * includes all the dpn tep ips and other devices tep ips in broadcast
106 * the elan to be updated
107 * @return the listenable future
109 public ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
110 SettableFuture<Void> future = SettableFuture.create();
113 WriteTransaction transaction = broker.newWriteOnlyTransaction();
114 for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
115 prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
117 return transaction.submit();
118 } catch (Throwable e) {
119 LOG.error("Failed to configure mcast mac on elan " + elanName, e);
124 public void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
125 HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(this, elanName,device);
126 DataStoreJobCoordinator.getInstance().enqueueJob(job.getJobKey(), job);
130 * Update remote mcast mac on elan l2 gw device.
136 * @return the listenable future
138 public ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
139 WriteTransaction transaction = broker.newWriteOnlyTransaction();
140 prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
141 return transaction.submit();
144 public void prepareRemoteMcastMacUpdateOnDevice(WriteTransaction transaction,String elanName,
145 L2GatewayDevice device) {
146 ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils
147 .getInvolvedL2GwDevices(elanName);
148 List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanName);
149 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
150 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
151 preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
155 * Update mcast macs for this elan.
156 * for all dpns in this elan recompute and update broadcast group
157 * for all l2gw devices in this elan recompute and update remote mcast mac entry
163 * @param updateThisDevice
164 * the update this device
165 * @return the listenable future
167 public ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
168 boolean updateThisDevice) {
170 SettableFuture<Void> ft = SettableFuture.create();
173 ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName);
174 elanInterfaceManager.updateRemoteBroadcastGroupForAllElanDpns(elanInstance);
176 List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanName);
178 ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
179 .getInvolvedL2GwDevices(elanName);
181 List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
182 List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices);
183 // if (allTepIps.size() < 2) {
184 // LOG.debug("no other devices are found in the elan {}", elanName);
188 WriteTransaction transaction = broker.newWriteOnlyTransaction();
189 if (updateThisDevice) {
190 preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
193 // TODO: Need to revisit below logic as logical switches might not be
194 // present to configure RemoteMcastMac entry
195 for (L2GatewayDevice otherDevice : devices.values()) {
196 if (!otherDevice.getDeviceName().equals(device.getDeviceName())) {
197 preapareRemoteMcastMacEntry(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
200 return transaction.submit();
205 * Update remote mcast mac.
215 * @param l2GwDevicesTepIps
216 * the l2 gw devices tep ips
217 * @return the write transaction
219 private void preapareRemoteMcastMacEntry(WriteTransaction transaction, String elanName,
220 L2GatewayDevice device, List<IpAddress> dpnsTepIps,
221 List<IpAddress> l2GwDevicesTepIps) {
222 NodeId nodeId = new NodeId(device.getHwvtepNodeId());
223 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
225 ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
226 remoteTepIps.remove(device.getTunnelIp());
227 remoteTepIps.addAll(dpnsTepIps);
228 if (dpnsTepIps.isEmpty()) {
229 // If no dpns in elan, configure dhcp designated switch Tep Ip as a
230 // physical locator in l2 gw device
231 IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
232 if (dhcpDesignatedSwitchTepIp != null) {
233 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
235 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
236 .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
237 HwvtepUtils.putPhysicalLocator(transaction, nodeId, phyLocatorAug);
240 "Adding PhysicalLocator for node: {} with Dhcp designated switch Tep Ip {} as physical locator, elan {}",
241 device.getHwvtepNodeId(), String.valueOf(dhcpDesignatedSwitchTepIp.getValue()), elanName);
243 LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
244 device.getHwvtepNodeId(), elanName);
248 putRemoteMcastMac(transaction, nodeId, logicalSwitchName, remoteTepIps);
249 LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
254 * Put remote mcast mac in config DS.
260 * @param logicalSwitchName
261 * the logical switch name
265 private static void putRemoteMcastMac(WriteTransaction transaction, NodeId nodeId, String logicalSwitchName,
266 ArrayList<IpAddress> tepIps) {
267 List<LocatorSet> locators = new ArrayList<>();
268 for (IpAddress tepIp : tepIps) {
269 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
270 .createHwvtepPhysicalLocatorAugmentation(String.valueOf(tepIp.getValue()));
271 HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
272 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
273 locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
276 HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
277 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
278 RemoteMcastMacs remoteUcastMac = new RemoteMcastMacsBuilder()
279 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
280 .setLocatorSet(locators).build();
281 HwvtepUtils.putRemoteMcastMac(transaction, nodeId, remoteUcastMac);
285 * Gets all the tep ips of dpns.
291 * @return the all tep ips of dpns and devices
293 private List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
294 List<IpAddress> tepIps = new ArrayList<>();
295 for (DpnInterfaces dpn : dpns) {
296 IpAddress internalTunnelIp = elanL2GatewayUtils.getSourceDpnTepIp(dpn.getDpId(),
297 new NodeId(l2GwDevice.getHwvtepNodeId()));
298 if (internalTunnelIp != null) {
299 tepIps.add(internalTunnelIp);
306 * Gets the all tep ips of l2 gw devices.
310 * @return the all tep ips of l2 gw devices
312 private static List<IpAddress> getAllTepIpsOfL2GwDevices(ConcurrentMap<String, L2GatewayDevice> devices) {
313 List<IpAddress> tepIps = new ArrayList<>();
314 for (L2GatewayDevice otherDevice : devices.values()) {
315 tepIps.add(otherDevice.getTunnelIp());
321 * Handle mcast for elan l2 gw device delete.
323 * @param elanInstance
325 * @param l2GatewayDevice
326 * the l2 gateway device
327 * @return the listenable future
329 public List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(ElanInstance elanInstance,
330 L2GatewayDevice l2GatewayDevice) {
331 ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacsForAllElanDevices(elanInstance.getElanInstanceName(),
332 l2GatewayDevice, false/* updateThisDevice */);
333 ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
334 new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanInstance.getElanInstanceName());
335 return Lists.newArrayList(updateMcastMacsFuture, deleteRemoteMcastMacFuture);
339 * Delete remote mcast mac from Hwvtep node.
343 * @param logicalSwitchName
344 * the logical switch name
345 * @return the listenable future
347 private ListenableFuture<Void> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
348 InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
349 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
350 RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
351 new MacAddress(ElanConstants.UNKNOWN_DMAC));
353 LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
355 return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
359 * Gets the tep ip of designated switch for external tunnel.
363 * @param elanInstanceName
364 * the elan instance name
365 * @return the tep ip of designated switch for external tunnel
367 public IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
368 String elanInstanceName) {
369 IpAddress tepIp = null;
370 if (l2GwDevice.getTunnelIp() == null) {
371 LOG.warn("Tunnel IP not found for {}", l2GwDevice.getDeviceName());
374 DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
376 if (desgSwitch != null) {
377 tepIp = elanL2GatewayUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
378 new NodeId(l2GwDevice.getHwvtepNodeId()));
384 * Gets the designated switch for external tunnel.
388 * @param elanInstanceName
389 * the elan instance name
390 * @return the designated switch for external tunnel
392 public DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
393 String elanInstanceName) {
394 InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
395 .builder(DesignatedSwitchesForExternalTunnels.class)
396 .child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
398 Optional<DesignatedSwitchForTunnel> designatedSwitchForTunnelOptional = MDSALUtil.read(broker,
399 LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
400 if (designatedSwitchForTunnelOptional.isPresent()) {
401 return designatedSwitchForTunnelOptional.get();