2 * Copyright (c) 2013, 2015 Red Hat, Inc. and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.plugin.md;
11 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
12 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
13 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
14 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
15 import org.opendaylight.controller.sal.utils.HexEncode;
16 import org.opendaylight.ovsdb.lib.notation.Row;
17 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
18 import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryListener;
19 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbCapableNode;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbCapableNodeBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbManagedNode;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbManagedNodeBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.nodes.node.OvsdbBridge;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.nodes.node.OvsdbBridgeBuilder;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34 import com.google.common.base.Optional;
35 import com.google.common.base.Preconditions;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 import java.net.InetAddress;
40 import java.util.ArrayList;
41 import java.util.List;
43 import java.util.concurrent.ExecutionException;
46 * Handle OVSDB Inventory Updates and create the necessary entries in the MD-SAL config datastore
48 public class OvsdbInventoryManager implements OvsdbInventoryListener {
50 // Dependencies injected by OSGi
51 private volatile OvsdbBindingAwareProvider provider;
52 private volatile OvsdbConfigurationService ovsdbConfigurationService;
54 static final String OVS_NODE_PREFIX = "openvswitch:";
55 static final String OPENFLOW_NODE_PREFIX = "openflow:";
57 static final Logger LOGGER = LoggerFactory.getLogger(OvsdbInventoryManager.class);
61 * Called by the framework when the bundle is started
64 //ToDo: Add existing nodes from inventory
65 //This case is required for surviving controller reboot
69 * When an AD-SAL node is added by the OVSDB Inventory Service, Add an MD-SAL node
71 * @param node The AD-SAL node
72 * @param address The {@link java.net.InetAddress} of the Node
73 * @param port The ephemeral port number used by this connection
76 public synchronized void nodeAdded(org.opendaylight.controller.sal.core.Node node,
79 DataBroker dataBroker = provider.getDataBroker();
80 Preconditions.checkNotNull(dataBroker);
82 NodeId nodeId = new NodeId(OVS_NODE_PREFIX + node.getNodeIDString());
83 NodeKey nodeKey = new NodeKey(nodeId);
85 OvsdbCapableNode ovsdbNode = new OvsdbCapableNodeBuilder()
86 .setIpAddress(Utils.convertIpAddress(address))
87 .setPort(new PortNumber(port))
88 .setManagedNodes(new ArrayList<NodeId>())
91 Node newNode = new NodeBuilder()
94 .addAugmentation(OvsdbCapableNode.class, ovsdbNode)
97 InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class)
98 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeKey)
101 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
102 tx.put(LogicalDatastoreType.CONFIGURATION, path, newNode, true);
105 LOGGER.debug("Removed Node {}", path.toString());
106 } catch (InterruptedException | ExecutionException e) {
107 LOGGER.error(e.getMessage(), e);
112 * When an AD-SAL node is removed by the OVSDB Inventory Service, Remove the MD-SAL node
114 * @param node The AD-SAL node
117 public synchronized void nodeRemoved(org.opendaylight.controller.sal.core.Node node) {
118 DataBroker dataBroker = provider.getDataBroker();
119 Preconditions.checkNotNull(dataBroker);
121 NodeId nodeId = new NodeId(new NodeId(OVS_NODE_PREFIX + node.getNodeIDString()));
122 NodeKey nodeKey = new NodeKey(nodeId);
124 InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class)
125 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeKey)
128 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
129 tx.delete(LogicalDatastoreType.CONFIGURATION, path);
132 LOGGER.debug("Removed Node {}", path.toString());
133 } catch (InterruptedException | ExecutionException e) {
134 LOGGER.error(e.getMessage(), e);
139 * Handle OVSDB row removed When a Bridge row is removed, the OpenFlow Node is deleted The parent OVSDB node is
140 * updated and the OpenFlow node removed from it's managed-nodes list
142 * @param node The AD-SAL node
143 * @param tableName The name of modified table
144 * @param uuid The UUID of the deleted row
145 * @param row The deleted Row
148 public synchronized void rowRemoved(org.opendaylight.controller.sal.core.Node node,
153 if (tableName.equalsIgnoreCase(ovsdbConfigurationService.getTableName(node, Bridge.class))) {
154 LOGGER.debug("OVSDB Bridge Row removed on node {}", node.toString());
155 DataBroker dataBroker = provider.getDataBroker();
156 Preconditions.checkNotNull(dataBroker);
158 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
159 Set<String> dpidString = bridge.getDatapathIdColumn().getData();
160 Long dpid = HexEncode.stringToLong((String) dpidString.toArray()[0]);
162 NodeId openflowNodeId = new NodeId(OPENFLOW_NODE_PREFIX + dpid.toString());
163 NodeKey openflowNodeKey = new NodeKey(openflowNodeId);
165 InstanceIdentifier<Node> openflowNodePath = InstanceIdentifier.builder(Nodes.class)
166 .child(Node.class, openflowNodeKey)
169 NodeId ovsdbNodeId = new NodeId(OVS_NODE_PREFIX + node.getNodeIDString());
170 NodeKey ovsdbNodeKey = new NodeKey(ovsdbNodeId);
172 InstanceIdentifier<OvsdbCapableNode> ovsdbNodePath = InstanceIdentifier.builder(Nodes.class)
173 .child(Node.class, ovsdbNodeKey)
174 .augmentation(OvsdbCapableNode.class)
177 // Read the current OVSDB Node from the DataStore
178 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
179 OvsdbCapableNode ovsdbNode;
181 Optional<OvsdbCapableNode> data = tx.read(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath).get();
182 if (!data.isPresent()) {
183 LOGGER.error("OVSDB node not updated. Parent node for {} does not exist", ovsdbNodePath.toString());
186 ovsdbNode = data.get();
187 } catch (InterruptedException | ExecutionException e) {
188 LOGGER.error("OVSDB node not updated. Parent node for {} does not exist", ovsdbNodePath.toString());
192 // Update the list of Nodes
193 List<NodeId> managedNodesList = ovsdbNode.getManagedNodes();
194 managedNodesList.remove(openflowNodeId);
196 // Write changes to DataStore
197 OvsdbCapableNode updatedNode = new OvsdbCapableNodeBuilder(ovsdbNode)
198 .setManagedNodes(managedNodesList)
200 tx.delete(LogicalDatastoreType.CONFIGURATION, openflowNodePath);
201 tx.put(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath, updatedNode);
205 LOGGER.debug("Transaction success for delete of {} and update of {}",
206 openflowNodePath.toString(),
207 ovsdbNodePath.toString());
208 } catch (InterruptedException | ExecutionException e) {
209 LOGGER.error(e.getMessage(), e);
215 * Handle OVSDB row updates When a Bridge row is updated and it contains a DPID then add a new OpenFlow node to the
216 * inventory A relationship is created between the OpenFlow and OVSDB nodes
218 * @param node The AD-SAL node
219 * @param tableName The name of the updated table
220 * @param uuid The UUID of the updated row
221 * @param old The old contents of the row
222 * @param row The updated Row
225 public synchronized void rowUpdated(org.opendaylight.controller.sal.core.Node node,
230 LOGGER.debug("OVSDB Bridge Row updated on node {}", node.toString());
231 if (tableName.equalsIgnoreCase(ovsdbConfigurationService.getTableName(node, Bridge.class))) {
232 DataBroker dataBroker = provider.getDataBroker();
233 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
235 Set<String> dpidString = bridge.getDatapathIdColumn().getData();
238 dpid = HexEncode.stringToLong((String) dpidString.toArray()[0]);
239 } catch (ArrayIndexOutOfBoundsException e) {
243 NodeId openflowNodeId = new NodeId(OPENFLOW_NODE_PREFIX + dpid.toString());
244 NodeKey openflowNodeKey = new NodeKey(openflowNodeId);
246 InstanceIdentifier<OvsdbManagedNode> openflowNodepath = InstanceIdentifier.builder(Nodes.class)
247 .child(Node.class, openflowNodeKey)
248 .augmentation(OvsdbManagedNode.class)
251 NodeId ovsdbNodeId = new NodeId(OVS_NODE_PREFIX + node.getNodeIDString());
252 NodeKey ovsdbNodeKey = new NodeKey(ovsdbNodeId);
254 InstanceIdentifier<OvsdbCapableNode> ovsdbNodePath = InstanceIdentifier.builder(Nodes.class)
255 .child(Node.class, ovsdbNodeKey)
256 .augmentation(OvsdbCapableNode.class)
259 // Create an OvsdbBridge object using the information from the update
260 OvsdbBridge ovsdbBridge = new OvsdbBridgeBuilder()
261 .setBridgeName(bridge.getName())
263 .setManagedBy(ovsdbNodeId)
266 // Add the bridge to the OvsdbManagedNode
267 OvsdbManagedNode ovsdbManagedNode = new OvsdbManagedNodeBuilder()
268 .setOvsdbBridge(ovsdbBridge)
271 // Read the current OVSDB Node from the DataStore
272 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
273 OvsdbCapableNode ovsdbNode;
275 Optional<OvsdbCapableNode> data = tx.read(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath).get();
276 if (!data.isPresent()) {
277 LOGGER.error("OVSDB node not updated. Parent node for {} does not exist", ovsdbNodePath.toString());
280 ovsdbNode = data.get();
281 } catch (InterruptedException | ExecutionException e) {
282 throw new RuntimeException("Node does not exist");
285 // Update the list of Nodes
286 List<NodeId> managedNodesList = ovsdbNode.getManagedNodes();
287 managedNodesList.add(openflowNodeId);
289 // Create a delta object
290 OvsdbCapableNode updatedNode = new OvsdbCapableNodeBuilder(ovsdbNode)
291 .setManagedNodes(managedNodesList)
294 // Create parent if we get to this node before openflowplugin
295 tx.put(LogicalDatastoreType.CONFIGURATION, openflowNodepath, ovsdbManagedNode, true);
296 tx.put(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath, updatedNode);
300 LOGGER.debug("Transaction success for addition of {} and update of {}",
301 openflowNodepath.toString(),
302 ovsdbNodePath.toString());
303 } catch (InterruptedException | ExecutionException e) {
304 LOGGER.error(e.getMessage(), e);
310 public synchronized void rowAdded(org.opendaylight.controller.sal.core.Node node,