1 package org.opendaylight.ovsdb.plugin;
3 import java.util.Collection;
4 import java.util.HashMap;
5 import java.util.HashSet;
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;
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;
35 import com.google.common.collect.Maps;
38 * Stub Implementation for IPluginInReadService used by SAL
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;
53 * Function called by the dependency manager when all the required
54 * dependencies are satisfied
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();
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.
71 public void destroy() {
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
83 * Function called by the dependency manager before the services exported by
84 * the component are unregistered, this will be followed by a "destroy ()"
89 this.executor.shutdownNow();
92 public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
93 if (this.pluginOutInventoryServices != null) {
94 this.pluginOutInventoryServices.add(service);
98 public void unsetPluginOutInventoryServices(
99 IPluginOutInventoryService service) {
100 if (this.pluginOutInventoryServices != null) {
101 this.pluginOutInventoryServices.remove(service);
106 * Retrieve nodes from openflow
109 public ConcurrentMap<Node, Map<String, Property>> getNodeProps() {
114 * Retrieve nodeConnectors from openflow
117 public ConcurrentMap<NodeConnector, Map<String, Property>> getNodeConnectorProps(
119 return nodeConnectorProps;
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();
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);
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);
147 public void updateRow(Node n, String tableName, String uuid, Table<?> row) {
148 NodeDB db = dbCache.get(n);
153 db.updateRow(tableName, uuid, row);
157 public void removeRow(Node n, String tableName, String uuid) {
158 NodeDB db = dbCache.get(n);
159 if (db != null) db.removeRow(tableName, uuid);
163 public void processTableUpdates(Node n, TableUpdates tableUpdates) {
164 NodeDB db = dbCache.get(n);
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);
189 if ((oldRow == null) && (inventoryListener != null)) {
190 inventoryListener.rowAdded(n, name.getName(), uuid, newRow);
191 } else if (inventoryListener != null) {
192 inventoryListener.rowUpdated(n, name.getName(), uuid, oldRow, newRow);
194 } else if (oldRow != null) {
195 if (inventoryListener != null) {
196 inventoryListener.rowRemoved(n, name.getName(), uuid, oldRow);
198 db.removeRow(name.getName(), uuid);
204 private void updateOFBridgeName(final Node node, final Bridge bridge) {
205 Runnable updateNameRunnable = new Runnable() {
208 OvsDBSet<String> dpids = bridge.getDatapath_id();
209 String bridgeName = bridge.getName();
210 if (dpids == null || bridgeName == null) return;
211 for (String dpid : dpids) {
212 Long dpidLong = Long.valueOf(HexEncode.stringToLong(dpid));
214 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
215 Description descProp = new Description(bridgeName);
216 Set<Property> props = new HashSet<Property>();
219 IPluginOutInventoryService salInventoryService = (IPluginOutInventoryService) ServiceHelper.getInstance(
220 IPluginOutInventoryService.class, "default", this);
221 if (salInventoryService != null) {
222 logger.debug("Updating Bridge Name {} on OF node {}", bridgeName, ofNode);
223 salInventoryService.updateNode(ofNode, UpdateType.CHANGED, props);
225 logger.error("Error accessing SAL Inventory plugin");
227 } catch (ConstructionException e) {
228 logger.error("Failed to construct node for " + dpid, e);
233 executor.execute(updateNameRunnable);
234 // Add a delay & re-execute to compensate for the current OpenFlow plugin bug of
235 // overriding the Description with a Null value after the first statistics timer.
236 // Hopefully this will be resolved in the newer version of the Openflow plugin.
237 executor.schedule(updateNameRunnable, 30, TimeUnit.SECONDS);
241 public void printCache(Node n) {
242 NodeDB db = dbCache.get(n);
243 if (db != null) db.printTableCache();
247 public void addNode(Node node, Set<Property> props) {
248 addNodeProperty(node, UpdateType.ADDED, props);
252 public void notifyNodeAdded(Node node) {
253 OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
254 if (inventoryListener != null) {
255 inventoryListener.nodeAdded(node);
260 public void addNodeProperty(Node node, UpdateType type, Set<Property> props) {
261 Map<String, Property> nProp = nodeProps.get(node);
262 if (nProp == null) nProp = new HashMap<String, Property>();
263 for (Property prop : props) {
264 nProp.put(prop.getName(), prop);
266 nodeProps.put(node, nProp);
267 for (IPluginOutInventoryService service : pluginOutInventoryServices) {
268 service.updateNode(node, type, props);
273 public DatabaseSchema getDatabaseSchema(Node n) {
274 NodeDB db = dbCache.get(n);
275 if (db != null) return db.getSchema();
280 public void updateDatabaseSchema(Node n, DatabaseSchema schema) {
281 NodeDB db = dbCache.get(n);
286 db.setSchema(schema);
290 public void removeNode(Node node) {
291 OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
292 if (inventoryListener != null) {
293 inventoryListener.nodeRemoved(node);
296 for (IPluginOutInventoryService service : pluginOutInventoryServices) {
297 service.updateNode(node, UpdateType.REMOVED, null);
299 nodeProps.remove(node);
300 dbCache.remove(node);