Merge "Ensure unique ids are allocate across cluster"
[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.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.Callable;
14 import javax.inject.Inject;
15 import javax.inject.Singleton;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
19 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
20 import org.opendaylight.genius.interfacemanager.IfmConstants;
21 import org.opendaylight.genius.interfacemanager.IfmUtil;
22 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
23 import org.opendaylight.genius.interfacemanager.commons.InterfaceMetaUtils;
24 import org.opendaylight.genius.interfacemanager.renderer.ovs.statehelpers.OvsInterfaceStateAddHelper;
25 import org.opendaylight.genius.interfacemanager.renderer.ovs.statehelpers.OvsInterfaceStateRemoveHelper;
26 import org.opendaylight.genius.interfacemanager.renderer.ovs.statehelpers.OvsInterfaceStateUpdateHelper;
27 import org.opendaylight.genius.interfacemanager.renderer.ovs.utilities.IfmClusterUtils;
28 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.AlivenessMonitorService;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info.InterfaceParentEntry;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info._interface.parent.entry.InterfaceChildEntry;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * This Class is a Data Change Listener for FlowCapableNodeConnector updates.
44  * This creates an entry in the interface-state OperDS for every node-connector
45  * used.
46  *
47  * <p>
48  * NOTE: This class just creates an ifstate entry whose interface-name will be
49  * the same as the node-connector portname. If PortName is not unique across
50  * DPNs, this implementation can have problems.
51  */
52 @Singleton
53 public class InterfaceInventoryStateListener
54         extends AsyncClusteredDataTreeChangeListenerBase<FlowCapableNodeConnector, InterfaceInventoryStateListener> {
55     private static final Logger LOG = LoggerFactory.getLogger(InterfaceInventoryStateListener.class);
56     private final DataBroker dataBroker;
57     private final IdManagerService idManager;
58     private final IMdsalApiManager mdsalApiManager;
59     private final AlivenessMonitorService alivenessMonitorService;
60
61     @Inject
62     public InterfaceInventoryStateListener(final DataBroker dataBroker, final IdManagerService idManagerService,
63             final IMdsalApiManager mdsalApiManager, final AlivenessMonitorService alivenessMonitorService) {
64         super(FlowCapableNodeConnector.class, InterfaceInventoryStateListener.class);
65         this.dataBroker = dataBroker;
66         this.idManager = idManagerService;
67         this.mdsalApiManager = mdsalApiManager;
68         this.alivenessMonitorService = alivenessMonitorService;
69         this.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
70     }
71
72     @Override
73     protected InstanceIdentifier<FlowCapableNodeConnector> getWildCardPath() {
74         return InstanceIdentifier.create(Nodes.class).child(Node.class).child(NodeConnector.class)
75                 .augmentation(FlowCapableNodeConnector.class);
76     }
77
78     @Override
79     protected InterfaceInventoryStateListener getDataTreeChangeListener() {
80         return InterfaceInventoryStateListener.this;
81     }
82
83     @Override
84     protected void remove(InstanceIdentifier<FlowCapableNodeConnector> key,
85             FlowCapableNodeConnector flowCapableNodeConnectorOld) {
86         IfmClusterUtils.runOnlyInLeaderNode(() -> {
87             LOG.debug("Received NodeConnector Remove Event: {}, {}", key, flowCapableNodeConnectorOld);
88             NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
89                     .getId();
90             String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
91                     flowCapableNodeConnectorOld.getName());
92
93             remove(nodeConnectorId, null, flowCapableNodeConnectorOld, portName, true);
94         }, IfmClusterUtils.INTERFACE_CONFIG_ENTITY);
95     }
96
97     private void remove(NodeConnectorId nodeConnectorIdNew, NodeConnectorId nodeConnectorIdOld,
98             FlowCapableNodeConnector fcNodeConnectorNew, String portName, boolean isNetworkEvent) {
99         boolean isNodePresent = InterfaceManagerCommonUtils.isNodePresent(dataBroker, nodeConnectorIdNew);
100         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
101         InterfaceStateRemoveWorker portStateRemoveWorker = new InterfaceStateRemoveWorker(idManager, nodeConnectorIdNew,
102                 nodeConnectorIdOld, fcNodeConnectorNew, portName, portName, isNodePresent, isNetworkEvent, true);
103         coordinator.enqueueJob(portName, portStateRemoveWorker, IfmConstants.JOB_MAX_RETRIES);
104     }
105
106     @Override
107     protected void update(InstanceIdentifier<FlowCapableNodeConnector> key, FlowCapableNodeConnector fcNodeConnectorOld,
108             FlowCapableNodeConnector fcNodeConnectorNew) {
109         IfmClusterUtils.runOnlyInLeaderNode(() -> {
110             LOG.debug("Received NodeConnector Update Event: {}, {}, {}", key, fcNodeConnectorOld, fcNodeConnectorNew);
111             NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
112                     .getId();
113             String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
114                     fcNodeConnectorNew.getName());
115             DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
116
117             InterfaceStateUpdateWorker portStateUpdateWorker = new InterfaceStateUpdateWorker(key, fcNodeConnectorOld,
118                     fcNodeConnectorNew, portName);
119             coordinator.enqueueJob(portName, portStateUpdateWorker, IfmConstants.JOB_MAX_RETRIES);
120         }, IfmClusterUtils.INTERFACE_CONFIG_ENTITY);
121     }
122
123     @Override
124     protected void add(InstanceIdentifier<FlowCapableNodeConnector> key, FlowCapableNodeConnector fcNodeConnectorNew) {
125         IfmClusterUtils.runOnlyInLeaderNode(() -> {
126             LOG.debug("Received NodeConnector Add Event: {}, {}", key, fcNodeConnectorNew);
127             NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
128                     .getId();
129             String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
130                     fcNodeConnectorNew.getName());
131
132             // VM Migration: Delete existing interface entry for older DPN
133             if (InterfaceManagerCommonUtils.isNovaPort(portName)) {
134                 NodeConnectorId nodeConnectorIdOld = IfmUtil.getNodeConnectorIdFromInterface(portName, dataBroker);
135                 if (nodeConnectorIdOld != null && !nodeConnectorId.equals(nodeConnectorIdOld)) {
136                     LOG.debug("Triggering NodeConnector Remove Event for the interface: {}, {}, {}", portName,
137                             nodeConnectorId, nodeConnectorIdOld);
138                     remove(nodeConnectorId, nodeConnectorIdOld, fcNodeConnectorNew, portName, false);
139                     // Adding a delay of 10sec for VM migration, so applications
140                     // can process remove and add events
141                     try {
142                         Thread.sleep(IfmConstants.DELAY_TIME_IN_MILLISECOND);
143                     } catch (InterruptedException e) {
144                         LOG.error("Error while waiting for the vm migration remove events to get processed");
145                     }
146                 }
147             }
148             DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
149             InterfaceStateAddWorker ifStateAddWorker = new InterfaceStateAddWorker(idManager, nodeConnectorId,
150                     fcNodeConnectorNew, portName);
151             coordinator.enqueueJob(portName, ifStateAddWorker, IfmConstants.JOB_MAX_RETRIES);
152         }, IfmClusterUtils.INTERFACE_CONFIG_ENTITY);
153     }
154
155
156     private class InterfaceStateAddWorker implements Callable {
157         private final NodeConnectorId nodeConnectorId;
158         private final FlowCapableNodeConnector fcNodeConnectorNew;
159         private final String interfaceName;
160         private final IdManagerService idManager;
161
162         InterfaceStateAddWorker(IdManagerService idManager, NodeConnectorId nodeConnectorId,
163                 FlowCapableNodeConnector fcNodeConnectorNew, String portName) {
164             this.nodeConnectorId = nodeConnectorId;
165             this.fcNodeConnectorNew = fcNodeConnectorNew;
166             this.interfaceName = portName;
167             this.idManager = idManager;
168         }
169
170         @Override
171         public Object call() {
172             // If another renderer(for eg : CSS) needs to be supported, check
173             // can be performed here
174             // to call the respective helpers.
175             List<ListenableFuture<Void>> futures = OvsInterfaceStateAddHelper.addState(dataBroker, idManager,
176                     mdsalApiManager, alivenessMonitorService, nodeConnectorId, interfaceName, fcNodeConnectorNew);
177             List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(dataBroker, interfaceName);
178             for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
179                 InterfaceStateAddWorker interfaceStateAddWorker = new InterfaceStateAddWorker(idManager,
180                         nodeConnectorId, fcNodeConnectorNew, interfaceChildEntry.getChildInterface());
181                 DataStoreJobCoordinator.getInstance().enqueueJob(interfaceName, interfaceStateAddWorker);
182             }
183             return futures;
184         }
185
186         @Override
187         public String toString() {
188             return "InterfaceStateAddWorker{" + "nodeConnectorId=" + nodeConnectorId + ", fcNodeConnectorNew="
189                     + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
190         }
191     }
192
193     private class InterfaceStateUpdateWorker implements Callable {
194         private final InstanceIdentifier<FlowCapableNodeConnector> key;
195         private final FlowCapableNodeConnector fcNodeConnectorOld;
196         private final FlowCapableNodeConnector fcNodeConnectorNew;
197         private final String interfaceName;
198
199         InterfaceStateUpdateWorker(InstanceIdentifier<FlowCapableNodeConnector> key,
200                 FlowCapableNodeConnector fcNodeConnectorOld, FlowCapableNodeConnector fcNodeConnectorNew,
201                 String portName) {
202             this.key = key;
203             this.fcNodeConnectorOld = fcNodeConnectorOld;
204             this.fcNodeConnectorNew = fcNodeConnectorNew;
205             this.interfaceName = portName;
206         }
207
208         @Override
209         public Object call() {
210             // If another renderer(for eg : CSS) needs to be supported, check
211             // can be performed here
212             // to call the respective helpers.
213             List<ListenableFuture<Void>> futures = OvsInterfaceStateUpdateHelper.updateState(key,
214                     alivenessMonitorService, dataBroker, interfaceName, fcNodeConnectorNew, fcNodeConnectorOld);
215             List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(dataBroker, interfaceName);
216             for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
217                 InterfaceStateUpdateWorker interfaceStateUpdateWorker = new InterfaceStateUpdateWorker(key,
218                         fcNodeConnectorOld, fcNodeConnectorNew, interfaceChildEntry.getChildInterface());
219                 DataStoreJobCoordinator.getInstance().enqueueJob(interfaceName, interfaceStateUpdateWorker);
220             }
221             return futures;
222         }
223
224         @Override
225         public String toString() {
226             return "InterfaceStateUpdateWorker{" + "key=" + key + ", fcNodeConnectorOld=" + fcNodeConnectorOld
227                     + ", fcNodeConnectorNew=" + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
228         }
229     }
230
231     private class InterfaceStateRemoveWorker implements Callable {
232         private final NodeConnectorId nodeConnectorIdNew;
233         private NodeConnectorId nodeConnectorIdOld;
234         FlowCapableNodeConnector fcNodeConnectorOld;
235         private final String interfaceName;
236         private final String parentInterface;
237         private final IdManagerService idManager;
238         private final boolean isNodePresent;
239         private final boolean isNetworkEvent;
240         private final boolean isParentInterface;
241
242         InterfaceStateRemoveWorker(IdManagerService idManager, NodeConnectorId nodeConnectorIdNew,
243                 NodeConnectorId nodeConnectorIdOld, FlowCapableNodeConnector fcNodeConnectorOld, String interfaceName,
244                 String parentInterface, boolean isNodePresent, boolean isNetworkEvent, boolean isParentInterface) {
245             this.nodeConnectorIdNew = nodeConnectorIdNew;
246             this.nodeConnectorIdOld = nodeConnectorIdOld;
247             this.fcNodeConnectorOld = fcNodeConnectorOld;
248             this.interfaceName = interfaceName;
249             this.parentInterface = parentInterface;
250             this.idManager = idManager;
251             this.isNodePresent = isNodePresent;
252             this.isNetworkEvent = isNetworkEvent;
253             this.isParentInterface = isParentInterface;
254         }
255
256         @Override
257         public Object call() {
258             // If another renderer(for eg : CSS) needs to be supported, check
259             // can be performed here
260             // to call the respective helpers.
261
262             List<ListenableFuture<Void>> futures = null;
263             // VM Migration: Skip OFPPR_DELETE event received after OFPPR_ADD
264             // for same interface from Older DPN
265             if (isParentInterface && isNetworkEvent) {
266                 nodeConnectorIdOld = IfmUtil.getNodeConnectorIdFromInterface(interfaceName, dataBroker);
267                 if (nodeConnectorIdOld != null && !nodeConnectorIdNew.equals(nodeConnectorIdOld)) {
268                     LOG.debug("Dropping the NodeConnector Remove Event for the interface: {}, {}, {}", interfaceName,
269                             nodeConnectorIdNew, nodeConnectorIdOld);
270                     return futures;
271                 }
272             }
273
274             futures = OvsInterfaceStateRemoveHelper.removeInterfaceStateConfiguration(idManager, mdsalApiManager,
275                     alivenessMonitorService, nodeConnectorIdNew, nodeConnectorIdOld, dataBroker, interfaceName,
276                     fcNodeConnectorOld, isNodePresent, parentInterface);
277
278             List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(dataBroker, interfaceName);
279             for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
280                 // Fetch all interfaces on this port and trigger remove worker
281                 // for each of them
282                 InterfaceStateRemoveWorker interfaceStateRemoveWorker = new InterfaceStateRemoveWorker(idManager,
283                         nodeConnectorIdNew, nodeConnectorIdOld, fcNodeConnectorOld,
284                         interfaceChildEntry.getChildInterface(), interfaceName, isNodePresent, isNetworkEvent, false);
285                 DataStoreJobCoordinator.getInstance().enqueueJob(interfaceName, interfaceStateRemoveWorker);
286             }
287             return futures;
288         }
289
290         @Override
291         public String toString() {
292             return "InterfaceStateRemoveWorker{" + "nodeConnectorIdNew=" + nodeConnectorIdNew + ", nodeConnectorIdOld="
293                     + nodeConnectorIdOld + ", fcNodeConnectorOld=" + fcNodeConnectorOld + ", interfaceName='"
294                     + interfaceName + '\'' + '}';
295         }
296     }
297
298     public static List<InterfaceChildEntry> getInterfaceChildEntries(DataBroker dataBroker, String interfaceName) {
299         InterfaceParentEntry interfaceParentEntry = InterfaceMetaUtils
300                 .getInterfaceParentEntryFromConfigDS(interfaceName, dataBroker);
301         if (interfaceParentEntry != null && interfaceParentEntry.getInterfaceChildEntry() != null) {
302             return interfaceParentEntry.getInterfaceChildEntry();
303         }
304         return new ArrayList<>();
305     }
306 }