Merge "elanmanager Checkstyle clean-up (94%) "
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / 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.netvirt.elan.l2gw.utils;
9
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;
52
53 /**
54  * The utility class to handle ELAN L2 Gateway related to multicast.
55  */
56 public class ElanL2GatewayMulticastUtils {
57
58     /** The Constant LOG. */
59     private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
60
61     /** The broker. */
62     private final DataBroker broker;
63
64     /** The elan instance manager. */
65     private final ElanInstanceManager elanInstanceManager;
66
67     /** The elan interface manager. */
68     private final ElanInterfaceManager elanInterfaceManager;
69
70     private final ElanUtils elanUtils;
71
72     public ElanL2GatewayMulticastUtils(DataBroker broker, ElanInstanceManager elanInstanceManager,
73                                        ElanInterfaceManager elanInterfaceManager,
74                                        ElanUtils elanUtils) {
75         this.broker = broker;
76         this.elanInstanceManager = elanInstanceManager;
77         this.elanInterfaceManager = elanInterfaceManager;
78         this.elanUtils = elanUtils;
79     }
80
81     /**
82      * Handle mcast for elan l2 gw device add.
83      *
84      * @param elanName
85      *            the elan name
86      * @param device
87      *            the device
88      * @return the listenable future
89      */
90     public ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
91         return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
92     }
93
94     /**
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
97      * locator set.
98      *
99      * @param elanName
100      *            the elan to be updated
101      * @return the listenable future
102      */
103     public ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
104         SettableFuture<Void> future = SettableFuture.create();
105         future.set(null);
106         try {
107             WriteTransaction transaction = broker.newWriteOnlyTransaction();
108             for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
109                 prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
110             }
111             return transaction.submit();
112         } catch (Throwable e) {
113             LOG.error("Failed to configure mcast mac on elan " + elanName, e);
114         }
115         return future;
116     }
117
118     public void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
119         HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(this, elanName,device);
120         DataStoreJobCoordinator.getInstance().enqueueJob(job.getJobKey(), job);
121     }
122
123     /**
124      * Update remote mcast mac on elan l2 gw device.
125      *
126      * @param elanName
127      *            the elan name
128      * @param device
129      *            the device
130      * @return the listenable future
131      */
132     public ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
133         WriteTransaction transaction = broker.newWriteOnlyTransaction();
134         prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
135         return transaction.submit();
136     }
137
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);
146     }
147
148     /**
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
152      *
153      * @param elanName
154      *            the elan name
155      * @param device
156      *            the device
157      * @param updateThisDevice
158      *            the update this device
159      * @return the listenable future
160      */
161     public ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
162                                                                           boolean updateThisDevice) {
163
164         SettableFuture<Void> ft = SettableFuture.create();
165         ft.set(null);
166
167         ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName);
168         elanInterfaceManager.updateRemoteBroadcastGroupForAllElanDpns(elanInstance);
169
170         List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanName);
171
172         ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
173                 .getInvolvedL2GwDevices(elanName);
174
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);
179         // return ft;
180         // }
181
182         WriteTransaction transaction = broker.newWriteOnlyTransaction();
183         if (updateThisDevice) {
184             preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
185         }
186
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);
192             }
193         }
194         return transaction.submit();
195
196     }
197
198     /**
199      * Update remote mcast mac.
200      *
201      * @param transaction
202      *            the transaction
203      * @param elanName
204      *            the elan name
205      * @param device
206      *            the device
207      * @param dpnsTepIps
208      *            the dpns tep ips
209      * @param l2GwDevicesTepIps
210      *            the l2 gw devices tep ips
211      * @return the write transaction
212      */
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());
217
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);
227
228                 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
229                         .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
230                 HwvtepUtils.putPhysicalLocator(transaction, nodeId, phyLocatorAug);
231
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);
235             } else {
236                 LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
237                         device.getHwvtepNodeId(), elanName);
238             }
239         }
240
241         String logicalSwitchName = ""; // ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
242         putRemoteMcastMac(transaction, nodeId, logicalSwitchName, remoteTepIps);
243         LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
244                 remoteTepIps);
245     }
246
247     /**
248      * Put remote mcast mac in config DS.
249      *
250      * @param transaction
251      *            the transaction
252      * @param nodeId
253      *            the node id
254      * @param logicalSwitchName
255      *            the logical switch name
256      * @param tepIps
257      *            the tep ips
258      */
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());
268         }
269
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);
276     }
277
278     /**
279      * Gets all the tep ips of dpns.
280      *
281      * @param l2GwDevice
282      *            the device
283      * @param dpns
284      *            the dpns
285      * @return the all tep ips of dpns and devices
286      */
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);
294             }
295         }
296         return tepIps;
297     }
298
299     /**
300      * Gets the all tep ips of l2 gw devices.
301      *
302      * @param devices
303      *            the devices
304      * @return the all tep ips of l2 gw devices
305      */
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());
310         }
311         return tepIps;
312     }
313
314     /**
315      * Handle mcast for elan l2 gw device delete.
316      *
317      * @param elanInstance
318      *            the elan instance
319      * @param l2GatewayDevice
320      *            the l2 gateway device
321      * @return the listenable future
322      */
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);
330     }
331
332     /**
333      * Delete remote mcast mac from Hwvtep node.
334      *
335      * @param nodeId
336      *            the node id
337      * @param logicalSwitchName
338      *            the logical switch name
339      * @return the listenable future
340      */
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));
346
347         LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
348                 logicalSwitchName);
349         return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
350     }
351
352     /**
353      * Gets the tep ip of designated switch for external tunnel.
354      *
355      * @param l2GwDevice
356      *            the l2 gw device
357      * @param elanInstanceName
358      *            the elan instance name
359      * @return the tep ip of designated switch for external tunnel
360      */
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());
366             return tepIp;
367         }
368         DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
369                 elanInstanceName);
370         if (desgSwitch != null) {
371             tepIp = null;//elanL2GatewayUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
372                     //new NodeId(l2GwDevice.getHwvtepNodeId()));
373         }
374         return tepIp;
375     }
376
377     /**
378      * Gets the designated switch for external tunnel.
379      *
380      * @param tunnelIp
381      *            the tunnel ip
382      * @param elanInstanceName
383      *            the elan instance name
384      * @return the designated switch for external tunnel
385      */
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))
391                 .build();
392         Optional<DesignatedSwitchForTunnel> designatedSwitchForTunnelOptional = MDSALUtil.read(broker,
393                 LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
394         if (designatedSwitchForTunnelOptional.isPresent()) {
395             return designatedSwitchForTunnelOptional.get();
396         }
397         return null;
398     }
399
400 }