Add support for openflow node callbacks
[ovsdb.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / providers / openflow13 / FlowCapableNodeDataChangeListener.java
1 /*
2  * Copyright (C) 2015 Red Hat, Inc.
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  * Authors : Sam Hague
9  */
10 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
11
12 import com.google.common.collect.Lists;
13 import java.util.List;
14 import java.util.Map;
15
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
18 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
22 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
23 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
24 import org.opendaylight.ovsdb.utils.mdsal.node.NodeUtils;
25 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
30 import org.opendaylight.yangtools.concepts.ListenerRegistration;
31 import org.opendaylight.yangtools.yang.binding.DataObject;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 public class FlowCapableNodeDataChangeListener implements DataChangeListener, AutoCloseable {
37     private static final Logger LOG = LoggerFactory.getLogger(FlowCapableNodeDataChangeListener.class);
38     private ListenerRegistration<DataChangeListener> registration;
39     private final Object nodeCacheLock = new Object();
40     private List<Node> nodeCache = Lists.newArrayList();
41     private PipelineOrchestrator pipelineOrchestrator = null;
42     private NodeCacheManager nodeCacheManager = null;
43
44     public static final InstanceIdentifier<FlowCapableNode> createFlowCapableNodePath () {
45         return InstanceIdentifier.builder(Nodes.class)
46                 .child(Node.class)
47                 .augmentation(FlowCapableNode.class)
48                 .build();
49     }
50
51     public FlowCapableNodeDataChangeListener (DataBroker dataBroker) {
52         LOG.info("Registering FlowCapableNodeChangeListener");
53         registration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
54                 createFlowCapableNodePath(), this, AsyncDataBroker.DataChangeScope.BASE);
55     }
56
57     @Override
58     public void close () throws Exception {
59         registration.close();
60     }
61
62     @Override
63     public void onDataChanged (AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
64         LOG.debug(">>>> onDataChanged: {}", changes);
65         checkMemberInitialization();
66
67         for (InstanceIdentifier instanceIdentifier : changes.getRemovedPaths()) {
68             DataObject originalDataObject = changes.getOriginalData().get(instanceIdentifier);
69             if (originalDataObject instanceof Node) {
70                 Node node = (Node) originalDataObject;
71                 String openflowId = node.getId().getValue();
72                 LOG.info(">>>>> removed iiD: {} - NodeKey: {}", instanceIdentifier, openflowId);
73                 Node openFlowNode = NodeUtils.getOpenFlowNode(openflowId);
74                 if (removeNodeFromCache(openFlowNode)) {
75                     notifyNodeRemoved(openFlowNode);
76                 }
77             }
78         }
79
80         for (Map.Entry<InstanceIdentifier<?>, DataObject> created : changes.getCreatedData().entrySet()) {
81             InstanceIdentifier<?> iID = created.getKey();
82             String openflowId = iID.firstKeyOf(Node.class, NodeKey.class).getId().getValue();
83             LOG.info(">>>>> created iiD: {} - first: {} - NodeKey: {}",
84                     iID, iID.firstIdentifierOf(Node.class), openflowId);
85             Node openFlowNode = NodeUtils.getOpenFlowNode(openflowId);
86             if (addNodeToCache(openFlowNode)) {
87                 notifyNodeCreated(openFlowNode);
88             } else {
89                 notifyNodeUpdated(openFlowNode);
90             }
91         }
92
93         for (Map.Entry<InstanceIdentifier<?>, DataObject> updated : changes.getUpdatedData().entrySet()) {
94             InstanceIdentifier<?> iID = updated.getKey();
95             String openflowId = iID.firstKeyOf(Node.class, NodeKey.class).getId().getValue();
96             LOG.info(">>>>> updated iiD: {} - first: {} - NodeKey: {}",
97                     iID, iID.firstIdentifierOf(Node.class), openflowId);
98             Node openFlowNode = NodeUtils.getOpenFlowNode(openflowId);
99             if (addNodeToCache(openFlowNode)) {
100                 notifyNodeCreated(openFlowNode);
101             } else {
102                 notifyNodeUpdated(openFlowNode);
103             }
104         }
105     }
106
107     public void notifyFlowCapableNodeEvent (String openFlowId, Action action) {
108         LOG.debug("Notification of flow capable node {}, action {}", openFlowId, action);
109         checkMemberInitialization();
110
111         Node openFlowNode = NodeUtils.getOpenFlowNode(openFlowId);
112         if (action == Action.DELETE) {
113             notifyNodeRemoved(openFlowNode);
114         } else {
115             if (addNodeToCache(openFlowNode)) {
116                 notifyNodeCreated(openFlowNode);
117             } else {
118                 notifyNodeUpdated(openFlowNode);
119             }
120         }
121     }
122
123     /**
124      * This method returns the true if node was added to the nodeCache. If param node
125      * is already in the cache, this method is expected to return false.
126      *
127      * @param openFlowNode the node to be added to the cache, if needed
128      * @return whether new node entry was added to cache
129      */
130     private Boolean addNodeToCache (Node openFlowNode) {
131         synchronized (nodeCacheLock) {
132             if (nodeCache.contains(openFlowNode)) {
133                 return false;
134             }
135             return nodeCache.add(openFlowNode);
136         }
137     }
138
139     /**
140      * This method returns the true if node was removed from the nodeCache. If param node
141      * is not in the cache, this method is expected to return false.
142      *
143      * @param openFlowNode the node to be removed from the cache, if needed
144      * @return whether new node entry was removed from cache
145      */
146     private Boolean removeNodeFromCache (Node openFlowNode) {
147         synchronized (nodeCacheLock) {
148             return nodeCache.remove(openFlowNode);
149         }
150     }
151
152     private void notifyNodeUpdated (Node openFlowNode) {
153         final String openflowId = openFlowNode.getId().getValue();
154         LOG.debug("notifyNodeUpdated: Node {} from Controller's inventory Service", openflowId);
155
156         // TODO: will do something amazing here, someday
157     }
158
159     private void notifyNodeCreated (Node openFlowNode) {
160         final String openflowId = openFlowNode.getId().getValue();
161         LOG.info("notifyNodeCreated: Node {} from Controller's inventory Service", openflowId);
162
163         if (pipelineOrchestrator != null) {
164             //pipelineOrchestrator.enqueue(openflowId);
165         }
166         if (nodeCacheManager != null) {
167             //nodeCacheManager.nodeAdded(openflowId);
168         }
169     }
170
171     private void notifyNodeRemoved (Node openFlowNode) {
172         LOG.info("notifyNodeRemoved: Node {} from Controller's inventory Service",
173                 openFlowNode.getId().getValue());
174
175         if (nodeCacheManager != null) {
176             //nodeCacheManager.nodeRemoved(openFlowNode);
177         }
178     }
179
180     private void checkMemberInitialization () {
181         /**
182          * Obtain local ref to members, if needed. Having these local saves us from calling getGlobalInstance
183          * upon every event.
184          */
185         if (pipelineOrchestrator == null) {
186             pipelineOrchestrator =
187                     (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
188         }
189         if (nodeCacheManager == null) {
190             nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
191         }
192     }
193 }