Merge "Skeleton Event handlers for the Neutron integration with OVSDB. As per the...
[netvirt.git] / ovsdb / src / main / java / org / opendaylight / ovsdb / plugin / InventoryService.java
1 package org.opendaylight.ovsdb.plugin;
2
3 import java.util.Collection;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Map;
7 import java.util.Set;
8 import java.util.concurrent.ConcurrentHashMap;
9 import java.util.concurrent.ConcurrentMap;
10 import java.util.concurrent.CopyOnWriteArraySet;
11 import java.util.concurrent.Executors;
12 import java.util.concurrent.ScheduledExecutorService;
13 import java.util.concurrent.TimeUnit;
14
15 import org.opendaylight.controller.sal.core.ConstructionException;
16 import org.opendaylight.controller.sal.core.Description;
17 import org.opendaylight.controller.sal.core.Node;
18 import org.opendaylight.controller.sal.core.NodeConnector;
19 import org.opendaylight.controller.sal.core.Property;
20 import org.opendaylight.controller.sal.core.UpdateType;
21 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
22 import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
23 import org.opendaylight.controller.sal.utils.HexEncode;
24 import org.opendaylight.controller.sal.utils.ServiceHelper;
25 import org.opendaylight.ovsdb.lib.database.DatabaseSchema;
26 import org.opendaylight.ovsdb.lib.message.TableUpdate;
27 import org.opendaylight.ovsdb.lib.message.TableUpdate.Row;
28 import org.opendaylight.ovsdb.lib.message.TableUpdates;
29 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
30 import org.opendaylight.ovsdb.lib.table.Bridge;
31 import org.opendaylight.ovsdb.lib.table.internal.Table;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 import com.google.common.collect.Maps;
36
37 /**
38  * Stub Implementation for IPluginInReadService used by SAL
39  *
40  *
41  */
42 public class InventoryService implements IPluginInInventoryService, InventoryServiceInternal {
43     private static final Logger logger = LoggerFactory
44             .getLogger(InventoryService.class);
45     private final Set<IPluginOutInventoryService> pluginOutInventoryServices =
46             new CopyOnWriteArraySet<IPluginOutInventoryService>();
47     private ConcurrentMap<Node, Map<String, Property>> nodeProps;
48     private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps;
49     private Map<Node, NodeDB> dbCache = Maps.newHashMap();
50     private ScheduledExecutorService executor;
51
52     /**
53      * Function called by the dependency manager when all the required
54      * dependencies are satisfied
55      *
56      */
57     public void init() {
58         nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
59         nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
60         Node.NodeIDType.registerIDType("OVS", String.class);
61         NodeConnector.NodeConnectorIDType.registerIDType("OVS", String.class, "OVS");
62         this.executor = Executors.newSingleThreadScheduledExecutor();
63     }
64
65     /**
66      * Function called by the dependency manager when at least one dependency
67      * become unsatisfied or when the component is shutting down because for
68      * example bundle is being stopped.
69      *
70      */
71     public void destroy() {
72     }
73
74     /**
75      * Function called by dependency manager after "init ()" is called and after
76      * the services provided by the class are registered in the service registry
77      *
78      */
79     public void start() {
80     }
81
82     /**
83      * Function called by the dependency manager before the services exported by
84      * the component are unregistered, this will be followed by a "destroy ()"
85      * calls
86      *
87      */
88     public void stop() {
89         this.executor.shutdownNow();
90     }
91
92     public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
93         if (this.pluginOutInventoryServices != null) {
94             this.pluginOutInventoryServices.add(service);
95         }
96     }
97
98     public void unsetPluginOutInventoryServices(
99             IPluginOutInventoryService service) {
100         if (this.pluginOutInventoryServices != null) {
101             this.pluginOutInventoryServices.remove(service);
102         }
103     }
104
105     /**
106      * Retrieve nodes from openflow
107      */
108     @Override
109     public ConcurrentMap<Node, Map<String, Property>> getNodeProps() {
110         return nodeProps;
111     }
112
113     /**
114      * Retrieve nodeConnectors from openflow
115      */
116     @Override
117     public ConcurrentMap<NodeConnector, Map<String, Property>> getNodeConnectorProps(
118             Boolean refresh) {
119         return nodeConnectorProps;
120     }
121
122
123     @Override
124     public Map<String, Map<String, Table<?>>> getCache(Node n) {
125         NodeDB db = dbCache.get(n);
126         if (db == null) return null;
127         return db.getTableCache();
128     }
129
130
131     @Override
132     public Map<String, Table<?>> getTableCache(Node n, String tableName) {
133         NodeDB db = dbCache.get(n);
134         if (db == null) return null;
135         return db.getTableCache(tableName);
136     }
137
138
139     @Override
140     public Table<?> getRow(Node n, String tableName, String uuid) {
141         NodeDB db = dbCache.get(n);
142         if (db == null) return null;
143         return db.getRow(tableName, uuid);
144     }
145
146     @Override
147     public void updateRow(Node n, String tableName, String uuid, Table<?> row) {
148         NodeDB db = dbCache.get(n);
149         if (db == null) {
150             db = new NodeDB();
151             dbCache.put(n, db);
152         }
153         db.updateRow(tableName, uuid, row);
154     }
155
156     @Override
157     public void removeRow(Node n, String tableName, String uuid) {
158         NodeDB db = dbCache.get(n);
159         if (db != null) db.removeRow(tableName, uuid);
160     }
161
162     @Override
163     public void processTableUpdates(Node n, TableUpdates tableUpdates) {
164         NodeDB db = dbCache.get(n);
165         if (db == null) {
166             db = new NodeDB();
167             dbCache.put(n, db);
168         }
169
170         OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
171         Set<Table.Name> available = tableUpdates.availableUpdates();
172         for (Table.Name name : available) {
173             TableUpdate tableUpdate = tableUpdates.getUpdate(name);
174             Collection<TableUpdate.Row<?>> rows = tableUpdate.getRows();
175             for (Row<?> row : rows) {
176                 String uuid = row.getId();
177                 Table<?> newRow = (Table<?>)row.getNew();
178                 Table<?> oldRow = (Table<?>)row.getOld();
179                 if (newRow != null) {
180                     db.updateRow(name.getName(), uuid, newRow);
181                     if (name.getName().equalsIgnoreCase("bridge")) {
182                         logger.debug("Received Bridge Table udpate for node {}", n);
183                         // OVSDB has the Bridge name info while OpenFlow Spec is not
184                         // Clear on that. From a user/manageability standpoint, it is easier
185                         // to handle Bridge names compared to dpids.
186                         // Updating the Openflow bridge name via the SAL Description update.
187                         updateOFBridgeName(n, (Bridge)newRow);
188                     }
189                     if ((oldRow == null) && (inventoryListener != null)) {
190                         inventoryListener.rowAdded(n, name.getName(), newRow);
191                     }
192                 } else if (oldRow != null) {
193                     if (inventoryListener != null) {
194                         inventoryListener.rowRemoved(n, name.getName(), oldRow);
195                     }
196                     db.removeRow(name.getName(), uuid);
197                 }
198             }
199         }
200     }
201
202     private void updateOFBridgeName(final Node node, final Bridge bridge) {
203         Runnable updateNameRunnable = new Runnable() {
204             @Override
205             public void run() {
206                 OvsDBSet<String> dpids = bridge.getDatapath_id();
207                 String bridgeName = bridge.getName();
208                 if (dpids == null || bridgeName == null) return;
209                 for (String dpid : dpids) {
210                     Long dpidLong = Long.valueOf(HexEncode.stringToLong(dpid));
211                     try {
212                         Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
213                         Description descProp = new Description(bridgeName);
214                         Set<Property> props = new HashSet<Property>();
215                         props.add(descProp);
216
217                         IPluginOutInventoryService salInventoryService = (IPluginOutInventoryService) ServiceHelper.getInstance(
218                                 IPluginOutInventoryService.class, "default", this);
219                         if (salInventoryService != null) {
220                             logger.debug("Updating Bridge Name {} on OF node {}", bridgeName, ofNode);
221                             salInventoryService.updateNode(ofNode, UpdateType.CHANGED, props);
222                         } else {
223                             logger.error("Error accessing SAL Inventory plugin");
224                         }
225                     } catch (ConstructionException e) {
226                         e.printStackTrace();
227                     }
228                 }
229             }
230         };
231         executor.execute(updateNameRunnable);
232         // Add a delay & re-execute to compensate for the current OpenFlow plugin bug of
233         // overriding the Description with a Null value after the first statistics timer.
234         // Hopefully this will be resolved in the newer version of the Openflow plugin.
235         executor.schedule(updateNameRunnable, 30, TimeUnit.SECONDS);
236     }
237
238     @Override
239     public void printCache(Node n) {
240         NodeDB db = dbCache.get(n);
241         if (db != null) db.printTableCache();
242     }
243
244     @Override
245     public void addNode(Node node, Set<Property> props) {
246         addNodeProperty(node, UpdateType.ADDED, props);
247         OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
248         if (inventoryListener != null) {
249             inventoryListener.nodeAdded(node);
250         }
251     }
252
253     @Override
254     public void addNodeProperty(Node node, UpdateType type, Set<Property> props) {
255         Map<String, Property> nProp = nodeProps.get(node);
256         if (nProp == null) nProp = new HashMap<String, Property>();
257         for (Property prop : props) {
258             nProp.put(prop.getName(), prop);
259         }
260         nodeProps.put(node, nProp);
261         for (IPluginOutInventoryService service : pluginOutInventoryServices) {
262             service.updateNode(node, type, props);
263         }
264     }
265
266     @Override
267     public DatabaseSchema getDatabaseSchema(Node n) {
268         NodeDB db = dbCache.get(n);
269         if (db != null) return db.getSchema();
270         return null;
271     }
272
273     @Override
274     public void updateDatabaseSchema(Node n, DatabaseSchema schema) {
275         NodeDB db = dbCache.get(n);
276         if (db == null) {
277             db = new NodeDB();
278             dbCache.put(n, db);
279         }
280         db.setSchema(schema);
281     }
282
283     @Override
284     public void removeNode(Node node) {
285         OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
286         if (inventoryListener != null) {
287             inventoryListener.nodeRemoved(node);
288         }
289
290         for (IPluginOutInventoryService service : pluginOutInventoryServices) {
291             service.updateNode(node, UpdateType.REMOVED, null);
292         }
293         nodeProps.remove(node);
294         dbCache.remove(node);
295     }
296 }