2 * Copyright (c) 2019 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.ovsdb.southbound;
10 import java.util.Collection;
12 import java.util.concurrent.ConcurrentHashMap;
13 import java.util.concurrent.ConcurrentMap;
14 import java.util.concurrent.ScheduledFuture;
15 import java.util.concurrent.TimeUnit;
16 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
17 import org.opendaylight.mdsal.binding.api.DataBroker;
18 import org.opendaylight.mdsal.binding.api.DataObjectModification;
19 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
20 import org.opendaylight.mdsal.binding.api.DataTreeModification;
21 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
22 import org.opendaylight.ovsdb.southbound.transactions.md.TransactionInvoker;
23 import org.opendaylight.ovsdb.utils.mdsal.utils.Scheduler;
24 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
25 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
26 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
27 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
28 import org.opendaylight.yangtools.concepts.ListenerRegistration;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
33 public class OvsdbOperGlobalListener implements ClusteredDataTreeChangeListener<Node>, AutoCloseable {
34 public static final ConcurrentMap<InstanceIdentifier<Node>, Node> OPER_NODE_CACHE = new ConcurrentHashMap<>();
36 private static final Logger LOG = LoggerFactory.getLogger(OvsdbOperGlobalListener.class);
38 private ListenerRegistration<OvsdbOperGlobalListener> registration;
39 private DataBroker db;
40 private final OvsdbConnectionManager ovsdbConnectionManager;
41 private final TransactionInvoker txInvoker;
43 OvsdbOperGlobalListener(DataBroker db, OvsdbConnectionManager ovsdbConnectionManager,
44 TransactionInvoker txInvoker) {
45 LOG.info("Registering OvsdbOperGlobalListener");
47 this.ovsdbConnectionManager = ovsdbConnectionManager;
48 this.txInvoker = txInvoker;
52 public void registerListener() {
53 DataTreeIdentifier<Node> treeId =
54 DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, getWildcardPath());
55 registration = db.registerDataTreeChangeListener(treeId, this);
60 if (registration != null) {
62 LOG.info("OVSDB Oper Node listener has been closed.");
67 @SuppressWarnings("checkstyle:IllegalCatch")
68 public void onDataTreeChanged(Collection<DataTreeModification<Node>> changes) {
69 changes.forEach((change) -> {
71 InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
72 DataObjectModification<Node> mod = change.getRootNode();
73 Node addNode = getCreated(mod);
74 if (addNode != null) {
75 OPER_NODE_CACHE.put(key, addNode);
76 LOG.info("Node added to oper {}", SouthboundUtil.getOvsdbNodeId(key));
78 Node removedNode = getRemoved(mod);
79 if (removedNode != null) {
80 OPER_NODE_CACHE.remove(key);
81 LOG.info("Node deleted from oper {}", SouthboundUtil.getOvsdbNodeId(key));
83 OvsdbConnectionInstance connectionInstance = ovsdbConnectionManager.getConnectionInstance(key);
84 if (connectionInstance != null && connectionInstance.isActive()
85 && connectionInstance.getHasDeviceOwnership() != null
86 && connectionInstance.getHasDeviceOwnership()) {
87 //Oops some one deleted the node held by me This should never happen.
88 //put the node back in oper
89 txInvoker.invoke(transaction -> {
90 transaction.put(LogicalDatastoreType.OPERATIONAL, key, removedNode);
96 Node modifiedNode = getUpdated(mod);
97 if (modifiedNode != null) {
98 OPER_NODE_CACHE.put(key, modifiedNode);
100 } catch (Exception e) {
101 LOG.error("Failed to handle oper node ", e);
106 private static final Map<InstanceIdentifier<Node>, ScheduledFuture> TIMEOUT_FTS = new ConcurrentHashMap<>();
108 public static void runAfterTimeoutIfNodeNotCreated(InstanceIdentifier<Node> iid, Runnable job) {
109 ScheduledFuture<?> ft = TIMEOUT_FTS.get(iid);
113 ft = Scheduler.getScheduledExecutorService().schedule(() -> {
114 TIMEOUT_FTS.remove(iid);
115 if (!OPER_NODE_CACHE.containsKey(iid)) {
118 }, SouthboundConstants.EOS_TIMEOUT, TimeUnit.SECONDS);
119 TIMEOUT_FTS.put(iid, ft);
122 private Node getCreated(DataObjectModification<Node> mod) {
123 if ((mod.getModificationType() == DataObjectModification.ModificationType.WRITE)
124 && (mod.getDataBefore() == null)) {
125 return mod.getDataAfter();
130 private Node getRemoved(DataObjectModification<Node> mod) {
131 if (mod.getModificationType() == DataObjectModification.ModificationType.DELETE) {
132 return mod.getDataBefore();
137 private Node getUpdated(DataObjectModification<Node> mod) {
139 switch (mod.getModificationType()) {
140 case SUBTREE_MODIFIED:
141 node = mod.getDataAfter();
144 if (mod.getDataBefore() != null) {
145 node = mod.getDataAfter();
154 private InstanceIdentifier<Node> getWildcardPath() {
155 InstanceIdentifier<Node> path = InstanceIdentifier
156 .create(NetworkTopology.class)
157 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))