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, 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)) {
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 String parentInterface;
272 private final IdManagerService idManager;
273 private final boolean isNodePresent;
274 private final boolean isNetworkEvent;
275 private final boolean isParentInterface;
277 InterfaceStateRemoveWorker(IdManagerService idManager, NodeConnectorId nodeConnectorIdNew,
278 NodeConnectorId nodeConnectorIdOld, FlowCapableNodeConnector fcNodeConnectorOld, String interfaceName,
279 String parentInterface, boolean isNodePresent, boolean isNetworkEvent, boolean isParentInterface) {
280 this.nodeConnectorIdNew = nodeConnectorIdNew;
281 this.nodeConnectorIdOld = nodeConnectorIdOld;
282 this.fcNodeConnectorOld = fcNodeConnectorOld;
283 this.interfaceName = interfaceName;
284 this.parentInterface = parentInterface;
285 this.idManager = idManager;
286 this.isNodePresent = isNodePresent;
287 this.isNetworkEvent = isNetworkEvent;
288 this.isParentInterface = isParentInterface;
292 public Object call() {
293 List<ListenableFuture<Void>> futures = null;
294 // VM Migration: Skip OFPPR_DELETE event received after OFPPR_ADD
295 // for same interface from Older DPN
296 if (isParentInterface && isNetworkEvent) {
297 nodeConnectorIdOld = FlowBasedServicesUtils.getNodeConnectorIdFromInterface(interfaceName,
298 interfaceManagerCommonUtils);
299 if (nodeConnectorIdOld != null && !nodeConnectorIdNew.equals(nodeConnectorIdOld)) {
300 LOG.debug("Dropping the NodeConnector Remove Event for the interface: {}, {}, {}", interfaceName,
301 nodeConnectorIdNew, nodeConnectorIdOld);
306 futures = removeInterfaceStateConfiguration(nodeConnectorIdNew, nodeConnectorIdOld, interfaceName,
307 fcNodeConnectorOld, isNodePresent);
309 List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(interfaceName);
310 for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
311 // Fetch all interfaces on this port and trigger remove worker
313 InterfaceStateRemoveWorker interfaceStateRemoveWorker = new InterfaceStateRemoveWorker(idManager,
314 nodeConnectorIdNew, nodeConnectorIdOld, fcNodeConnectorOld,
315 interfaceChildEntry.getChildInterface(), interfaceName, isNodePresent, isNetworkEvent, false);
316 coordinator.enqueueJob(interfaceName, interfaceStateRemoveWorker);
321 private List<ListenableFuture<Void>> removeInterfaceStateConfiguration(NodeConnectorId nodeConnectorIdNew,
322 NodeConnectorId nodeConnectorIdOld, String interfaceName, FlowCapableNodeConnector fcNodeConnectorOld,
323 boolean isNodePresent) {
324 LOG.debug("Removing interface state information for interface: {} {}", interfaceName, isNodePresent);
325 List<ListenableFuture<Void>> futures = new ArrayList<>();
326 WriteTransaction defaultOperationalShardTransaction = dataBroker.newWriteOnlyTransaction();
328 //VM Migration: Use old nodeConnectorId to delete the interface entry
329 NodeConnectorId nodeConnectorId = nodeConnectorIdOld != null
330 && !nodeConnectorIdNew.equals(nodeConnectorIdOld) ? nodeConnectorIdOld : nodeConnectorIdNew;
331 // delete the port entry from interface operational DS
332 BigInteger dpId = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
334 //VM Migration: Update the interface state to unknown only if remove event received for same switch
335 if (!isNodePresent && nodeConnectorIdNew.equals(nodeConnectorIdOld)) {
336 //Remove event is because of connection lost between controller and switch, or switch shutdown.
337 // Hence, don't remove the interface but set the status as "unknown"
338 ovsInterfaceStateUpdateHelper.updateInterfaceStateOnNodeRemove(interfaceName, fcNodeConnectorOld,
339 defaultOperationalShardTransaction);
341 InterfaceManagerCommonUtils.deleteStateEntry(interfaceName, defaultOperationalShardTransaction);
342 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
343 .Interface iface = interfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName);
346 // If this interface is a tunnel interface, remove the tunnel ingress flow and stop LLDP monitoring
347 if (InterfaceManagerCommonUtils.isTunnelInterface(iface)) {
348 interfaceMetaUtils.removeLportTagInterfaceMap(defaultOperationalShardTransaction,
350 handleTunnelMonitoringRemoval(dpId, iface.getName(), iface.getAugmentation(IfTunnel.class),
351 defaultOperationalShardTransaction, futures);
355 // remove ingress flow only for northbound configured interfaces
356 // skip this check for non-unique ports(Ex: br-int,br-ex)
357 if (iface != null || iface == null && !interfaceName.contains(fcNodeConnectorOld.getName())) {
358 FlowBasedServicesUtils.removeIngressFlow(interfaceName, dpId, dataBroker, futures);
361 // Delete the Vpn Interface from DpnToInterface Op DS.
362 interfaceManagerCommonUtils.deleteDpnToInterface(dpId, interfaceName,
363 defaultOperationalShardTransaction);
365 futures.add(defaultOperationalShardTransaction.submit());
369 private void handleTunnelMonitoringRemoval(BigInteger dpId, String interfaceName,
370 IfTunnel ifTunnel, WriteTransaction transaction, List<ListenableFuture<Void>> futures) {
371 interfaceManagerCommonUtils.removeTunnelIngressFlow(ifTunnel, dpId, interfaceName);
373 IfmUtil.unbindService(dataBroker, coordinator, interfaceName,
374 FlowBasedServicesUtils.buildDefaultServiceId(interfaceName));
376 futures.add(transaction.submit());
377 alivenessMonitorUtils.stopLLDPMonitoring(ifTunnel, interfaceName);
381 public String toString() {
382 return "InterfaceStateRemoveWorker{" + "nodeConnectorIdNew=" + nodeConnectorIdNew + ", nodeConnectorIdOld="
383 + nodeConnectorIdOld + ", fcNodeConnectorOld=" + fcNodeConnectorOld + ", interfaceName='"
384 + interfaceName + '\'' + '}';
388 public List<InterfaceChildEntry> getInterfaceChildEntries(String interfaceName) {
389 InterfaceParentEntry interfaceParentEntry =
390 interfaceMetaUtils.getInterfaceParentEntryFromConfigDS(interfaceName);
391 if (interfaceParentEntry != null && interfaceParentEntry.getInterfaceChildEntry() != null) {
392 return interfaceParentEntry.getInterfaceChildEntry();
394 return new ArrayList<>();