Add MD-SAL Adapter for the OVSDB Plugin 89/9589/2
authorDave Tucker <djt@redhat.com>
Fri, 1 Aug 2014 19:42:14 +0000 (20:42 +0100)
committerDave Tucker <djt@redhat.com>
Mon, 4 Aug 2014 23:56:52 +0000 (00:56 +0100)
This commit adds an initial MD-SAL connector for OVSDB
The OvsdbInventoryManager updates the MD-SAL with nodes as they are
added and removed from inventory. The Yang model provides a reference
between OVSDB nodes and the OpenFlow nodes (bridges) that they manage

Also changes the nodeAdded API in OvsdbIventoryListener to pass the
IpAddress and Port number of the new node. This avoids having to query
the AD-SAL based properties set for this inforamtion

Change-Id: Ia2d8140c3f504d9b2d78b490bb273808f9a86c51
Signed-off-by: Dave Tucker <djt@redhat.com>
17 files changed:
commons/parent/pom.xml
distribution/opendaylight/pom.xml
integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/plugin/OvsdbPluginIT.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/SouthboundHandler.java
plugin-mdsal-adapter/pom.xml [new file with mode: 0644]
plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/Activator.java [new file with mode: 0644]
plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/OvsdbBindingAwareProvider.java [new file with mode: 0644]
plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/OvsdbBindingAwareProviderImpl.java [new file with mode: 0644]
plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/OvsdbInventoryManager.java [new file with mode: 0644]
plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/Utils.java [new file with mode: 0644]
plugin-mdsal-adapter/src/main/yang/ovsdb-node-inventory.yang [new file with mode: 0644]
plugin-mdsal-adapter/src/test/java/org/opendaylight/ovsdb/plugin/md/UtilsTest.java [new file with mode: 0644]
plugin/src/main/java/org/opendaylight/ovsdb/plugin/api/OvsdbInventoryListener.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/api/OvsdbInventoryService.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/impl/ConnectionServiceImpl.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/impl/InventoryServiceImpl.java
pom.xml

index a1d813e8bdb09b6074a906e72ab1c958f77a65bd..86c9bd181f099cb9f6f0da10d9b32660271c7e27 100755 (executable)
         <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>
index 8c1a28c23163dd685c6e9c52bb1e4c01af2ea4ac..bd407c7fe43bd4ac0e66b000e58df2d0ebedd50d 100755 (executable)
@@ -85,6 +85,10 @@ see https://git.opendaylight.org/gerrit/#/c/390/
       <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>
index 904d46d527ff58447adc79410062a5c7965eebc1..2557be552effda0eae2e0ca299080df62275907b 100644 (file)
@@ -20,16 +20,6 @@ import static org.ops4j.pax.exam.CoreOptions.options;
 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;
@@ -47,6 +37,13 @@ import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
 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;
@@ -57,8 +54,12 @@ import org.osgi.framework.BundleContext;
 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 {
@@ -174,7 +175,7 @@ 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);
@@ -191,12 +192,14 @@ public class OvsdbPluginIT extends OvsdbIntegrationTestBase {
         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);
@@ -260,7 +263,7 @@ public class OvsdbPluginIT extends OvsdbIntegrationTestBase {
     public class FakeListener implements OvsdbInventoryListener {
 
         @Override
-        public void nodeAdded(Node node) {
+        public void nodeAdded(Node node, InetAddress address, int port) {
 
         }
 
index 4177b7269293b25e8ad892c1c60858850f52c395..e85d9330fbb9c40a2ca0e9e90bd2ff095c05515c 100644 (file)
@@ -31,6 +31,7 @@ import com.google.common.collect.Lists;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.net.InetAddress;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -103,7 +104,7 @@ public class SouthboundHandler extends AbstractHandler implements OvsdbInventory
     }
 
     @Override
-    public void nodeAdded(Node node) {
+    public void nodeAdded(Node node, InetAddress address, int port) {
         this.enqueueEvent(new SouthboundEvent(node, SouthboundEvent.Action.ADD));
     }
 
diff --git a/plugin-mdsal-adapter/pom.xml b/plugin-mdsal-adapter/pom.xml
new file mode 100644 (file)
index 0000000..1b2cdac
--- /dev/null
@@ -0,0 +1,104 @@
+<?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
diff --git a/plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/Activator.java b/plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/Activator.java
new file mode 100644 (file)
index 0000000..28d8621
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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));
+        }
+    }
+}
diff --git a/plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/OvsdbBindingAwareProvider.java b/plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/OvsdbBindingAwareProvider.java
new file mode 100644 (file)
index 0000000..d4fac1c
--- /dev/null
@@ -0,0 +1,12 @@
+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();
+}
diff --git a/plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/OvsdbBindingAwareProviderImpl.java b/plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/OvsdbBindingAwareProviderImpl.java
new file mode 100644 (file)
index 0000000..78158d9
--- /dev/null
@@ -0,0 +1,50 @@
+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;
+    }
+}
diff --git a/plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/OvsdbInventoryManager.java b/plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/OvsdbInventoryManager.java
new file mode 100644 (file)
index 0000000..3c5df15
--- /dev/null
@@ -0,0 +1,259 @@
+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
+    }
+}
diff --git a/plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/Utils.java b/plugin-mdsal-adapter/src/main/java/org/opendaylight/ovsdb/plugin/md/Utils.java
new file mode 100644 (file)
index 0000000..c1644f0
--- /dev/null
@@ -0,0 +1,35 @@
+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);
+        }
+    }
+}
diff --git a/plugin-mdsal-adapter/src/main/yang/ovsdb-node-inventory.yang b/plugin-mdsal-adapter/src/main/yang/ovsdb-node-inventory.yang
new file mode 100644 (file)
index 0000000..d64e1e5
--- /dev/null
@@ -0,0 +1,75 @@
+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;
+    }
+
+}
diff --git a/plugin-mdsal-adapter/src/test/java/org/opendaylight/ovsdb/plugin/md/UtilsTest.java b/plugin-mdsal-adapter/src/test/java/org/opendaylight/ovsdb/plugin/md/UtilsTest.java
new file mode 100644 (file)
index 0000000..15f4eba
--- /dev/null
@@ -0,0 +1,30 @@
+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
index 4c7d239f607760bb786a995a94707c037c3ee167..cf61202d9bc7758eb8ba21039a024bbd602450e9 100644 (file)
@@ -12,8 +12,10 @@ package org.opendaylight.ovsdb.plugin.api;
 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);
index 8c41e352ebd68f348b7db9abe659cb48b0a5c295..cb086ee1a2a5b7fb539a42ee3945a152efeb3b3e 100644 (file)
@@ -9,6 +9,7 @@
  */
 package org.opendaylight.ovsdb.plugin.api;
 
+import java.net.InetAddress;
 import java.util.Set;
 import java.util.concurrent.ConcurrentMap;
 
@@ -27,9 +28,8 @@ public interface OvsdbInventoryService extends IPluginInInventoryService {
     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
index e4b49a6005b86609d9b80ec7f928aba4beaf2dc8..64a0fa1e9a77237bd2611bd1d327067ba18f3217 100644 (file)
@@ -251,7 +251,7 @@ public class ConnectionServiceImpl implements IPluginInConnectionService,
             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 {
index 5f5c437d92131b13868e6eac5dda7ad2d0b54f51..ed7a65797d5ce8e4654cf891cc7a222453e70111 100644 (file)
@@ -9,6 +9,7 @@
  */
 package org.opendaylight.ovsdb.plugin.impl;
 
+import java.net.InetAddress;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -282,10 +283,16 @@ public class InventoryServiceImpl implements IPluginInInventoryService,
     }
 
     @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);
             }
         }
     }
diff --git a/pom.xml b/pom.xml
index e4044dad8fa00cead93b94f789e78f3b22f1c4c0..25ac506fb539c3d2112f0c0f3c1e5616c3f62304 100755 (executable)
--- a/pom.xml
+++ b/pom.xml
@@ -26,6 +26,7 @@
     <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>