Adjust to odlparent 3 Checkstyle settings
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / listeners / InterfaceInventoryStateListener.java
1 /*
2  * Copyright (c) 2016, 2017 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.genius.interfacemanager.listeners;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.Objects;
15 import java.util.concurrent.Callable;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
22 import org.opendaylight.genius.interfacemanager.IfmConstants;
23 import org.opendaylight.genius.interfacemanager.IfmUtil;
24 import org.opendaylight.genius.interfacemanager.commons.AlivenessMonitorUtils;
25 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
26 import org.opendaylight.genius.interfacemanager.commons.InterfaceMetaUtils;
27 import org.opendaylight.genius.interfacemanager.renderer.ovs.statehelpers.OvsInterfaceStateAddHelper;
28 import org.opendaylight.genius.interfacemanager.renderer.ovs.statehelpers.OvsInterfaceStateUpdateHelper;
29 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
30 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
31 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
32 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortReason;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.AlivenessMonitorService;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info.InterfaceParentEntry;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info._interface.parent.entry.InterfaceChildEntry;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 /**
49  * This Class is a Data Change Listener for FlowCapableNodeConnector updates.
50  * This creates an entry in the interface-state OperDS for every node-connector
51  * used.
52  *
53  * <p>
54  * NOTE: This class just creates an ifstate entry whose interface-name will be
55  * the same as the node-connector portname. If PortName is not unique across
56  * DPNs, this implementation can have problems.
57  */
58 @Singleton
59 public class InterfaceInventoryStateListener
60         extends AsyncClusteredDataTreeChangeListenerBase<FlowCapableNodeConnector, InterfaceInventoryStateListener> {
61     private static final Logger LOG = LoggerFactory.getLogger(InterfaceInventoryStateListener.class);
62     private final DataBroker dataBroker;
63     private final IdManagerService idManager;
64     private final EntityOwnershipUtils entityOwnershipUtils;
65     private final JobCoordinator coordinator;
66     private final InterfaceManagerCommonUtils interfaceManagerCommonUtils;
67     private final AlivenessMonitorUtils alivenessMonitorUtils;
68     private final OvsInterfaceStateUpdateHelper ovsInterfaceStateUpdateHelper;
69     private final OvsInterfaceStateAddHelper ovsInterfaceStateAddHelper;
70     private final InterfaceMetaUtils interfaceMetaUtils;
71
72     @Inject
73     public InterfaceInventoryStateListener(final DataBroker dataBroker, final IdManagerService idManagerService,
74             final IMdsalApiManager mdsalApiManager, final AlivenessMonitorService alivenessMonitorService,
75             final EntityOwnershipUtils entityOwnershipUtils, final JobCoordinator coordinator,
76             final InterfaceManagerCommonUtils interfaceManagerCommonUtils,
77             final OvsInterfaceStateAddHelper ovsInterfaceStateAddHelper,
78             final OvsInterfaceStateUpdateHelper ovsInterfaceStateUpdateHelper,
79             final AlivenessMonitorUtils alivenessMonitorUtils,
80             final InterfaceMetaUtils interfaceMetaUtils) {
81         super(FlowCapableNodeConnector.class, InterfaceInventoryStateListener.class);
82         this.dataBroker = dataBroker;
83         this.idManager = idManagerService;
84         this.entityOwnershipUtils = entityOwnershipUtils;
85         this.coordinator = coordinator;
86         this.interfaceManagerCommonUtils = interfaceManagerCommonUtils;
87         this.alivenessMonitorUtils = alivenessMonitorUtils;
88         this.ovsInterfaceStateUpdateHelper = ovsInterfaceStateUpdateHelper;
89         this.ovsInterfaceStateAddHelper = ovsInterfaceStateAddHelper;
90         this.interfaceMetaUtils = interfaceMetaUtils;
91         this.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
92     }
93
94     @Override
95     protected InstanceIdentifier<FlowCapableNodeConnector> getWildCardPath() {
96         return InstanceIdentifier.create(Nodes.class).child(Node.class).child(NodeConnector.class)
97                 .augmentation(FlowCapableNodeConnector.class);
98     }
99
100     @Override
101     protected InterfaceInventoryStateListener getDataTreeChangeListener() {
102         return InterfaceInventoryStateListener.this;
103     }
104
105     @Override
106     protected void remove(InstanceIdentifier<FlowCapableNodeConnector> key,
107             FlowCapableNodeConnector flowCapableNodeConnectorOld) {
108         if (!entityOwnershipUtils.isEntityOwner(IfmConstants.INTERFACE_CONFIG_ENTITY,
109                 IfmConstants.INTERFACE_CONFIG_ENTITY)) {
110             return;
111         }
112
113         LOG.debug("Received NodeConnector Remove Event: {}, {}", key, flowCapableNodeConnectorOld);
114         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
115             .getId();
116         String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
117             flowCapableNodeConnectorOld.getName());
118
119         remove(nodeConnectorId, null, flowCapableNodeConnectorOld, portName, true);
120     }
121
122     private void remove(NodeConnectorId nodeConnectorIdNew, NodeConnectorId nodeConnectorIdOld,
123             FlowCapableNodeConnector fcNodeConnectorNew, String portName, boolean isNetworkEvent) {
124         boolean isNodePresent = interfaceManagerCommonUtils.isNodePresent(nodeConnectorIdNew);
125         InterfaceStateRemoveWorker portStateRemoveWorker = new InterfaceStateRemoveWorker(idManager, nodeConnectorIdNew,
126                 nodeConnectorIdOld, fcNodeConnectorNew, portName, isNodePresent, isNetworkEvent, true);
127         coordinator.enqueueJob(portName, portStateRemoveWorker, IfmConstants.JOB_MAX_RETRIES);
128     }
129
130     @Override
131     protected void update(InstanceIdentifier<FlowCapableNodeConnector> key, FlowCapableNodeConnector fcNodeConnectorOld,
132             FlowCapableNodeConnector fcNodeConnectorNew) {
133         if (!entityOwnershipUtils.isEntityOwner(IfmConstants.INTERFACE_CONFIG_ENTITY,
134                 IfmConstants.INTERFACE_CONFIG_ENTITY)) {
135             return;
136         }
137
138         LOG.debug("Received NodeConnector Update Event: {}, {}, {}", key, fcNodeConnectorOld, fcNodeConnectorNew);
139         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
140             .getId();
141         String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
142             fcNodeConnectorNew.getName());
143
144         InterfaceStateUpdateWorker portStateUpdateWorker = new InterfaceStateUpdateWorker(key, fcNodeConnectorOld,
145             fcNodeConnectorNew, portName);
146         coordinator.enqueueJob(portName, portStateUpdateWorker, IfmConstants.JOB_MAX_RETRIES);
147     }
148
149     @Override
150     protected void add(InstanceIdentifier<FlowCapableNodeConnector> key, FlowCapableNodeConnector fcNodeConnectorNew) {
151         if (!entityOwnershipUtils.isEntityOwner(IfmConstants.INTERFACE_CONFIG_ENTITY,
152                 IfmConstants.INTERFACE_CONFIG_ENTITY)) {
153             return;
154         }
155
156         LOG.debug("Received NodeConnector Add Event: {}, {}", key, fcNodeConnectorNew);
157         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
158             .getId();
159         String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
160             fcNodeConnectorNew.getName());
161
162         if (InterfaceManagerCommonUtils.isNovaPort(portName) || InterfaceManagerCommonUtils.isK8SPort(portName)) {
163             NodeConnectorId nodeConnectorIdOld =
164                     FlowBasedServicesUtils.getNodeConnectorIdFromInterface(portName, interfaceManagerCommonUtils);
165             if (nodeConnectorIdOld != null && !nodeConnectorId.equals(nodeConnectorIdOld)) {
166                 BigInteger dpnIdOld = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorIdOld);
167                 BigInteger dpnIdNew = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
168                 if (!Objects.equals(dpnIdOld, dpnIdNew)) {
169                     if (fcNodeConnectorNew.getReason() != PortReason.Add) {
170                         LOG.error("Dropping Port update event for {}, as DPN id is changed from {} to {}",
171                             fcNodeConnectorNew.getName(), dpnIdOld, dpnIdNew);
172                         return;
173                     }
174                 } else {
175                     LOG.warn("Port number update detected for {}", fcNodeConnectorNew.getName());
176                 }
177                 //VM Migration or Port Number Update: Delete existing interface entry for older DPN
178                 LOG.debug("Triggering NodeConnector Remove Event for the interface: {}, {}, {}", portName,
179                     nodeConnectorId, nodeConnectorIdOld);
180                 remove(nodeConnectorId, nodeConnectorIdOld, fcNodeConnectorNew, portName, false);
181                 // Adding a delay of 10sec for VM migration, so applications will have sufficient time
182                 // for processing remove before add
183                 try {
184                     Thread.sleep(IfmConstants.DELAY_TIME_IN_MILLISECOND);
185                 } catch (InterruptedException e) {
186                     LOG.error("Error while waiting for the vm migration remove events to get processed");
187                 }
188             }
189         }
190
191         InterfaceStateAddWorker ifStateAddWorker = new InterfaceStateAddWorker(idManager, nodeConnectorId,
192             fcNodeConnectorNew, portName);
193         coordinator.enqueueJob(portName, ifStateAddWorker, IfmConstants.JOB_MAX_RETRIES);
194     }
195
196
197     private class InterfaceStateAddWorker implements Callable {
198         private final NodeConnectorId nodeConnectorId;
199         private final FlowCapableNodeConnector fcNodeConnectorNew;
200         private final String interfaceName;
201         private final IdManagerService idManager;
202
203         InterfaceStateAddWorker(IdManagerService idManager, NodeConnectorId nodeConnectorId,
204                 FlowCapableNodeConnector fcNodeConnectorNew, String portName) {
205             this.nodeConnectorId = nodeConnectorId;
206             this.fcNodeConnectorNew = fcNodeConnectorNew;
207             this.interfaceName = portName;
208             this.idManager = idManager;
209         }
210
211         @Override
212         public Object call() {
213             List<ListenableFuture<Void>> futures = ovsInterfaceStateAddHelper.addState(nodeConnectorId, interfaceName,
214                     fcNodeConnectorNew);
215             List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(interfaceName);
216             for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
217                 InterfaceStateAddWorker interfaceStateAddWorker = new InterfaceStateAddWorker(idManager,
218                         nodeConnectorId, fcNodeConnectorNew, interfaceChildEntry.getChildInterface());
219                 coordinator.enqueueJob(interfaceName, interfaceStateAddWorker);
220             }
221             return futures;
222         }
223
224         @Override
225         public String toString() {
226             return "InterfaceStateAddWorker{" + "nodeConnectorId=" + nodeConnectorId + ", fcNodeConnectorNew="
227                     + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
228         }
229     }
230
231     private class InterfaceStateUpdateWorker implements Callable {
232         private final InstanceIdentifier<FlowCapableNodeConnector> key;
233         private final FlowCapableNodeConnector fcNodeConnectorOld;
234         private final FlowCapableNodeConnector fcNodeConnectorNew;
235         private final String interfaceName;
236
237         InterfaceStateUpdateWorker(InstanceIdentifier<FlowCapableNodeConnector> key,
238                 FlowCapableNodeConnector fcNodeConnectorOld, FlowCapableNodeConnector fcNodeConnectorNew,
239                 String portName) {
240             this.key = key;
241             this.fcNodeConnectorOld = fcNodeConnectorOld;
242             this.fcNodeConnectorNew = fcNodeConnectorNew;
243             this.interfaceName = portName;
244         }
245
246         @Override
247         public Object call() {
248             List<ListenableFuture<Void>> futures = ovsInterfaceStateUpdateHelper.updateState(
249                     interfaceName, fcNodeConnectorNew, fcNodeConnectorOld);
250             List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(interfaceName);
251             for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
252                 InterfaceStateUpdateWorker interfaceStateUpdateWorker = new InterfaceStateUpdateWorker(key,
253                         fcNodeConnectorOld, fcNodeConnectorNew, interfaceChildEntry.getChildInterface());
254                 coordinator.enqueueJob(interfaceName, interfaceStateUpdateWorker);
255             }
256             return futures;
257         }
258
259         @Override
260         public String toString() {
261             return "InterfaceStateUpdateWorker{" + "key=" + key + ", fcNodeConnectorOld=" + fcNodeConnectorOld
262                     + ", fcNodeConnectorNew=" + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
263         }
264     }
265
266     private class InterfaceStateRemoveWorker implements Callable {
267         private final NodeConnectorId nodeConnectorIdNew;
268         private NodeConnectorId nodeConnectorIdOld;
269         FlowCapableNodeConnector fcNodeConnectorOld;
270         private final String interfaceName;
271         private final IdManagerService idManager;
272         private final boolean isNodePresent;
273         private final boolean isNetworkEvent;
274         private final boolean isParentInterface;
275
276         InterfaceStateRemoveWorker(IdManagerService idManager, NodeConnectorId nodeConnectorIdNew,
277                 NodeConnectorId nodeConnectorIdOld, FlowCapableNodeConnector fcNodeConnectorOld, String interfaceName,
278                 boolean isNodePresent, boolean isNetworkEvent, boolean isParentInterface) {
279             this.nodeConnectorIdNew = nodeConnectorIdNew;
280             this.nodeConnectorIdOld = nodeConnectorIdOld;
281             this.fcNodeConnectorOld = fcNodeConnectorOld;
282             this.interfaceName = interfaceName;
283             this.idManager = idManager;
284             this.isNodePresent = isNodePresent;
285             this.isNetworkEvent = isNetworkEvent;
286             this.isParentInterface = isParentInterface;
287         }
288
289         @Override
290         public Object call() {
291             List<ListenableFuture<Void>> futures = null;
292             // VM Migration: Skip OFPPR_DELETE event received after OFPPR_ADD
293             // for same interface from Older DPN
294             if (isParentInterface && isNetworkEvent) {
295                 nodeConnectorIdOld = FlowBasedServicesUtils.getNodeConnectorIdFromInterface(interfaceName,
296                         interfaceManagerCommonUtils);
297                 if (nodeConnectorIdOld != null && !nodeConnectorIdNew.equals(nodeConnectorIdOld)) {
298                     LOG.debug("Dropping the NodeConnector Remove Event for the interface: {}, {}, {}", interfaceName,
299                             nodeConnectorIdNew, nodeConnectorIdOld);
300                     return futures;
301                 }
302             }
303
304             futures = removeInterfaceStateConfiguration();
305
306             List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(interfaceName);
307             for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
308                 // Fetch all interfaces on this port and trigger remove worker
309                 // for each of them
310                 InterfaceStateRemoveWorker interfaceStateRemoveWorker = new InterfaceStateRemoveWorker(idManager,
311                         nodeConnectorIdNew, nodeConnectorIdOld, fcNodeConnectorOld,
312                         interfaceChildEntry.getChildInterface(), isNodePresent, isNetworkEvent, false);
313                 coordinator.enqueueJob(interfaceName, interfaceStateRemoveWorker);
314             }
315             return futures;
316         }
317
318         private List<ListenableFuture<Void>> removeInterfaceStateConfiguration() {
319             LOG.debug("Removing interface state information for interface: {} {}", interfaceName, isNodePresent);
320             List<ListenableFuture<Void>> futures = new ArrayList<>();
321             WriteTransaction defaultOperationalShardTransaction = dataBroker.newWriteOnlyTransaction();
322
323             //VM Migration: Use old nodeConnectorId to delete the interface entry
324             NodeConnectorId nodeConnectorId = nodeConnectorIdOld != null
325                     && !nodeConnectorIdNew.equals(nodeConnectorIdOld) ? nodeConnectorIdOld : nodeConnectorIdNew;
326             // delete the port entry from interface operational DS
327             BigInteger dpId = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
328
329             //VM Migration: Update the interface state to unknown only if remove event received for same switch
330             if (!isNodePresent && nodeConnectorIdNew.equals(nodeConnectorIdOld)) {
331                 //Remove event is because of connection lost between controller and switch, or switch shutdown.
332                 // Hence, don't remove the interface but set the status as "unknown"
333                 ovsInterfaceStateUpdateHelper.updateInterfaceStateOnNodeRemove(interfaceName, fcNodeConnectorOld,
334                         defaultOperationalShardTransaction);
335             } else {
336                 InterfaceManagerCommonUtils.deleteStateEntry(interfaceName, defaultOperationalShardTransaction);
337                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
338                     .Interface iface = interfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName);
339
340                 if (iface != null) {
341                     // If this interface is a tunnel interface, remove the tunnel ingress flow and stop LLDP monitoring
342                     if (InterfaceManagerCommonUtils.isTunnelInterface(iface)) {
343                         interfaceMetaUtils.removeLportTagInterfaceMap(defaultOperationalShardTransaction,
344                                 interfaceName);
345                         handleTunnelMonitoringRemoval(dpId, iface.getName(), iface.getAugmentation(IfTunnel.class),
346                                 defaultOperationalShardTransaction, futures);
347                         return futures;
348                     }
349                 }
350                 // remove ingress flow only for northbound configured interfaces
351                 // skip this check for non-unique ports(Ex: br-int,br-ex)
352                 if (iface != null || !interfaceName.contains(fcNodeConnectorOld.getName())) {
353                     FlowBasedServicesUtils.removeIngressFlow(interfaceName, dpId, dataBroker, futures);
354                 }
355
356                 // Delete the Vpn Interface from DpnToInterface Op DS.
357                 interfaceManagerCommonUtils.deleteDpnToInterface(dpId, interfaceName,
358                         defaultOperationalShardTransaction);
359             }
360             futures.add(defaultOperationalShardTransaction.submit());
361             return futures;
362         }
363
364         private void handleTunnelMonitoringRemoval(BigInteger dpId, String removedInterfaceName,
365                 IfTunnel ifTunnel, WriteTransaction transaction, List<ListenableFuture<Void>> futures) {
366             interfaceManagerCommonUtils.removeTunnelIngressFlow(ifTunnel, dpId, removedInterfaceName);
367
368             IfmUtil.unbindService(dataBroker, coordinator, removedInterfaceName,
369                     FlowBasedServicesUtils.buildDefaultServiceId(removedInterfaceName));
370
371             futures.add(transaction.submit());
372             alivenessMonitorUtils.stopLLDPMonitoring(ifTunnel, removedInterfaceName);
373         }
374
375         @Override
376         public String toString() {
377             return "InterfaceStateRemoveWorker{" + "nodeConnectorIdNew=" + nodeConnectorIdNew + ", nodeConnectorIdOld="
378                     + nodeConnectorIdOld + ", fcNodeConnectorOld=" + fcNodeConnectorOld + ", interfaceName='"
379                     + interfaceName + '\'' + '}';
380         }
381     }
382
383     public List<InterfaceChildEntry> getInterfaceChildEntries(String interfaceName) {
384         InterfaceParentEntry interfaceParentEntry =
385                 interfaceMetaUtils.getInterfaceParentEntryFromConfigDS(interfaceName);
386         if (interfaceParentEntry != null && interfaceParentEntry.getInterfaceChildEntry() != null) {
387             return interfaceParentEntry.getInterfaceChildEntry();
388         }
389         return new ArrayList<>();
390     }
391 }