<artifactId>schema.openvswitch</artifactId>
<version>${schema.openvswitch.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>plugin-mdsal-adapter</artifactId>
+ <version>${ovsdb.plugin.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<sourceDirectory>${project.basedir}</sourceDirectory>
<includes>**\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat</includes>
- <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,\/,**\/xtend-gen\/</excludes>
+ <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,\/</excludes>
</configuration>
<dependencies>
<dependency>
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <version>${yangtools.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <!-- directory containing yang files to parse and generate code -->
+ <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+ </codeGeneratorClass>
+ <!-- directory into which generated files will be placed -->
+ <outputBaseDir>
+ target/generated-sources/sal
+ </outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>maven-sal-api-gen-plugin</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.7</version>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>target/generated-sources/sal</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</pluginManagement>
</build>
<groupId>org.opendaylight.ovsdb</groupId>
<artifactId>plugin</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>plugin-mdsal-adapter</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.ovsdb</groupId>
<artifactId>schema.openvswitch</artifactId>
import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperty;
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-import java.util.List;
-import java.util.concurrent.ConcurrentMap;
-
-import javax.inject.Inject;
-
-import org.apache.felix.dm.Component;
-import org.apache.felix.dm.DependencyManager;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.utils.ServiceHelper;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.inject.Inject;
@RunWith(PaxExam.class)
public class OvsdbPluginIT extends OvsdbIntegrationTestBase {
}
@Test
- public void testInventoryListeners(){
+ public void testInventoryListeners() throws UnknownHostException {
DependencyManager dm = new DependencyManager(bc);
OvsdbInventoryListener listenerA = Mockito.mock(FakeListener.class);
dm.add(componentB);
Node newNode = Node.fromString("OVS:10.10.10.10:65342");
+ InetAddress address = InetAddress.getByName("10.10.10.10");
+ int port = 65342;
// Trigger event
- ovsdbInventoryService.notifyNodeAdded(newNode);
+ ovsdbInventoryService.notifyNodeAdded(newNode, address, port);
- Mockito.verify(listenerA, Mockito.times(1)).nodeAdded(newNode);
- Mockito.verify(listenerB, Mockito.times(1)).nodeAdded(newNode);
+ Mockito.verify(listenerA, Mockito.times(1)).nodeAdded(newNode, address, port);
+ Mockito.verify(listenerB, Mockito.times(1)).nodeAdded(newNode, address, port);
dm.remove(componentA);
dm.remove(componentB);
public class FakeListener implements OvsdbInventoryListener {
@Override
- public void nodeAdded(Node node) {
+ public void nodeAdded(Node node, InetAddress address, int port) {
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.net.InetAddress;
import java.util.List;
import java.util.Map;
import java.util.Set;
}
@Override
- public void nodeAdded(Node node) {
+ public void nodeAdded(Node node, InetAddress address, int port) {
this.enqueueEvent(new SouthboundEvent(node, SouthboundEvent.Action.ADD));
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>commons</artifactId>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <version>1.2.0-SNAPSHOT</version>
+ <relativePath>../commons/parent/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>plugin-mdsal-adapter</artifactId>
+ <name>OpenDaylight OVSDB Plugin MD_SAL Adapter</name>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <!-- Yang Models -->
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-inet-types</artifactId>
+ <version>2010.09.24.4-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-inventory</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-flow-service</artifactId>
+ </dependency>
+ <!-- Controller Dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>library</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>plugin</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.6</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.*,
+ org.opendaylight.controller.sal.binding.api,
+ org.opendaylight.ovsdb.plugin.api,
+ org.apache.felix.dm,
+ org.slf4j,
+ org.eclipse.osgi.framework.console,
+ org.osgi.framework,
+ javax.net.ssl,
+ *
+ </Import-Package>
+ <Embed-Transitive>true</Embed-Transitive>
+ <Bundle-Activator>
+ org.opendaylight.ovsdb.plugin.md.Activator
+ </Bundle-Activator>
+ </instructions>
+ <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Authors : Dave Tucker
+ */
+
+package org.opendaylight.ovsdb.plugin.md;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
+import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryListener;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * OSGi Bundle Activator for the Neutron providers
+ */
+public class Activator extends ComponentActivatorAbstractBase {
+ /**
+ * Function called when the activator starts just after some
+ * initializations are done by the
+ * ComponentActivatorAbstractBase.
+ */
+ @Override
+ public void init() {
+ }
+
+ /**
+ * Function called when the activator stops just before the
+ * cleanup done by ComponentActivatorAbstractBase.
+ *
+ */
+ @Override
+ public void destroy() {
+ }
+
+ /**
+ * Function that is used to communicate to dependency manager the
+ * list of known implementations for services inside a container.
+ *
+ * @return An array containing all the CLASS objects that will be
+ * instantiated in order to get an fully working implementation
+ * Object
+ */
+ @Override
+ public Object[] getImplementations() {
+ Object[] res = {OvsdbBindingAwareProviderImpl.class,
+ OvsdbInventoryManager.class };
+ return res;
+ }
+
+ /**
+ * Function that is called when configuration of the dependencies
+ * is required.
+ *
+ * @param c dependency manager Component object, used for
+ * configuring the dependencies exported and imported
+ * @param imp Implementation class that is being configured,
+ * needed as long as the same routine can configure multiple
+ * implementations
+ * @param containerName The containerName being configured, this allow
+ * also optional per-container different behavior if needed, usually
+ * should not be the case though.
+ */
+ @Override
+ public void configureInstance(Component c, Object imp,
+ String containerName) {
+
+ if (imp.equals(OvsdbBindingAwareProviderImpl.class)) {
+ c.setInterface(OvsdbBindingAwareProvider.class.getName(), null);
+ c.add(createServiceDependency()
+ .setService(BindingAwareBroker.class)
+ .setRequired(true));
+ }
+
+ if (imp.equals(OvsdbInventoryManager.class)) {
+ c.setInterface(OvsdbInventoryListener.class.getName(), null);
+ c.add(createServiceDependency()
+ .setService(OvsdbBindingAwareProvider.class)
+ .setRequired(true));
+ c.add(createServiceDependency()
+ .setService(OvsdbConfigurationService.class)
+ .setRequired(true));
+ }
+ }
+}
--- /dev/null
+package org.opendaylight.ovsdb.plugin.md;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.NotificationService;
+
+/**
+ * Created by dave on 01/08/2014.
+ */
+public interface OvsdbBindingAwareProvider {
+ public DataBroker getDataBroker();
+ public NotificationService getNotificationService();
+}
--- /dev/null
+package org.opendaylight.ovsdb.plugin.md;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.binding.api.NotificationService;
+
+import org.apache.felix.dm.Component;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OvsdbBindingAwareProviderImpl extends AbstractBindingAwareProvider implements OvsdbBindingAwareProvider {
+
+ private DataBroker dataBroker;
+ private NotificationProviderService notificationService;
+
+ static final Logger logger = LoggerFactory.getLogger(OvsdbBindingAwareProvider.class);
+
+ private BundleContext bc;
+ private volatile BindingAwareBroker broker;
+
+ void init(Component c) {
+ this.bc = c.getDependencyManager().getBundleContext();
+ broker.registerProvider(this, this.bc);
+ logger.info("OVSDB MD-SAL Inventory Adapter Registered With the MD-SAL");
+ }
+
+ void destroy() {
+ this.dataBroker = null;
+ this.notificationService = null;
+ }
+
+ @Override
+ public void onSessionInitiated(BindingAwareBroker.ProviderContext providerContext) {
+ this.dataBroker = providerContext.getSALService(DataBroker.class);
+ this.notificationService = providerContext.getSALService(NotificationProviderService.class);
+ }
+
+ @Override
+ public DataBroker getDataBroker() {
+ return this.dataBroker;
+ }
+
+ @Override
+ public NotificationService getNotificationService() {
+ return this.notificationService;
+ }
+}
--- /dev/null
+package org.opendaylight.ovsdb.plugin.md;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
+import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryListener;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbManagedNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.OvsdbManagedNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.nodes.node.OvsdbBridge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.ovsdb.node.inventory.rev140731.nodes.node.OvsdbBridgeBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Handle OVSDB Inventory Updates and create the necessary entries in the MD-SAL config datastore
+ */
+public class OvsdbInventoryManager implements OvsdbInventoryListener {
+
+ // Dependencies injected by OSGi
+ private volatile OvsdbBindingAwareProvider provider;
+ private volatile OvsdbConfigurationService ovsdbConfigurationService;
+
+ static final String OVS_NODE_PREFIX = "openvswitch:";
+ static final String OPENFLOW_NODE_PREFIX = "openflow:";
+
+ static final Logger logger = LoggerFactory.getLogger(OvsdbInventoryManager.class);
+
+
+ /**
+ * Called by the framework when the bundle is started
+ */
+ public void start(){
+ //ToDo: Add existing nodes from inventory
+ //This case is required for surviving controller reboot
+ }
+
+ /**
+ * When an AD-SAL node is added by the OVSDB Inventory Service, Add an MD-SAL node
+ */
+ @Override
+ public synchronized void nodeAdded(org.opendaylight.controller.sal.core.Node node, InetAddress address, int port) {
+ logger.debug("OVSDB MD-SAL Inventory Adapter: Got node added for node {}", node.toString());
+ DataBroker dataBroker = provider.getDataBroker();
+ Preconditions.checkNotNull(dataBroker);
+
+ NodeId nodeId = new NodeId(OVS_NODE_PREFIX + node.getNodeIDString());
+ NodeKey nodeKey = new NodeKey(nodeId);
+
+ OvsdbCapableNode ovsdbNode = new OvsdbCapableNodeBuilder()
+ .setIpAddress(Utils.convertIpAddress(address))
+ .setPort(new PortNumber(port))
+ .setManagedNodes(new ArrayList<NodeId>())
+ .build();
+
+ Node newNode = new NodeBuilder()
+ .setId(nodeId)
+ .setKey(nodeKey)
+ .addAugmentation(OvsdbCapableNode.class, ovsdbNode)
+ .build();
+
+ InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeKey)
+ .toInstance();
+
+ WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+ tx.put(LogicalDatastoreType.CONFIGURATION, path, newNode, true);
+ try {
+ tx.submit().get();
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * When an AD-SAL node is removed by the OVSDB Inventory Service, Remove the MD-SAL node
+ */
+ @Override
+ public synchronized void nodeRemoved(org.opendaylight.controller.sal.core.Node node) {
+ logger.debug("OVSDB MD-SAL Inventory Adapter: Got node removed for node {}", node.toString());
+ DataBroker dataBroker = provider.getDataBroker();
+ Preconditions.checkNotNull(dataBroker);
+
+ NodeId nodeId = new NodeId(new NodeId(OVS_NODE_PREFIX + node.getNodeIDString()));
+ NodeKey nodeKey = new NodeKey(nodeId);
+
+ InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeKey)
+ .toInstance();
+
+ WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+ tx.delete(LogicalDatastoreType.CONFIGURATION, path);
+ try {
+ tx.submit().get();
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * When a Bridge Row is removed, delete the node
+ */
+ @Override
+ public synchronized void rowRemoved(org.opendaylight.controller.sal.core.Node node, String tableName, String uuid, Row row,
+ Object context) {
+ if (tableName.equalsIgnoreCase(ovsdbConfigurationService.getTableName(node, Bridge.class))) {
+ logger.debug("OVSDB Bridge Row removed on node {}", node.toString());
+ DataBroker dataBroker = provider.getDataBroker();
+
+ Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
+ Set<String> dpidString = bridge.getDatapathIdColumn().getData();
+ Long dpid = HexEncode.stringToLong((String) dpidString.toArray()[0]);
+
+ NodeId openflowNodeId = new NodeId(OPENFLOW_NODE_PREFIX + dpid.toString());
+ NodeKey openflowNodeKey = new NodeKey(openflowNodeId);
+
+ InstanceIdentifier<OvsdbManagedNode> openflowNodepath = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, openflowNodeKey)
+ .augmentation(OvsdbManagedNode.class)
+ .toInstance();
+
+ NodeId ovsdbNodeId = new NodeId(OVS_NODE_PREFIX + node.getNodeIDString());
+ NodeKey ovsdbNodeKey = new NodeKey(ovsdbNodeId);
+
+ InstanceIdentifier<OvsdbCapableNode> ovsdbNodePath = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, ovsdbNodeKey)
+ .augmentation(OvsdbCapableNode.class)
+ .toInstance();
+
+ // Read the current OVSDB Node from the DataStore
+ ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
+ OvsdbCapableNode ovsdbNode;
+ try {
+ Optional<OvsdbCapableNode> data = readTx.read(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath).get();
+ ovsdbNode = data.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException("Node does not exist");
+ }
+
+ // Update the list of Nodes
+ List<NodeId> managedNodesList = ovsdbNode.getManagedNodes();
+ managedNodesList.remove(openflowNodeId);
+
+ // Write changes to DataStore
+ OvsdbCapableNode updatedNode = new OvsdbCapableNodeBuilder(ovsdbNode)
+ .setManagedNodes(managedNodesList)
+ .build();
+ WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
+ writeTx.delete(LogicalDatastoreType.CONFIGURATION, openflowNodepath);
+ writeTx.put(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath, updatedNode);
+ writeTx.submit();
+ }
+ }
+
+ /**
+ * Handle OVSDB row updates
+ */
+ @Override
+ public synchronized void rowUpdated(org.opendaylight.controller.sal.core.Node node, String tableName, String uuid, Row old,
+ Row row) {
+ logger.debug("OVSDB Bridge Row updated on node {}", node.toString());
+ if (tableName.equalsIgnoreCase(ovsdbConfigurationService.getTableName(node, Bridge.class))) {
+ DataBroker dataBroker = provider.getDataBroker();
+ Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
+
+ Set<String> dpidString = bridge.getDatapathIdColumn().getData();
+ Long dpid;
+ try {
+ dpid = HexEncode.stringToLong((String) dpidString.toArray()[0]);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return;
+ }
+
+ NodeId openflowNodeId = new NodeId(OPENFLOW_NODE_PREFIX + dpid.toString());
+ NodeKey openflowNodeKey = new NodeKey(openflowNodeId);
+
+ InstanceIdentifier<OvsdbManagedNode> openflowNodepath = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, openflowNodeKey)
+ .augmentation(OvsdbManagedNode.class)
+ .toInstance();
+
+ NodeId ovsdbNodeId = new NodeId(OVS_NODE_PREFIX + node.getNodeIDString());
+ NodeKey ovsdbNodeKey = new NodeKey(ovsdbNodeId);
+
+ InstanceIdentifier<OvsdbCapableNode> ovsdbNodePath = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, ovsdbNodeKey)
+ .augmentation(OvsdbCapableNode.class)
+ .toInstance();
+
+ // Create an OvsdbBridge object using the information from the update
+ OvsdbBridge ovsdbBridge = new OvsdbBridgeBuilder()
+ .setBridgeName(bridge.getName())
+ .setBridgeUuid(uuid)
+ .setManagedBy(ovsdbNodeId)
+ .build();
+
+ // Add the bridge to the OvsdbManagedNode
+ OvsdbManagedNode ovsdbManagedNode = new OvsdbManagedNodeBuilder()
+ .setOvsdbBridge(ovsdbBridge)
+ .build();
+
+ // Read the current OVSDB Node from the DataStore
+ ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
+ OvsdbCapableNode ovsdbNode = null;
+ try {
+ Optional<OvsdbCapableNode>
+ data =
+ readTx.read(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath).get();
+ ovsdbNode = data.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException("Node does not exist");
+ }
+
+ // Update the list of Nodes
+ List<NodeId> managedNodesList = ovsdbNode.getManagedNodes();
+ Boolean updated = false;
+ managedNodesList.add(openflowNodeId);
+
+ // Create a delta object
+ OvsdbCapableNode updatedNode = new OvsdbCapableNodeBuilder(ovsdbNode)
+ .setManagedNodes(managedNodesList)
+ .build();
+
+ // Write changes to DataStore
+ WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
+ // Create parent if we get to this node before openflowplugin
+ writeTx.put(LogicalDatastoreType.CONFIGURATION, openflowNodepath, ovsdbManagedNode, true);
+ writeTx.put(LogicalDatastoreType.CONFIGURATION, ovsdbNodePath, updatedNode);
+ writeTx.submit();
+ }
+ }
+
+ @Override
+ public synchronized void rowAdded(org.opendaylight.controller.sal.core.Node node, String tableName, String uuid, Row row) {
+ // noop
+ }
+}
--- /dev/null
+package org.opendaylight.ovsdb.plugin.md;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+
+/**
+ * Utilities to convert Java types to the types specified in the Yang models
+ */
+public final class Utils {
+
+ static final Logger logger = LoggerFactory.getLogger(Utils.class);
+
+ /**
+ * Returns a {@link org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress}
+ * from a @{link java.net.InetAddress}
+ */
+ public static IpAddress convertIpAddress(InetAddress inetAddress){
+
+ if (inetAddress instanceof Inet4Address){
+ Ipv4Address ipv4Address = new Ipv4Address(inetAddress.getHostAddress());
+ return new IpAddress(ipv4Address);
+ }
+ else {
+ Ipv6Address ipv6Address = new Ipv6Address(inetAddress.getHostAddress());
+ return new IpAddress(ipv6Address);
+ }
+ }
+}
--- /dev/null
+module ovsdb-node-inventory {
+ namespace "urn:opendaylight:ovsdb-node-inventory";
+ prefix "ovsdbinv";
+
+ import opendaylight-inventory {
+ prefix inv;
+ revision-date "2013-08-19";
+ }
+
+ import yang-ext {
+ prefix ext;
+ revision-date "2013-07-09";
+ }
+
+ import ietf-inet-types {
+ prefix inet;
+ revision-date "2010-09-24";
+ }
+
+ import flow-node-inventory {
+ prefix flowcapable;
+ revision-date "2013-08-19";
+ }
+
+ revision "2014-07-31" {
+ description "Initial revision of the OVSDB Inventory model";
+ }
+
+ grouping ovsdb-bridge-attributes {
+ leaf bridge-uuid {
+ description "The unique identifier of the bridge";
+ type string;
+ }
+
+ leaf bridge-name {
+ description "The name of the bridge";
+ type string;
+ }
+
+ leaf managed-by {
+ description "The OVSDB which this bridge belongs to";
+ type inv:node-id;
+ }
+ }
+
+ grouping ovsdb-node-attributes {
+ leaf ip-address {
+ description "The IP Address of an OVSDB node";
+ type inet:ip-address;
+ }
+
+ leaf port {
+ description "The port that an OVSDB node is connected on";
+ type inet:port-number;
+ }
+
+ leaf-list managed-nodes {
+ type inv:node-id;
+ }
+ }
+
+ augment /inv:nodes/inv:node {
+ ext:augment-identifier "ovsdb-managed-node";
+ // when "/inv:nodes/inv:node/flowcapable:manufacturer = '*'";
+ container ovsdb-bridge {
+ uses ovsdb-bridge-attributes;
+ }
+ }
+
+ augment /inv:nodes/inv:node {
+ ext:augment-identifier "ovsdb-capable-node";
+ uses ovsdb-node-attributes;
+ }
+
+}
--- /dev/null
+package org.opendaylight.ovsdb.plugin.md;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+public class UtilsTest {
+
+ static final String IPV4_ADDRESS = "10.10.10.10";
+ static final String IPV6_ADDRESS = "2001:db8:0:0:0:ff00:42:8329";
+
+ @Test
+ public void testConvertIpAddress() throws UnknownHostException {
+
+ InetAddress addressV4 = Inet4Address.getByName(IPV4_ADDRESS);
+ InetAddress addressV6 = Inet6Address.getByName(IPV6_ADDRESS);
+
+ IpAddress ipAddresV4 = Utils.convertIpAddress(addressV4);
+ IpAddress ipAddresV6 = Utils.convertIpAddress(addressV6);
+
+ Assert.assertEquals(IPV4_ADDRESS, ipAddresV4.getIpv4Address().getValue());
+ Assert.assertEquals(IPV6_ADDRESS, ipAddresV6.getIpv6Address().getValue());
+ }
+}
\ No newline at end of file
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.ovsdb.lib.notation.Row;
+import java.net.InetAddress;
+
public interface OvsdbInventoryListener {
- public void nodeAdded(Node node);
+ public void nodeAdded(Node node, InetAddress address, int port );
public void nodeRemoved(Node node);
public void rowAdded(Node node, String tableName, String uuid, Row row);
public void rowUpdated(Node node, String tableName, String uuid, Row old, Row row);
*/
package org.opendaylight.ovsdb.plugin.api;
+import java.net.InetAddress;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
public void removeRow(Node n, String databaseName, String tableName, String uuid);
public void processTableUpdates(Node n, String databaseName,TableUpdates tableUpdates);
public void printCache(Node n);
-
public void addNode(Node n, Set<Property> props);
- public void notifyNodeAdded(Node n);
+ public void notifyNodeAdded(Node n, InetAddress address, int port);
public void removeNode(Node n);
public void addNodeProperty(Node node, UpdateType type, Set<Property> props);
}
\ No newline at end of file
ovsdbInventoryService.processTableUpdates(connection.getNode(), dbSchema.getName(), updates);
}
logger.info("Notifying Inventory Listeners for Node Added: {}", connection.getNode().toString());
- ovsdbInventoryService.notifyNodeAdded(connection.getNode());
+ ovsdbInventoryService.notifyNodeAdded(connection.getNode(), address, port);
}
public TableUpdates monitorTables(Node node, DatabaseSchema dbSchema) throws ExecutionException, InterruptedException, IOException {
*/
package org.opendaylight.ovsdb.plugin.impl;
+import java.net.InetAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
}
@Override
- public void notifyNodeAdded(Node node) {
+ @Deprecated public void notifyNodeAdded(Node node) {
+ //noop
+ }
+
+
+ @Override
+ public void notifyNodeAdded(Node node, InetAddress address, int port) {
if (!ovsdbInventoryListeners.isEmpty()) {
for (OvsdbInventoryListener listener : ovsdbInventoryListeners) {
- listener.nodeAdded(node);
+ listener.nodeAdded(node, address, port);
}
}
}
<module>schemas/openvswitch</module>
<module>schemas/hardwarevtep</module>
<module>plugin</module>
+ <module>plugin-mdsal-adapter</module>
<module>northbound</module>
<module>openstack/net-virt</module>
<module>openstack/net-virt-providers</module>