2 * Copyright (C) 2013 Red Hat, Inc.
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 * Authors : Madhu Venugopal, Brent Salisbury
10 package org.opendaylight.ovsdb.plugin;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.HashSet;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.ConcurrentMap;
20 import java.util.concurrent.CopyOnWriteArraySet;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.ScheduledExecutorService;
23 import java.util.concurrent.TimeUnit;
25 import org.opendaylight.controller.sal.core.ConstructionException;
26 import org.opendaylight.controller.sal.core.Description;
27 import org.opendaylight.controller.sal.core.Node;
28 import org.opendaylight.controller.sal.core.NodeConnector;
29 import org.opendaylight.controller.sal.core.Property;
30 import org.opendaylight.controller.sal.core.UpdateType;
31 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
32 import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
33 import org.opendaylight.controller.sal.utils.HexEncode;
34 import org.opendaylight.controller.sal.utils.ServiceHelper;
35 import org.opendaylight.ovsdb.lib.database.DatabaseSchema;
36 import org.opendaylight.ovsdb.lib.message.TableUpdate;
37 import org.opendaylight.ovsdb.lib.message.TableUpdate.Row;
38 import org.opendaylight.ovsdb.lib.message.TableUpdates;
39 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
40 import org.opendaylight.ovsdb.lib.table.Bridge;
41 import org.opendaylight.ovsdb.lib.table.Table;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
45 import com.google.common.collect.Maps;
48 * Stub Implementation for IPluginInReadService used by SAL
52 public class InventoryService implements IPluginInInventoryService, InventoryServiceInternal {
53 private static final Logger logger = LoggerFactory
54 .getLogger(InventoryService.class);
55 private final Set<IPluginOutInventoryService> pluginOutInventoryServices =
56 new CopyOnWriteArraySet<IPluginOutInventoryService>();
57 private ConcurrentMap<Node, Map<String, Property>> nodeProps;
58 private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps;
59 private ConcurrentMap<Node, NodeDB> dbCache = Maps.newConcurrentMap();
60 private ScheduledExecutorService executor;
63 * Function called by the dependency manager when all the required
64 * dependencies are satisfied
68 nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
69 nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
70 Node.NodeIDType.registerIDType("OVS", String.class);
71 NodeConnector.NodeConnectorIDType.registerIDType("OVS", String.class, "OVS");
72 this.executor = Executors.newSingleThreadScheduledExecutor();
76 * Function called by the dependency manager when at least one dependency
77 * become unsatisfied or when the component is shutting down because for
78 * example bundle is being stopped.
81 public void destroy() {
85 * Function called by dependency manager after "init ()" is called and after
86 * the services provided by the class are registered in the service registry
93 * Function called by the dependency manager before the services exported by
94 * the component are unregistered, this will be followed by a "destroy ()"
99 this.executor.shutdownNow();
102 public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
103 this.pluginOutInventoryServices.add(service);
106 public void unsetPluginOutInventoryServices(IPluginOutInventoryService service) {
107 this.pluginOutInventoryServices.remove(service);
111 * Retrieve nodes from openflow
114 public ConcurrentMap<Node, Map<String, Property>> getNodeProps() {
119 * Retrieve nodeConnectors from openflow
122 public ConcurrentMap<NodeConnector, Map<String, Property>> getNodeConnectorProps(
124 return nodeConnectorProps;
129 public ConcurrentMap<String, ConcurrentMap<String, Table<?>>> getCache(Node n) {
130 NodeDB db = dbCache.get(n);
131 if (db == null) return null;
132 return db.getTableCache();
137 public ConcurrentMap<String, Table<?>> getTableCache(Node n, String tableName) {
138 NodeDB db = dbCache.get(n);
139 if (db == null) return null;
140 return db.getTableCache(tableName);
145 public Table<?> getRow(Node n, String tableName, String uuid) {
146 NodeDB db = dbCache.get(n);
147 if (db == null) return null;
148 return db.getRow(tableName, uuid);
152 public void updateRow(Node n, String tableName, String uuid, Table<?> row) {
153 NodeDB db = dbCache.get(n);
158 db.updateRow(tableName, uuid, row);
162 public void removeRow(Node n, String tableName, String uuid) {
163 NodeDB db = dbCache.get(n);
164 if (db != null) db.removeRow(tableName, uuid);
168 public void processTableUpdates(Node n, TableUpdates tableUpdates) {
169 NodeDB db = dbCache.get(n);
175 OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
176 Set<Table.Name> available = tableUpdates.availableUpdates();
177 for (Table.Name name : available) {
178 TableUpdate tableUpdate = tableUpdates.getUpdate(name);
179 Collection<TableUpdate.Row<?>> rows = tableUpdate.getRows();
180 for (Row<?> row : rows) {
181 String uuid = row.getId();
182 Table<?> newRow = (Table<?>)row.getNew();
183 Table<?> oldRow = (Table<?>)row.getOld();
184 if (newRow != null) {
185 db.updateRow(name.getName(), uuid, newRow);
186 if (name.getName().equalsIgnoreCase("bridge")) {
187 logger.debug("Received Bridge Table udpate for node {}", n);
188 // OVSDB has the Bridge name info while OpenFlow Spec is not
189 // Clear on that. From a user/manageability standpoint, it is easier
190 // to handle Bridge names compared to dpids.
191 // Updating the Openflow bridge name via the SAL Description update.
193 // updateOFBridgeName(n, (Bridge)newRow);
195 if ((oldRow == null) && (inventoryListener != null)) {
196 inventoryListener.rowAdded(n, name.getName(), uuid, newRow);
197 } else if (inventoryListener != null) {
198 inventoryListener.rowUpdated(n, name.getName(), uuid, oldRow, newRow);
200 } else if (oldRow != null) {
201 if (inventoryListener != null) {
202 inventoryListener.rowRemoved(n, name.getName(), uuid, oldRow);
204 db.removeRow(name.getName(), uuid);
210 private void updateOFBridgeName(final Node node, final Bridge bridge) {
211 Runnable updateNameRunnable = new Runnable() {
214 OvsDBSet<String> dpids = bridge.getDatapath_id();
215 String bridgeName = bridge.getName();
216 if (dpids == null || bridgeName == null) return;
217 for (String dpid : dpids) {
218 Long dpidLong = Long.valueOf(HexEncode.stringToLong(dpid));
220 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
221 Description descProp = new Description(bridgeName);
222 Set<Property> props = new HashSet<Property>();
225 IPluginOutInventoryService salInventoryService = (IPluginOutInventoryService) ServiceHelper.getInstance(
226 IPluginOutInventoryService.class, "default", this);
227 if (salInventoryService != null) {
228 logger.debug("Updating Bridge Name {} on OF node {}", bridgeName, ofNode);
229 salInventoryService.updateNode(ofNode, UpdateType.CHANGED, props);
231 logger.error("Error accessing SAL Inventory plugin");
233 } catch (ConstructionException e) {
234 logger.error("Failed to construct node for " + dpid, e);
239 executor.execute(updateNameRunnable);
240 // Add a delay & re-execute to compensate for the current OpenFlow plugin bug of
241 // overriding the Description with a Null value after the first statistics timer.
242 // Hopefully this will be resolved in the newer version of the Openflow plugin.
243 executor.schedule(updateNameRunnable, 30, TimeUnit.SECONDS);
247 public void printCache(Node n) {
248 NodeDB db = dbCache.get(n);
249 if (db != null) db.printTableCache();
253 public void addNode(Node node, Set<Property> props) {
254 addNodeProperty(node, UpdateType.ADDED, props);
258 public void notifyNodeAdded(Node node) {
259 OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
260 if (inventoryListener != null) {
261 inventoryListener.nodeAdded(node);
266 public void addNodeProperty(Node node, UpdateType type, Set<Property> props) {
267 Map<String, Property> nProp = nodeProps.get(node);
268 if (nProp == null) nProp = new HashMap<String, Property>();
269 for (Property prop : props) {
270 nProp.put(prop.getName(), prop);
272 nodeProps.put(node, nProp);
273 for (IPluginOutInventoryService service : pluginOutInventoryServices) {
274 service.updateNode(node, type, props);
279 public DatabaseSchema getDatabaseSchema(Node n) {
280 NodeDB db = dbCache.get(n);
281 if (db != null) return db.getSchema();
286 public void updateDatabaseSchema(Node n, DatabaseSchema schema) {
287 NodeDB db = dbCache.get(n);
292 db.setSchema(schema);
296 public void removeNode(Node node) {
297 OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
298 if (inventoryListener != null) {
299 inventoryListener.nodeRemoved(node);
302 for (IPluginOutInventoryService service : pluginOutInventoryServices) {
303 service.updateNode(node, UpdateType.REMOVED, null);
305 nodeProps.remove(node);
306 dbCache.remove(node);
310 public Set<Node> getConfiguredNotConnectedNodes() {
311 return Collections.emptySet();