2 * Copyright (c) 2016, 2017 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.genius.interfacemanager.listeners;
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;
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
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.
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;
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);
95 protected InstanceIdentifier<FlowCapableNodeConnector> getWildCardPath() {
96 return InstanceIdentifier.create(Nodes.class).child(Node.class).child(NodeConnector.class)
97 .augmentation(FlowCapableNodeConnector.class);
101 protected InterfaceInventoryStateListener getDataTreeChangeListener() {
102 return InterfaceInventoryStateListener.this;
106 protected void remove(InstanceIdentifier<FlowCapableNodeConnector> key,
107 FlowCapableNodeConnector flowCapableNodeConnectorOld) {
108 if (!entityOwnershipUtils.isEntityOwner(IfmConstants.INTERFACE_CONFIG_ENTITY,
109 IfmConstants.INTERFACE_CONFIG_ENTITY)) {
113 LOG.debug("Received NodeConnector Remove Event: {}, {}", key, flowCapableNodeConnectorOld);
114 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
116 String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
117 flowCapableNodeConnectorOld.getName());
119 remove(nodeConnectorId, null, flowCapableNodeConnectorOld, portName, true);
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);
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)) {
138 LOG.debug("Received NodeConnector Update Event: {}, {}, {}", key, fcNodeConnectorOld, fcNodeConnectorNew);
139 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
141 String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
142 fcNodeConnectorNew.getName());
144 InterfaceStateUpdateWorker portStateUpdateWorker = new InterfaceStateUpdateWorker(key, fcNodeConnectorOld,
145 fcNodeConnectorNew, portName);
146 coordinator.enqueueJob(portName, portStateUpdateWorker, IfmConstants.JOB_MAX_RETRIES);
150 protected void add(InstanceIdentifier<FlowCapableNodeConnector> key, FlowCapableNodeConnector fcNodeConnectorNew) {
151 if (!entityOwnershipUtils.isEntityOwner(IfmConstants.INTERFACE_CONFIG_ENTITY,
152 IfmConstants.INTERFACE_CONFIG_ENTITY)) {
156 LOG.debug("Received NodeConnector Add Event: {}, {}", key, fcNodeConnectorNew);
157 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
159 String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
160 fcNodeConnectorNew.getName());
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);
175 LOG.warn("Port number update detected for {}", fcNodeConnectorNew.getName());
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
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");
191 InterfaceStateAddWorker ifStateAddWorker = new InterfaceStateAddWorker(idManager, nodeConnectorId,
192 fcNodeConnectorNew, portName);
193 coordinator.enqueueJob(portName, ifStateAddWorker, IfmConstants.JOB_MAX_RETRIES);
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;
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;
212 public Object call() {
213 List<ListenableFuture<Void>> futures = ovsInterfaceStateAddHelper.addState(nodeConnectorId, interfaceName,
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);
225 public String toString() {
226 return "InterfaceStateAddWorker{" + "nodeConnectorId=" + nodeConnectorId + ", fcNodeConnectorNew="
227 + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
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;
237 InterfaceStateUpdateWorker(InstanceIdentifier<FlowCapableNodeConnector> key,
238 FlowCapableNodeConnector fcNodeConnectorOld, FlowCapableNodeConnector fcNodeConnectorNew,
241 this.fcNodeConnectorOld = fcNodeConnectorOld;
242 this.fcNodeConnectorNew = fcNodeConnectorNew;
243 this.interfaceName = portName;
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);
260 public String toString() {
261 return "InterfaceStateUpdateWorker{" + "key=" + key + ", fcNodeConnectorOld=" + fcNodeConnectorOld
262 + ", fcNodeConnectorNew=" + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
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;
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;
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);
304 futures = removeInterfaceStateConfiguration();
306 List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(interfaceName);
307 for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
308 // Fetch all interfaces on this port and trigger remove worker
310 InterfaceStateRemoveWorker interfaceStateRemoveWorker = new InterfaceStateRemoveWorker(idManager,
311 nodeConnectorIdNew, nodeConnectorIdOld, fcNodeConnectorOld,
312 interfaceChildEntry.getChildInterface(), isNodePresent, isNetworkEvent, false);
313 coordinator.enqueueJob(interfaceName, interfaceStateRemoveWorker);
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();
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);
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);
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);
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,
345 handleTunnelMonitoringRemoval(dpId, iface.getName(), iface.getAugmentation(IfTunnel.class),
346 defaultOperationalShardTransaction, futures);
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);
356 // Delete the Vpn Interface from DpnToInterface Op DS.
357 interfaceManagerCommonUtils.deleteDpnToInterface(dpId, interfaceName,
358 defaultOperationalShardTransaction);
360 futures.add(defaultOperationalShardTransaction.submit());
364 private void handleTunnelMonitoringRemoval(BigInteger dpId, String removedInterfaceName,
365 IfTunnel ifTunnel, WriteTransaction transaction, List<ListenableFuture<Void>> futures) {
366 interfaceManagerCommonUtils.removeTunnelIngressFlow(ifTunnel, dpId, removedInterfaceName);
368 IfmUtil.unbindService(dataBroker, coordinator, removedInterfaceName,
369 FlowBasedServicesUtils.buildDefaultServiceId(removedInterfaceName));
371 futures.add(transaction.submit());
372 alivenessMonitorUtils.stopLLDPMonitoring(ifTunnel, removedInterfaceName);
376 public String toString() {
377 return "InterfaceStateRemoveWorker{" + "nodeConnectorIdNew=" + nodeConnectorIdNew + ", nodeConnectorIdOld="
378 + nodeConnectorIdOld + ", fcNodeConnectorOld=" + fcNodeConnectorOld + ", interfaceName='"
379 + interfaceName + '\'' + '}';
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();
389 return new ArrayList<>();