Updating OpenFlow Node Description that is learnt from the OVSDB bridge table. 87/2587/1
authorMadhu Venugopal <mavenugo@gmail.com>
Sun, 10 Nov 2013 17:19:11 +0000 (09:19 -0800)
committerMadhu Venugopal <mavenugo@gmail.com>
Sun, 10 Nov 2013 17:19:11 +0000 (09:19 -0800)
In order to compensate for a bug in the way Openflow plugin overrides a null value on the switchmanage node description,
this fix also adds a scheduled reexecution of the description update message after a few seconds to make sure the updates
are not lost.

Change-Id: I605a2ff237d13cb72cdeb60ecf55ad19295c3133
Signed-off-by: Madhu Venugopal <mavenugo@gmail.com>
ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/ConnectionService.java
ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/InventoryService.java

index 7449d6da7b60b2b5431ed9bb04d42863565d2b1f..61f64b65f04c719ada181f696147b71dcefea4d9 100755 (executable)
@@ -2,7 +2,13 @@ package org.opendaylight.ovsdb.plugin;
 
 import io.netty.bootstrap.Bootstrap;
 import io.netty.bootstrap.ServerBootstrap;
-import io.netty.channel.*;
+import io.netty.channel.AdaptiveRecvByteBufAllocator;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.channel.socket.nio.NioServerSocketChannel;
@@ -12,6 +18,17 @@ import io.netty.handler.logging.LogLevel;
 import io.netty.handler.logging.LoggingHandler;
 import io.netty.util.CharsetUtil;
 
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+
 import org.opendaylight.controller.sal.connection.ConnectionConstants;
 import org.opendaylight.controller.sal.connection.IPluginInConnectionService;
 import org.opendaylight.controller.sal.core.Node;
@@ -37,17 +54,6 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.util.concurrent.ListenableFuture;
 
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-
 
 /**
  * Represents the openflow plugin component in charge of programming the flows
@@ -108,7 +114,7 @@ public class ConnectionService implements IPluginInConnectionService, IConnectio
      * the component are unregistered, this will be followed by a "destroy ()"
      * calls
      */
-    void stop() {
+    void stopping() {
         for (Connection connection : ovsdbConnections.values()) {
             connection.disconnect();
         }
@@ -228,6 +234,7 @@ public class ConnectionService implements IPluginInConnectionService, IConnectio
             Connection connection;
             String identifier;
 
+            @Override
             public void run() {
                 try {
                     initializeInventoryForNewNode(connection);
@@ -291,6 +298,7 @@ public class ConnectionService implements IPluginInConnectionService, IConnectio
 
     private void startOvsdbManager() {
         new Thread() {
+            @Override
             public void run() {
                 ovsdbManager();
             }
index 86106166b4e0d32946f5420f764b9ca0ffdd03ff..f92eeed5225deb815eb8fdbe20f01596ee014eaa 100755 (executable)
@@ -2,25 +2,35 @@ package org.opendaylight.ovsdb.plugin;
 
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.Description;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.core.UpdateType;
 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
 import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.ovsdb.lib.database.DatabaseSchema;
 import org.opendaylight.ovsdb.lib.message.TableUpdate;
 import org.opendaylight.ovsdb.lib.message.TableUpdate.Row;
 import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
+import org.opendaylight.ovsdb.lib.table.Bridge;
 import org.opendaylight.ovsdb.lib.table.internal.Table;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.Maps;
 
@@ -37,6 +47,7 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
     private ConcurrentMap<Node, Map<String, Property>> nodeProps;
     private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps;
     private Map<Node, NodeDB> dbCache = Maps.newHashMap();
+    private ScheduledExecutorService executor;
 
     /**
      * Function called by the dependency manager when all the required
@@ -48,6 +59,7 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
         nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
         Node.NodeIDType.registerIDType("OVS", String.class);
         NodeConnector.NodeConnectorIDType.registerIDType("OVS", String.class, "OVS");
+        this.executor = Executors.newSingleThreadScheduledExecutor();
     }
 
     /**
@@ -74,6 +86,7 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
      *
      */
     public void stop() {
+        this.executor.shutdownNow();
     }
 
     public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
@@ -164,6 +177,14 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
                 Table<?> oldRow = (Table<?>)row.getOld();
                 if (newRow != null) {
                     db.updateRow(name.getName(), uuid, newRow);
+                    if (name.getName().equalsIgnoreCase("bridge")) {
+                        logger.debug("Received Bridge Table udpate for node {}", n);
+                        // OVSDB has the Bridge name info while OpenFlow Spec is not
+                        // Clear on that. From a user/manageability standpoint, it is easier
+                        // to handle Bridge names compared to dpids.
+                        // Updating the Openflow bridge name via the SAL Description update.
+                        updateOFBridgeName(n, (Bridge)newRow);
+                    }
                 } else if (oldRow != null) {
                     db.removeRow(name.getName(), uuid);
                 }
@@ -171,6 +192,42 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
         }
     }
 
+    private void updateOFBridgeName(final Node node, final Bridge bridge) {
+        Runnable updateNameRunnable = new Runnable() {
+            @Override
+            public void run() {
+                OvsDBSet<String> dpids = bridge.getDatapath_id();
+                String bridgeName = bridge.getName();
+                if (dpids == null || bridgeName == null) return;
+                for (String dpid : dpids) {
+                    Long dpidLong = Long.valueOf(HexEncode.stringToLong(dpid));
+                    try {
+                        Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+                        Description descProp = new Description(bridgeName);
+                        Set<Property> props = new HashSet<Property>();
+                        props.add(descProp);
+
+                        IPluginOutInventoryService salInventoryService = (IPluginOutInventoryService) ServiceHelper.getInstance(
+                                IPluginOutInventoryService.class, "default", this);
+                        if (salInventoryService != null) {
+                            logger.debug("Updating Bridge Name {} on OF node {}", bridgeName, ofNode);
+                            salInventoryService.updateNode(ofNode, UpdateType.CHANGED, props);
+                        } else {
+                            logger.error("Error accessing SAL Inventory plugin");
+                        }
+                    } catch (ConstructionException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        };
+        executor.execute(updateNameRunnable);
+        // Add a delay & re-execute to compensate for the current OpenFlow plugin bug of
+        // overriding the Description with a Null value after the first statistics timer.
+        // Hopefully this will be resolved in the newer version of the Openflow plugin.
+        executor.schedule(updateNameRunnable, 30, TimeUnit.SECONDS);
+    }
+
     @Override
     public void printCache(Node n) {
         NodeDB db = dbCache.get(n);