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.Collections;
13 import java.util.HashMap;
14 import java.util.HashSet;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
19 import java.util.concurrent.CopyOnWriteArraySet;
20 import java.util.concurrent.ExecutionException;
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.message.TableUpdate;
36 import org.opendaylight.ovsdb.lib.message.TableUpdates;
37 import org.opendaylight.ovsdb.lib.notation.Row;
38 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 import com.google.common.collect.Maps;
45 * Stub Implementation for IPluginInReadService used by SAL
49 public class InventoryService implements IPluginInInventoryService, InventoryServiceInternal {
50 private static final Logger logger = LoggerFactory
51 .getLogger(InventoryService.class);
52 private final Set<IPluginOutInventoryService> pluginOutInventoryServices =
53 new CopyOnWriteArraySet<IPluginOutInventoryService>();
54 private ConcurrentMap<Node, Map<String, Property>> nodeProps;
55 private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps;
56 private ConcurrentMap<Node, NodeDB> dbCache = Maps.newConcurrentMap();
57 private ScheduledExecutorService executor;
58 private OVSDBConfigService configurationService;
61 * Function called by the dependency manager when all the required
62 * dependencies are satisfied
66 nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
67 nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
68 Node.NodeIDType.registerIDType("OVS", String.class);
69 NodeConnector.NodeConnectorIDType.registerIDType("OVS", String.class, "OVS");
70 this.executor = Executors.newSingleThreadScheduledExecutor();
74 * Function called by the dependency manager when at least one dependency
75 * become unsatisfied or when the component is shutting down because for
76 * example bundle is being stopped.
79 public void destroy() {
83 * Function called by dependency manager after "init ()" is called and after
84 * the services provided by the class are registered in the service registry
91 * Function called by the dependency manager before the services exported by
92 * the component are unregistered, this will be followed by a "destroy ()"
97 this.executor.shutdownNow();
100 public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
101 this.pluginOutInventoryServices.add(service);
104 public void unsetPluginOutInventoryServices(IPluginOutInventoryService service) {
105 this.pluginOutInventoryServices.remove(service);
108 public void setConfigurationService(OVSDBConfigService service) {
109 configurationService = service;
112 public void unsetConfigurationService(OVSDBConfigService service) {
113 configurationService = null;
117 * Retrieve nodes from openflow
120 public ConcurrentMap<Node, Map<String, Property>> getNodeProps() {
125 * Retrieve nodeConnectors from openflow
128 public ConcurrentMap<NodeConnector, Map<String, Property>> getNodeConnectorProps(
130 return nodeConnectorProps;
135 public ConcurrentMap<String, ConcurrentMap<String, Row>> getCache(Node n, String databaseName) {
136 NodeDB db = dbCache.get(n);
137 if (db == null) return null;
138 return db.getDatabase(databaseName);
143 public ConcurrentMap<String, Row> getTableCache(Node n, String databaseName, String tableName) {
144 NodeDB db = dbCache.get(n);
145 if (db == null) return null;
146 return db.getTableCache(databaseName, tableName);
151 public Row getRow(Node n, String databaseName, String tableName, String uuid) {
152 NodeDB db = dbCache.get(n);
153 if (db == null) return null;
154 return db.getRow(databaseName, tableName, uuid);
158 public void updateRow(Node n, String databaseName, String tableName, String uuid, Row row) {
159 NodeDB db = dbCache.get(n);
164 db.updateRow(databaseName, tableName, uuid, row);
168 public void removeRow(Node n, String databaseName, String tableName, String uuid) {
169 NodeDB db = dbCache.get(n);
170 if (db != null) db.removeRow(databaseName, tableName, uuid);
174 public void processTableUpdates(Node n, String databaseName, TableUpdates tableUpdates) {
175 NodeDB db = dbCache.get(n);
181 OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
182 for (String tableName : tableUpdates.getUpdates().keySet()) {
183 Map<String, Row> tCache = db.getTableCache(databaseName, tableName);
184 TableUpdate update = tableUpdates.getUpdates().get(tableName);
186 if (update.getNew() != null) {
187 boolean isNewRow = (tCache == null || tCache.get(update.getUuid().toString()) == null) ? true : false;
188 db.updateRow(databaseName, tableName, update.getUuid().toString(), update.getNew());
190 this.handleOpenVSwitchSpecialCase(n, databaseName, tableName, update);
191 if (inventoryListener != null) inventoryListener.rowAdded(n, tableName, update.getUuid().toString(), update.getNew());
193 if (inventoryListener != null) inventoryListener.rowUpdated(n, tableName, update.getUuid().toString(), update.getOld(), update.getNew());
195 } else if (update.getOld() != null){
196 if (tCache != null) {
197 if (inventoryListener != null) inventoryListener.rowRemoved(n, tableName, update.getUuid().toString(), update.getOld(), update.getNew());
199 db.removeRow(databaseName, tableName, update.getUuid().toString());
204 private void handleOpenVSwitchSpecialCase(Node node, String databaseName, String tableName, TableUpdate update) {
205 if (OvsVswitchdSchemaConstants.shouldConfigureController(databaseName, tableName)) {
207 if (configurationService != null) configurationService.setOFController(node, update.getUuid().toString());
208 } catch (InterruptedException | ExecutionException e) {
214 private void updateOFBridgeName(final Node node, final Bridge bridge) {
215 Runnable updateNameRunnable = new Runnable() {
218 Set<String> dpids = bridge.getDatapathIdColumn().getData();
219 String bridgeName = bridge.getName();
220 if (dpids == null || bridgeName == null) return;
221 for (String dpid : dpids) {
222 Long dpidLong = Long.valueOf(HexEncode.stringToLong(dpid));
224 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
225 Description descProp = new Description(bridgeName);
226 Set<Property> props = new HashSet<Property>();
229 IPluginOutInventoryService salInventoryService = (IPluginOutInventoryService) ServiceHelper.getInstance(
230 IPluginOutInventoryService.class, "default", this);
231 if (salInventoryService != null) {
232 logger.debug("Updating Bridge Name {} on OF node {}", bridgeName, ofNode);
233 salInventoryService.updateNode(ofNode, UpdateType.CHANGED, props);
235 logger.error("Error accessing SAL Inventory plugin");
237 } catch (ConstructionException e) {
238 logger.error("Failed to construct node for " + dpid, e);
243 executor.execute(updateNameRunnable);
244 // Add a delay & re-execute to compensate for the current OpenFlow plugin bug of
245 // overriding the Description with a Null value after the first statistics timer.
246 // Hopefully this will be resolved in the newer version of the Openflow plugin.
247 executor.schedule(updateNameRunnable, 30, TimeUnit.SECONDS);
251 public void printCache(Node n) {
252 NodeDB db = dbCache.get(n);
253 if (db != null) db.printTableCache();
257 public void addNode(Node node, Set<Property> props) {
258 addNodeProperty(node, UpdateType.ADDED, props);
262 public void notifyNodeAdded(Node node) {
263 OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
264 if (inventoryListener != null) {
265 inventoryListener.nodeAdded(node);
270 public void addNodeProperty(Node node, UpdateType type, Set<Property> props) {
271 Map<String, Property> nProp = nodeProps.get(node);
272 if (nProp == null) nProp = new HashMap<String, Property>();
273 for (Property prop : props) {
274 nProp.put(prop.getName(), prop);
276 nodeProps.put(node, nProp);
277 for (IPluginOutInventoryService service : pluginOutInventoryServices) {
278 service.updateNode(node, type, props);
283 public void removeNode(Node node) {
284 OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this);
285 if (inventoryListener != null) {
286 inventoryListener.nodeRemoved(node);
289 for (IPluginOutInventoryService service : pluginOutInventoryServices) {
290 service.updateNode(node, UpdateType.REMOVED, null);
292 nodeProps.remove(node);
293 dbCache.remove(node);
297 public Set<Node> getConfiguredNotConnectedNodes() {
298 return Collections.emptySet();