1 package org.opendaylight.ovsdb.plugin.md;
3 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
4 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
5 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
6 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
7 import org.opendaylight.controller.sal.utils.HexEncode;
8 import org.opendaylight.ovsdb.lib.notation.Row;
9 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
10 import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryListener;
11 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
12 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbCapableNode;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbCapableNodeBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbManagedNode;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbManagedNodeBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.nodes.node.OvsdbBridge;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.nodes.node.OvsdbBridgeBuilder;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
26 import com.google.common.base.Optional;
27 import com.google.common.base.Preconditions;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
31 import java.net.InetAddress;
32 import java.util.ArrayList;
33 import java.util.List;
35 import java.util.concurrent.ExecutionException;
38 * Handle OVSDB Inventory Updates and create the necessary entries in the MD-SAL config datastore
40 public class OvsdbInventoryManager implements OvsdbInventoryListener {
42 // Dependencies injected by OSGi
43 private volatile OvsdbBindingAwareProvider provider;
44 private volatile OvsdbConfigurationService ovsdbConfigurationService;
46 static final String OVS_NODE_PREFIX = "openvswitch:";
47 static final String OPENFLOW_NODE_PREFIX = "openflow:";
49 static final Logger logger = LoggerFactory.getLogger(OvsdbInventoryManager.class);
53 * Called by the framework when the bundle is started
56 //ToDo: Add existing nodes from inventory
57 //This case is required for surviving controller reboot
61 * When an AD-SAL node is added by the OVSDB Inventory Service, Add an MD-SAL node
63 * @param node The AD-SAL node
64 * @param address The {@link java.net.InetAddress} of the Node
65 * @param port The ephemeral port number used by this connection
68 public synchronized void nodeAdded(org.opendaylight.controller.sal.core.Node node,
71 DataBroker dataBroker = provider.getDataBroker();
72 Preconditions.checkNotNull(dataBroker);
74 NodeId nodeId = new NodeId(OVS_NODE_PREFIX + node.getNodeIDString());
75 NodeKey nodeKey = new NodeKey(nodeId);
77 OvsdbCapableNode ovsdbNode = new OvsdbCapableNodeBuilder()
78 .setIpAddress(Utils.convertIpAddress(address))
79 .setPort(new PortNumber(port))
80 .setManagedNodes(new ArrayList<NodeId>())
83 Node newNode = new NodeBuilder()
86 .addAugmentation(OvsdbCapableNode.class, ovsdbNode)
89 InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class)
90 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeKey)
93 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
94 tx.put(LogicalDatastoreType.CONFIGURATION, path, newNode, true);
97 logger.debug("Removed Node {}", path.toString());
98 } catch (InterruptedException | ExecutionException e) {
99 logger.error(e.getMessage(), e);
104 * When an AD-SAL node is removed by the OVSDB Inventory Service, Remove the MD-SAL node
106 * @param node The AD-SAL node
109 public synchronized void nodeRemoved(org.opendaylight.controller.sal.core.Node node) {
110 DataBroker dataBroker = provider.getDataBroker();
111 Preconditions.checkNotNull(dataBroker);
113 NodeId nodeId = new NodeId(new NodeId(OVS_NODE_PREFIX + node.getNodeIDString()));
114 NodeKey nodeKey = new NodeKey(nodeId);
116 InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class)
117 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeKey)
120 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
121 tx.delete(LogicalDatastoreType.CONFIGURATION, path);
124 logger.debug("Removed Node {}", path.toString());
125 } catch (InterruptedException | ExecutionException e) {
126 logger.error(e.getMessage(), e);
131 * Handle OVSDB row removed When a Bridge row is removed, the OpenFlow Node is deleted The parent OVSDB node is
132 * updated and the OpenFlow node removed from it's managed-nodes list
134 * @param node The AD-SAL node
135 * @param tableName The name of modified table
136 * @param uuid The UUID of the deleted row
137 * @param row The deleted Row
140 public synchronized void rowRemoved(org.opendaylight.controller.sal.core.Node node,
145 if (tableName.equalsIgnoreCase(ovsdbConfigurationService.getTableName(node, Bridge.class))) {
146 logger.debug("OVSDB Bridge Row removed on node {}", node.toString());
147 DataBroker dataBroker = provider.getDataBroker();
148 Preconditions.checkNotNull(dataBroker);
150 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
151 Set<String> dpidString = bridge.getDatapathIdColumn().getData();
152 Long dpid = HexEncode.stringToLong((String) dpidString.toArray()[0]);
154 NodeId openflowNodeId = new NodeId(OPENFLOW_NODE_PREFIX + dpid.toString());
155 NodeKey openflowNodeKey = new NodeKey(openflowNodeId);
157 InstanceIdentifier<Node> openflowNodePath = InstanceIdentifier.builder(Nodes.class)
158 .child(Node.class, openflowNodeKey)
161 NodeId ovsdbNodeId = new NodeId(OVS_NODE_PREFIX + node.getNodeIDString());
162 NodeKey ovsdbNodeKey = new NodeKey(ovsdbNodeId);
164 InstanceIdentifier<OvsdbCapableNode> ovsdbNodePath = InstanceIdentifier.builder(Nodes.class)
165 .child(Node.class, ovsdbNodeKey)
166 .augmentation(OvsdbCapableNode.class)
169 // Read the current OVSDB Node from the DataStore
170 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
171 OvsdbCapableNode ovsdbNode;
173 Optional<OvsdbCapableNode> data = tx.read(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath).get();
174 if (!data.isPresent()) {
175 logger.error("OVSDB node not updated. Parent node for {} does not exist", ovsdbNodePath.toString());
178 ovsdbNode = data.get();
179 } catch (InterruptedException | ExecutionException e) {
180 logger.error("OVSDB node not updated. Parent node for {} does not exist", ovsdbNodePath.toString());
184 // Update the list of Nodes
185 List<NodeId> managedNodesList = ovsdbNode.getManagedNodes();
186 managedNodesList.remove(openflowNodeId);
188 // Write changes to DataStore
189 OvsdbCapableNode updatedNode = new OvsdbCapableNodeBuilder(ovsdbNode)
190 .setManagedNodes(managedNodesList)
192 tx.delete(LogicalDatastoreType.CONFIGURATION, openflowNodePath);
193 tx.put(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath, updatedNode);
197 logger.debug("Transaction success for delete of {} and update of {}",
198 openflowNodePath.toString(),
199 ovsdbNodePath.toString());
200 } catch (InterruptedException | ExecutionException e) {
201 logger.error(e.getMessage(), e);
207 * Handle OVSDB row updates When a Bridge row is updated and it contains a DPID then add a new OpenFlow node to the
208 * inventory A relationship is created between the OpenFlow and OVSDB nodes
210 * @param node The AD-SAL node
211 * @param tableName The name of the updated table
212 * @param uuid The UUID of the updated row
213 * @param old The old contents of the row
214 * @param row The updated Row
217 public synchronized void rowUpdated(org.opendaylight.controller.sal.core.Node node,
222 logger.debug("OVSDB Bridge Row updated on node {}", node.toString());
223 if (tableName.equalsIgnoreCase(ovsdbConfigurationService.getTableName(node, Bridge.class))) {
224 DataBroker dataBroker = provider.getDataBroker();
225 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
227 Set<String> dpidString = bridge.getDatapathIdColumn().getData();
230 dpid = HexEncode.stringToLong((String) dpidString.toArray()[0]);
231 } catch (ArrayIndexOutOfBoundsException e) {
235 NodeId openflowNodeId = new NodeId(OPENFLOW_NODE_PREFIX + dpid.toString());
236 NodeKey openflowNodeKey = new NodeKey(openflowNodeId);
238 InstanceIdentifier<OvsdbManagedNode> openflowNodepath = InstanceIdentifier.builder(Nodes.class)
239 .child(Node.class, openflowNodeKey)
240 .augmentation(OvsdbManagedNode.class)
243 NodeId ovsdbNodeId = new NodeId(OVS_NODE_PREFIX + node.getNodeIDString());
244 NodeKey ovsdbNodeKey = new NodeKey(ovsdbNodeId);
246 InstanceIdentifier<OvsdbCapableNode> ovsdbNodePath = InstanceIdentifier.builder(Nodes.class)
247 .child(Node.class, ovsdbNodeKey)
248 .augmentation(OvsdbCapableNode.class)
251 // Create an OvsdbBridge object using the information from the update
252 OvsdbBridge ovsdbBridge = new OvsdbBridgeBuilder()
253 .setBridgeName(bridge.getName())
255 .setManagedBy(ovsdbNodeId)
258 // Add the bridge to the OvsdbManagedNode
259 OvsdbManagedNode ovsdbManagedNode = new OvsdbManagedNodeBuilder()
260 .setOvsdbBridge(ovsdbBridge)
263 // Read the current OVSDB Node from the DataStore
264 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
265 OvsdbCapableNode ovsdbNode;
267 Optional<OvsdbCapableNode> data = tx.read(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath).get();
268 if (!data.isPresent()) {
269 logger.error("OVSDB node not updated. Parent node for {} does not exist", ovsdbNodePath.toString());
272 ovsdbNode = data.get();
273 } catch (InterruptedException | ExecutionException e) {
274 throw new RuntimeException("Node does not exist");
277 // Update the list of Nodes
278 List<NodeId> managedNodesList = ovsdbNode.getManagedNodes();
279 managedNodesList.add(openflowNodeId);
281 // Create a delta object
282 OvsdbCapableNode updatedNode = new OvsdbCapableNodeBuilder(ovsdbNode)
283 .setManagedNodes(managedNodesList)
286 // Create parent if we get to this node before openflowplugin
287 tx.put(LogicalDatastoreType.CONFIGURATION, openflowNodepath, ovsdbManagedNode, true);
288 tx.put(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath, updatedNode);
292 logger.debug("Transaction success for addition of {} and update of {}",
293 openflowNodepath.toString(),
294 ovsdbNodePath.toString());
295 } catch (InterruptedException | ExecutionException e) {
296 logger.error(e.getMessage(), e);
302 public synchronized void rowAdded(org.opendaylight.controller.sal.core.Node node,