Updated L2Gw changes in "neutronvpn", "elanmanager" and "dhcpservice" modules
[vpnservice.git] / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / vpnservice / elan / l2gw / utils / ElanL2GatewayMulticastUtils.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.vpnservice.elan.l2gw.utils;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.ConcurrentMap;
14
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;
50
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;
55
56 /**
57  * The utility class to handle ELAN L2 Gateway related to multicast.
58  */
59 public class ElanL2GatewayMulticastUtils {
60
61     /** The Constant LOG. */
62     private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
63
64     /** The broker. */
65     private static DataBroker broker;
66
67     /** The elan instance manager. */
68     private static ElanInstanceManager elanInstanceManager;
69
70     /** The elan interface manager. */
71     private static ElanInterfaceManager elanInterfaceManager;
72
73     static DataStoreJobCoordinator dataStoreJobCoordinator;
74
75     public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
76         dataStoreJobCoordinator = ds;
77     }
78
79     /**
80      * Sets the broker.
81      *
82      * @param broker
83      *            the new broker
84      */
85     public static void setBroker(DataBroker broker) {
86         ElanL2GatewayMulticastUtils.broker = broker;
87     }
88
89     /**
90      * Sets the elan instance manager.
91      *
92      * @param elanMgr
93      *            the new elan instance manager
94      */
95     public static void setElanInstanceManager(ElanInstanceManager elanMgr) {
96         ElanL2GatewayMulticastUtils.elanInstanceManager = elanMgr;
97     }
98
99     /**
100      * Sets the elan interface manager.
101      *
102      * @param interfaceMgr
103      *            the new elan interface manager
104      */
105     public static void setElanInterfaceManager(ElanInterfaceManager interfaceMgr) {
106         elanInterfaceManager = interfaceMgr;
107     }
108
109     /**
110      * Handle mcast for elan l2 gw device add.
111      *
112      * @param elanName
113      *            the elan name
114      * @param device
115      *            the device
116      * @return the listenable future
117      */
118     public static ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
119         return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
120     }
121
122     /**
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
125      * locator set.
126      *
127      * @param elanName
128      *            the elan to be updated
129      * @return the listenable future
130      */
131     public static ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
132         SettableFuture<Void> future = SettableFuture.create();
133         future.set(null);
134         try {
135             WriteTransaction transaction = broker.newWriteOnlyTransaction();
136             for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
137                 prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
138             }
139             return transaction.submit();
140         } catch (Throwable e) {
141             LOG.error("Failed to configure mcast mac on elan " + elanName, e);
142         }
143         return future;
144     }
145
146     public static void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
147         HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(elanName,device);
148         dataStoreJobCoordinator.enqueueJob(job.getJobKey(), job);
149     }
150
151     /**
152      * Update remote mcast mac on elan l2 gw device.
153      *
154      * @param elanName
155      *            the elan name
156      * @param device
157      *            the device
158      * @return the listenable future
159      */
160     public static ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
161         WriteTransaction transaction = broker.newWriteOnlyTransaction();
162         prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
163         return transaction.submit();
164     }
165
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);
174     }
175
176     /**
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
180      *
181      * @param elanName
182      *            the elan name
183      * @param device
184      *            the device
185      * @param updateThisDevice
186      *            the update this device
187      * @return the listenable future
188      */
189     public static ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
190                                                                           boolean updateThisDevice) {
191
192         SettableFuture<Void> ft = SettableFuture.create();
193         ft.set(null);
194
195         ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName);
196         elanInterfaceManager.updateRemoteBroadcastGroupForAllElanDpns(elanInstance);
197
198         List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
199
200         ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
201                 .getInvolvedL2GwDevices(elanName);
202
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);
207         // return ft;
208         // }
209
210         WriteTransaction transaction = broker.newWriteOnlyTransaction();
211         if (updateThisDevice) {
212             preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
213         }
214
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);
220             }
221         }
222         return transaction.submit();
223
224     }
225
226     /**
227      * Update remote mcast mac.
228      *
229      * @param transaction
230      *            the transaction
231      * @param elanName
232      *            the elan name
233      * @param device
234      *            the device
235      * @param dpnsTepIps
236      *            the dpns tep ips
237      * @param l2GwDevicesTepIps
238      *            the l2 gw devices tep ips
239      * @return the write transaction
240      */
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);
246
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);
256
257                 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
258                         .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
259                 HwvtepUtils.putPhysicalLocator(transaction, nodeId, phyLocatorAug);
260
261                 LOG.info(
262                         "Adding PhysicalLocator for node: {} with Dhcp designated switch Tep Ip {} as physical locator, elan {}",
263                         device.getHwvtepNodeId(), String.valueOf(dhcpDesignatedSwitchTepIp.getValue()), elanName);
264             } else {
265                 LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
266                         device.getHwvtepNodeId(), elanName);
267             }
268         }
269
270         putRemoteMcastMac(transaction, nodeId, logicalSwitchName, remoteTepIps);
271         LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
272                 remoteTepIps);
273     }
274
275     /**
276      * Put remote mcast mac in config DS.
277      *
278      * @param transaction
279      *            the transaction
280      * @param nodeId
281      *            the node id
282      * @param logicalSwitchName
283      *            the logical switch name
284      * @param tepIps
285      *            the tep ips
286      */
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());
296         }
297
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);
304     }
305
306     /**
307      * Gets all the tep ips of dpns.
308      *
309      * @param l2GwDevice
310      *            the device
311      * @param dpns
312      *            the dpns
313      * @return the all tep ips of dpns and devices
314      */
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);
322             }
323         }
324         return tepIps;
325     }
326
327     /**
328      * Gets the all tep ips of l2 gw devices.
329      *
330      * @param devices
331      *            the devices
332      * @return the all tep ips of l2 gw devices
333      */
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());
338         }
339         return tepIps;
340     }
341
342     /**
343      * Handle mcast for elan l2 gw device delete.
344      *
345      * @param elanInstance
346      *            the elan instance
347      * @param l2GatewayDevice
348      *            the l2 gateway device
349      * @return the listenable future
350      */
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);
358     }
359
360     /**
361      * Delete remote mcast mac from Hwvtep node.
362      *
363      * @param nodeId
364      *            the node id
365      * @param logicalSwitchName
366      *            the logical switch name
367      * @return the listenable future
368      */
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));
374
375         RemoteMcastMacs remoteMcast = HwvtepUtils.getRemoteMcastMac(broker, LogicalDatastoreType.OPERATIONAL, nodeId,
376                 remoteMcastMacsKey);
377         if (remoteMcast != null) {
378             LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
379                     logicalSwitchName);
380             return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
381         }
382
383         SettableFuture<Void> future = SettableFuture.create();
384         future.set(null);
385         return future;
386     }
387
388     /**
389      * Gets the tep ip of designated switch for external tunnel.
390      *
391      * @param l2GwDevice
392      *            the l2 gw device
393      * @param elanInstanceName
394      *            the elan instance name
395      * @return the tep ip of designated switch for external tunnel
396      */
397     public static IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
398             String elanInstanceName) {
399         IpAddress tepIp = null;
400         DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
401                 elanInstanceName);
402         if (desgSwitch != null) {
403             tepIp = ElanL2GatewayUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
404                     new NodeId(l2GwDevice.getHwvtepNodeId()));
405         }
406         return tepIp;
407     }
408
409     /**
410      * Gets the designated switch for external tunnel.
411      *
412      * @param tunnelIp
413      *            the tunnel ip
414      * @param elanInstanceName
415      *            the elan instance name
416      * @return the designated switch for external tunnel
417      */
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))
423                 .build();
424         Optional<DesignatedSwitchForTunnel> designatedSwitchForTunnelOptional = MDSALUtil.read(broker,
425                 LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
426         if (designatedSwitchForTunnelOptional.isPresent()) {
427             return designatedSwitchForTunnelOptional.get();
428         }
429         return null;
430     }
431
432 }