Add 'TableStatistics' to SAL and Northbound Statistics API. 18/418/6
authorAditya Prakash Vaja <aditya.vaja@bigswitch.com>
Fri, 31 May 2013 19:28:15 +0000 (12:28 -0700)
committerAditya Prakash Vaja <aditya.vaja@bigswitch.com>
Sat, 1 Jun 2013 19:27:10 +0000 (12:27 -0700)
It is similar to the FlowStats and PortStats (NodeConnectorStats) that are present now.

Change-Id: Ibecb95c9c4a4f911e5fd3847bbf1f2e77eb16be1
Signed-off-by: Aditya Prakash Vaja <aditya.vaja@bigswitch.com>
23 files changed:
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/AllTableStatistics.java [new file with mode: 0644]
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthbound.java
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/TableStatistics.java [new file with mode: 0644]
opendaylight/northbound/statistics/src/test/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthboundTest.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IOFStatisticsManager.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IPluginReadServiceFilter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadService.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TableConverter.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TableStatisticsConverter.java [new file with mode: 0644]
opendaylight/protocol_plugins/stub/src/main/java/org/opendaylight/controller/protocol_plugins/stub/internal/ReadService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/NodeTable.java [new file with mode: 0644]
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IPluginInReadService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IReadService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/NodeTableStatistics.java [new file with mode: 0644]
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeTableCreator.java [new file with mode: 0644]
opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/core/NodeTableTest.java [new file with mode: 0644]
opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/reader/NodeTableStatisticsTest.java [new file with mode: 0644]
opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ReadService.java
opendaylight/statisticsmanager/api/src/main/java/org/opendaylight/controller/statisticsmanager/IStatisticsManager.java
opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java

index df4526e6f9cbac41fc4df3b07de19dc12caee8fd..a8d7beb49b560c65f0c52c03271b31f3704cd318 100644 (file)
@@ -56,6 +56,8 @@ org.eclipse.gemini.web.tomcat.config.path=configuration/tomcat-server.xml
 # of.portStatsPollInterval=5
 # The description statistics polling interval in second (default 60 sec)
 # of.descStatsPollInterval=60
 # of.portStatsPollInterval=5
 # The description statistics polling interval in second (default 60 sec)
 # of.descStatsPollInterval=60
+# The table statistics polling interval in second (default 10 sec)
+#  of.tableStatsPollInterval=10
 # The maximum number of asynchronous messages can be sent before sending a Barrier Request (default 100)
 # of.barrierMessagePriorCount=100
 # The interval which determines how often the discovery packets should be sent (default 300 sec)
 # The maximum number of asynchronous messages can be sent before sending a Barrier Request (default 100)
 # of.barrierMessagePriorCount=100
 # The interval which determines how often the discovery packets should be sent (default 300 sec)
diff --git a/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/AllTableStatistics.java b/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/AllTableStatistics.java
new file mode 100644 (file)
index 0000000..5b998ee
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Big Switch Networks, Inc.  All rights reserved.
+ *
+ * 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
+ */
+package org.opendaylight.controller.statistics.northbound;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class AllTableStatistics {
+    @XmlElement
+    List<TableStatistics> tableStatistics;
+    //To satisfy JAXB
+    private AllTableStatistics() {
+    }
+
+    public AllTableStatistics(List<TableStatistics> tableStatistics) {
+        this.tableStatistics = tableStatistics;
+    }
+
+    public List<TableStatistics> getTableStatistics() {
+        return tableStatistics;
+    }
+
+    public void setTableStatistics(List<TableStatistics> tableStatistics) {
+        this.tableStatistics = tableStatistics;
+    }
+
+}
index 5cddc663c69283bd61b097ec6137da97736589e5..dee52932bda41ed77ca5b0be273bae94886b791e 100644 (file)
@@ -31,6 +31,7 @@ import org.opendaylight.controller.sal.authorization.Privilege;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
@@ -113,9 +114,9 @@ public class StatisticsNorthbound {
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(AllFlowStatistics.class)
     @StatusCodes({
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(AllFlowStatistics.class)
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Operation successful"),
-            @ResponseCode(code = 404, condition = "The containerName is not found"),
-            @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 404, condition = "The containerName is not found"),
+        @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public AllFlowStatistics getFlowStatistics(
             @PathParam("containerName") String containerName) {
         if (!NorthboundUtils.isAuthorized(
     public AllFlowStatistics getFlowStatistics(
             @PathParam("containerName") String containerName) {
         if (!NorthboundUtils.isAuthorized(
@@ -168,9 +169,9 @@ public class StatisticsNorthbound {
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(FlowStatistics.class)
     @StatusCodes({
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(FlowStatistics.class)
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Operation successful"),
-            @ResponseCode(code = 404, condition = "The containerName is not found"),
-            @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 404, condition = "The containerName is not found"),
+        @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public FlowStatistics getFlowStatistics(
             @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
     public FlowStatistics getFlowStatistics(
             @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
@@ -216,9 +217,9 @@ public class StatisticsNorthbound {
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(AllPortStatistics.class)
     @StatusCodes({
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(AllPortStatistics.class)
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Operation successful"),
-            @ResponseCode(code = 404, condition = "The containerName is not found"),
-            @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 404, condition = "The containerName is not found"),
+        @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public AllPortStatistics getPortStatistics(
             @PathParam("containerName") String containerName) {
 
     public AllPortStatistics getPortStatistics(
             @PathParam("containerName") String containerName) {
 
@@ -270,9 +271,9 @@ public class StatisticsNorthbound {
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(PortStatistics.class)
     @StatusCodes({
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(PortStatistics.class)
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Operation successful"),
-            @ResponseCode(code = 404, condition = "The containerName is not found"),
-            @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 404, condition = "The containerName is not found"),
+        @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public PortStatistics getPortStatistics(
             @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
     public PortStatistics getPortStatistics(
             @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
@@ -304,6 +305,108 @@ public class StatisticsNorthbound {
                 statisticsManager.getNodeConnectorStatistics(node));
     }
 
                 statisticsManager.getNodeConnectorStatistics(node));
     }
 
+    /**
+     * Returns a list of all the Table Statistics on all Nodes.
+     *
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     *
+     * @return Returns a list of all the Table Statistics in a given Node.
+     */
+    @Path("/{containerName}/tablestats")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(TableStatistics.class)
+    @StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 404, condition = "The containerName is not found"),
+        @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+    public AllTableStatistics getTableStatistics(
+            @PathParam("containerName") String containerName) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+        handleDefaultDisabled(containerName);
+
+        IStatisticsManager statisticsManager = getStatisticsService(containerName);
+        if (statisticsManager == null) {
+            throw new ServiceUnavailableException("Statistics "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+                .getInstance(ISwitchManager.class, containerName, this);
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        List<TableStatistics> statistics = new ArrayList<TableStatistics>();
+        for (Node node : switchManager.getNodes()) {
+            List<NodeTableStatistics> stat = statisticsManager
+                    .getNodeTableStatistics(node);
+            TableStatistics tableStat = new TableStatistics(node, stat);
+            statistics.add(tableStat);
+        }
+        return new AllTableStatistics(statistics);
+    }
+
+    /**
+     * Returns a list of all the Table Statistics on all Nodes.
+     *
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param nodeType
+     *            Node Type as specifid by Node class
+     * @param Node
+     *            Identifier
+     * @return Returns a list of all the Table Statistics in a given Node.
+     */
+    @Path("/{containerName}/tablestats/{nodeType}/{nodeId}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(TableStatistics.class)
+    @StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 404, condition = "The containerName is not found"),
+        @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+    public TableStatistics getTableStatistics(
+            @PathParam("containerName") String containerName,
+            @PathParam("nodeType") String nodeType,
+            @PathParam("nodeId") String nodeId) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+        handleDefaultDisabled(containerName);
+
+        IStatisticsManager statisticsManager = getStatisticsService(containerName);
+        if (statisticsManager == null) {
+            throw new ServiceUnavailableException("Statistics "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+                .getInstance(ISwitchManager.class, containerName, this);
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        Node node = handleNodeAvailability(containerName, nodeType, nodeId);
+        return new TableStatistics(node,
+                statisticsManager.getNodeTableStatistics(node));
+    }
+
     private void handleDefaultDisabled(String containerName) {
         IContainerManager containerManager = (IContainerManager) ServiceHelper
                 .getGlobalInstance(IContainerManager.class, this);
     private void handleDefaultDisabled(String containerName) {
         IContainerManager containerManager = (IContainerManager) ServiceHelper
                 .getGlobalInstance(IContainerManager.class, this);
diff --git a/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/TableStatistics.java b/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/TableStatistics.java
new file mode 100644 (file)
index 0000000..a1c2019
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013 Big Switch Networks, Inc.  All rights reserved.
+ *
+ * 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
+ */
+package org.opendaylight.controller.statistics.northbound;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class TableStatistics {
+    @XmlElement
+    private Node node;
+    @XmlElement(name="tableStat")
+    private List<NodeTableStatistics> tableStats;
+
+    // To satisfy JAXB
+    @SuppressWarnings("unused")
+    private TableStatistics() {
+    }
+
+    public TableStatistics(Node node, List<NodeTableStatistics> tableStats) {
+        super();
+        this.node = node;
+        this.tableStats = tableStats;
+    }
+
+    public Node getNode() {
+        return node;
+    }
+
+    public void setNode(Node node) {
+        this.node = node;
+    }
+
+    public List<NodeTableStatistics> getTableStats() {
+        return tableStats;
+    }
+
+    public void setTableStats(List<NodeTableStatistics> tableStats) {
+        this.tableStats = tableStats;
+    }
+
+}
index 3790ae8ea925f9b92a7caefc6d1d9170e92a2520..0764c0b0077d25f9d33e2d173079a16e2bae9078 100644 (file)
@@ -1,17 +1,27 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * 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
+ */
+
 package org.opendaylight.controller.statistics.northbound;
 
 import java.util.ArrayList;
 import java.util.List;
 
 package org.opendaylight.controller.statistics.northbound;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import junit.framework.TestCase;
+
 import org.junit.Assert;
 import org.junit.Test;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.junit.Assert;
 import org.junit.Test;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 import org.opendaylight.controller.sal.utils.NodeCreator;
 
 import org.opendaylight.controller.sal.utils.NodeCreator;
 
-import junit.framework.TestCase;
-
 public class StatisticsNorthboundTest extends TestCase {
 
     @Test
 public class StatisticsNorthboundTest extends TestCase {
 
     @Test
@@ -64,4 +74,28 @@ public class StatisticsNorthboundTest extends TestCase {
         Assert.assertTrue(aps.getPortStatistics() == null);
     }
 
         Assert.assertTrue(aps.getPortStatistics() == null);
     }
 
+    @Test
+    public void testTableStatistics() {
+        List<NodeTableStatistics> nts = new ArrayList<NodeTableStatistics>();
+        Node node = NodeCreator.createOFNode(1L);
+        TableStatistics ts = new TableStatistics(node, nts);
+
+        Assert.assertTrue(ts.getNode().equals(node));
+        Assert.assertTrue(ts.getTableStats().equals(nts));
+        Node node2 = NodeCreator.createOFNode(2L);
+        ts.setNode(node2);
+        Assert.assertTrue(ts.getNode().equals(node2));
+        ts.setTableStats(null);
+        Assert.assertTrue(ts.getTableStats() == null);
+    }
+
+    @Test
+    public void testAllTableStatistics() {
+        List<TableStatistics> ts = new ArrayList<TableStatistics>();
+        AllTableStatistics ats = new AllTableStatistics(ts);
+        Assert.assertTrue(ats.getTableStatistics().equals(ts));
+        ats.setTableStatistics(null);
+        Assert.assertTrue(ats.getTableStatistics() == null);
+    }
+
 }
 }
index 18fe686dd5be1dbf98bbafea3841b9803e7fbd93..74dc84aec9613671bb24a17bfd38f788b5c8f35d 100644 (file)
@@ -22,9 +22,9 @@ public interface IOFStatisticsManager {
     /**
      * Return all the statistics for all the flows present on the specified switch
      *
     /**
      * Return all the statistics for all the flows present on the specified switch
      *
-        * @param switchId the openflow datapath id
-        * @return      the list of openflow statistics
-        */
+     * @param switchId the openflow datapath id
+     * @return the list of openflow statistics
+     */
     List<OFStatistics> getOFFlowStatistics(Long switchId);
 
     /**
     List<OFStatistics> getOFFlowStatistics(Long switchId);
 
     /**
@@ -39,7 +39,7 @@ public interface IOFStatisticsManager {
     /**
      * Return the description statistics for the specified switch.
      *
     /**
      * Return the description statistics for the specified switch.
      *
-        * @param switchId the openflow datapath id
+     * @param switchId the openflow datapath id
      * @return the list of openflow statistics
      */
     List<OFStatistics> getOFDescStatistics(Long switchId);
      * @return the list of openflow statistics
      */
     List<OFStatistics> getOFDescStatistics(Long switchId);
@@ -47,7 +47,7 @@ public interface IOFStatisticsManager {
     /**
      * Returns the statistics for all the ports on the specified switch
      *
     /**
      * Returns the statistics for all the ports on the specified switch
      *
-        * @param switchId the openflow datapath id
+     * @param switchId the openflow datapath id
      * @return the list of openflow statistics
      */
     List<OFStatistics> getOFPortStatistics(Long switchId);
      * @return the list of openflow statistics
      */
     List<OFStatistics> getOFPortStatistics(Long switchId);
@@ -55,7 +55,7 @@ public interface IOFStatisticsManager {
     /**
      * Returns the statistics for the specified switch port
      *
     /**
      * Returns the statistics for the specified switch port
      *
-        * @param switchId the openflow datapath id
+     * @param switchId the openflow datapath id
      * @param portId the openflow switch port id
      * @return the list of openflow statistics
      */
      * @param portId the openflow switch port id
      * @return the list of openflow statistics
      */
@@ -64,7 +64,7 @@ public interface IOFStatisticsManager {
     /**
      * Returns the number of flows installed on the switch
      *
     /**
      * Returns the number of flows installed on the switch
      *
-        * @param switchId the openflow datapath id
+     * @param switchId the openflow datapath id
      * @return the number of flows installed on the switch
      */
     int getFlowsNumber(long switchId);
      * @return the number of flows installed on the switch
      */
     int getFlowsNumber(long switchId);
@@ -77,12 +77,12 @@ public interface IOFStatisticsManager {
      * @param switchId the openflow datapath id of the target switch
      * @param statType the openflow statistics type
      * @param target the target object. For flow statistics it is the OFMatch.
      * @param switchId the openflow datapath id of the target switch
      * @param statType the openflow statistics type
      * @param target the target object. For flow statistics it is the OFMatch.
-     *                                  For port statistics, it is the port id. If null the query
-     *                                  will be performed for all the targets for the specified
-     *                                  statistics type. 
-     *                                  
+     *                                  For port statistics, it is the port id. If null the query
+     *                                  will be performed for all the targets for the specified
+     *                                  statistics type.
+     * 
      * @param timeout the timeout in milliseconds the system will wait for a response
      * @param timeout the timeout in milliseconds the system will wait for a response
-     *                   from the switch, before declaring failure 
+     *                  from the switch, before declaring failure
      * @return the list of openflow statistics
      */
     List<OFStatistics> queryStatistics(Long switchId,
      * @return the list of openflow statistics
      */
     List<OFStatistics> queryStatistics(Long switchId,
@@ -97,4 +97,21 @@ public interface IOFStatisticsManager {
      */
     long getTransmitRate(Long switchId, Short port);
 
      */
     long getTransmitRate(Long switchId, Short port);
 
+    /**
+     * Returns the statistics for the specified switch table
+     *
+     * @param switchId the openflow datapath id
+     * @param tableId the openflow switch table id
+     * @return the list of openflow statistics
+     */
+    List<OFStatistics> getOFTableStatistics(Long switchId, Byte tableId);
+
+    /**
+     * Returns all the table statistics for the node specified
+     *
+     * @param switchId the openflow datapath id
+     * @return the list of openflow statistics
+     */
+    List<OFStatistics> getOFTableStatistics(Long switchId);
+
 }
 }
index a000024e9e0c7e5355e49e668cb966f71f004080..af474f0e67215492f29418ed66628bf6d3b2833b 100644 (file)
@@ -13,10 +13,12 @@ import java.util.List;
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 
 /**
  * Interface to serve the hardware information requests coming from SAL
 
 /**
  * Interface to serve the hardware information requests coming from SAL
@@ -77,6 +79,24 @@ public interface IPluginReadServiceFilter {
     public List<NodeConnectorStatistics> readAllNodeConnector(String container,
             Node node, boolean cached);
 
     public List<NodeConnectorStatistics> readAllNodeConnector(String container,
             Node node, boolean cached);
 
+    /**
+     * Returns the table statistics of the node as specified by the given container
+     * @param node
+     * @param cached
+     * @return
+     */
+    public NodeTableStatistics readNodeTable(String container,
+            NodeTable nodeTable, boolean cached);
+
+    /**
+     * Returns the table statistics of all the tables for the specified node
+     *
+     * @param node
+     * @return
+     */
+    public List<NodeTableStatistics> readAllNodeTable(String containerName,
+            Node node, boolean cached);
+
     /**
      * Returns the average transmit rate for the specified node conenctor on
      * the given container. If the node connector does not belong to the passed
     /**
      * Returns the average transmit rate for the specified node conenctor on
      * the given container. If the node connector does not belong to the passed
index d6100e3fdc499c2bd53eb9eb45c414c70e8517d1..78fddc773637c8aefb338b729d4e416e66e85441 100644 (file)
@@ -54,6 +54,7 @@ import org.openflow.protocol.statistics.OFPortStatisticsRequest;
 import org.openflow.protocol.statistics.OFQueueStatisticsRequest;
 import org.openflow.protocol.statistics.OFStatistics;
 import org.openflow.protocol.statistics.OFStatisticsType;
 import org.openflow.protocol.statistics.OFQueueStatisticsRequest;
 import org.openflow.protocol.statistics.OFStatistics;
 import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.protocol.statistics.OFTableStatistics;
 import org.openflow.protocol.statistics.OFVendorStatistics;
 import org.openflow.util.HexString;
 import org.osgi.framework.BundleContext;
 import org.openflow.protocol.statistics.OFVendorStatistics;
 import org.openflow.util.HexString;
 import org.osgi.framework.BundleContext;
@@ -67,23 +68,26 @@ import org.slf4j.LoggerFactory;
  * provides an API to directly query the switch about the statistics
  */
 public class OFStatisticsManager implements IOFStatisticsManager,
  * provides an API to directly query the switch about the statistics
  */
 public class OFStatisticsManager implements IOFStatisticsManager,
-        IInventoryShimExternalListener, CommandProvider {
+IInventoryShimExternalListener, CommandProvider {
     private static final Logger log = LoggerFactory
             .getLogger(OFStatisticsManager.class);
     private static final int initialSize = 64;
     private static final long flowStatsPeriod = 10000;
     private static final long descriptionStatsPeriod = 60000;
     private static final long portStatsPeriod = 5000;
     private static final Logger log = LoggerFactory
             .getLogger(OFStatisticsManager.class);
     private static final int initialSize = 64;
     private static final long flowStatsPeriod = 10000;
     private static final long descriptionStatsPeriod = 60000;
     private static final long portStatsPeriod = 5000;
+    private static final long tableStatsPeriod = 10000;
     private static final long tickPeriod = 1000;
     private static short statisticsTickNumber = (short) (flowStatsPeriod / tickPeriod);
     private static short descriptionTickNumber = (short) (descriptionStatsPeriod / tickPeriod);
     private static short portTickNumber = (short) (portStatsPeriod / tickPeriod);
     private static final long tickPeriod = 1000;
     private static short statisticsTickNumber = (short) (flowStatsPeriod / tickPeriod);
     private static short descriptionTickNumber = (short) (descriptionStatsPeriod / tickPeriod);
     private static short portTickNumber = (short) (portStatsPeriod / tickPeriod);
+    private static short tableTickNumber = (short) (tableStatsPeriod / tickPeriod);
     private static short factoredSamples = (short) 2;
     private static short counter = 1;
     private IController controller = null;
     private ConcurrentMap<Long, List<OFStatistics>> flowStatistics;
     private ConcurrentMap<Long, List<OFStatistics>> descStatistics;
     private ConcurrentMap<Long, List<OFStatistics>> portStatistics;
     private static short factoredSamples = (short) 2;
     private static short counter = 1;
     private IController controller = null;
     private ConcurrentMap<Long, List<OFStatistics>> flowStatistics;
     private ConcurrentMap<Long, List<OFStatistics>> descStatistics;
     private ConcurrentMap<Long, List<OFStatistics>> portStatistics;
+    private ConcurrentMap<Long, List<OFStatistics>> tableStatistics;
     private List<OFStatistics> dummyList;
     private ConcurrentMap<Long, StatisticsTicks> statisticsTimerTicks;
     protected BlockingQueue<StatsRequest> pendingStatsRequests;
     private List<OFStatistics> dummyList;
     private ConcurrentMap<Long, StatisticsTicks> statisticsTimerTicks;
     protected BlockingQueue<StatsRequest> pendingStatsRequests;
@@ -164,6 +168,7 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         flowStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
         descStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
         portStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
         flowStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
         descStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
         portStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
+        tableStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
         dummyList = new ArrayList<OFStatistics>(1);
         statisticsTimerTicks = new ConcurrentHashMap<Long, StatisticsTicks>(
                 initialSize);
         dummyList = new ArrayList<OFStatistics>(1);
         statisticsTimerTicks = new ConcurrentHashMap<Long, StatisticsTicks>(
                 initialSize);
@@ -283,6 +288,7 @@ public class OFStatisticsManager implements IOFStatisticsManager,
             type = t;
         }
 
             type = t;
         }
 
+        @Override
         public String toString() {
             return "SReq = {switchId=" + switchId + ", type=" + type + "}";
         }
         public String toString() {
             return "SReq = {switchId=" + switchId + ", type=" + type + "}";
         }
@@ -339,6 +345,7 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         private short flowStatisticsTicks;
         private short descriptionTicks;
         private short portStatisticsTicks;
         private short flowStatisticsTicks;
         private short descriptionTicks;
         private short portStatisticsTicks;
+        private short tableStatisticsTicks;
 
         public StatisticsTicks(boolean scattered) {
             if (scattered) {
 
         public StatisticsTicks(boolean scattered) {
             if (scattered) {
@@ -350,10 +357,12 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                         % statisticsTickNumber);
                 descriptionTicks = (short) (1 + counter % descriptionTickNumber);
                 portStatisticsTicks = (short) (1 + counter % portTickNumber);
                         % statisticsTickNumber);
                 descriptionTicks = (short) (1 + counter % descriptionTickNumber);
                 portStatisticsTicks = (short) (1 + counter % portTickNumber);
+                tableStatisticsTicks = (short) (1 + counter % tableTickNumber);
             } else {
                 flowStatisticsTicks = statisticsTickNumber;
                 descriptionTicks = descriptionTickNumber;
                 portStatisticsTicks = portTickNumber;
             } else {
                 flowStatisticsTicks = statisticsTickNumber;
                 descriptionTicks = descriptionTickNumber;
                 portStatisticsTicks = portTickNumber;
+                tableStatisticsTicks = tableTickNumber;
             }
         }
 
             }
         }
 
@@ -387,9 +396,20 @@ public class OFStatisticsManager implements IOFStatisticsManager,
             return false;
         }
 
             return false;
         }
 
+        public boolean decrementTableTicksIsZero() {
+            // Please ensure no code is inserted between the if check and the
+            // descriptionTicks reset
+            if(--tableStatisticsTicks == 0) {
+                tableStatisticsTicks = tableTickNumber;
+                return true;
+            }
+            return false;
+        }
+
+        @Override
         public String toString() {
             return "{fT=" + flowStatisticsTicks + ",dT=" + descriptionTicks
         public String toString() {
             return "{fT=" + flowStatisticsTicks + ",dT=" + descriptionTicks
-                    + ",pT=" + portStatisticsTicks + "}";
+                    + ",pT=" + portStatisticsTicks + ",tT=" + tableStatisticsTicks + "}";
         }
     }
 
         }
     }
 
@@ -438,6 +458,16 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                     printInfoMessage("Port", request);
                 }
             }
                     printInfoMessage("Port", request);
                 }
             }
+
+            if(clock.decrementTableTicksIsZero() == true) {
+                request = new StatsRequest(switchId, OFStatisticsType.TABLE);
+                // If a request for this switch is already in the queue, skip to
+                // add this new request
+                if (!pendingStatsRequests.contains(request)
+                        && false == pendingStatsRequests.offer(request)) {
+                    printInfoMessage("Table", request);
+                }
+            }
         }
     }
 
         }
     }
 
@@ -454,6 +484,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                 OFStatisticsType.DESC));
         pendingStatsRequests.remove(new StatsRequest(switchId,
                 OFStatisticsType.PORT));
                 OFStatisticsType.DESC));
         pendingStatsRequests.remove(new StatsRequest(switchId,
                 OFStatisticsType.PORT));
+        pendingStatsRequests.remove(new StatsRequest(switchId,
+                OFStatisticsType.TABLE));
         // Take care of the TX rate databases
         switchPortStatsUpdated.remove(switchId);
         txRates.remove(switchId);
         // Take care of the TX rate databases
         switchPortStatsUpdated.remove(switchId);
         txRates.remove(switchId);
@@ -491,6 +523,9 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                 // Wake up the thread which maintains the TX byte counters for
                 // each port
                 switchPortStatsUpdated.offer(switchId);
                 // Wake up the thread which maintains the TX byte counters for
                 // each port
                 switchPortStatsUpdated.offer(switchId);
+            } else if (statType == OFStatisticsType.TABLE) {
+                // Overwrite cache
+                tableStatistics.put(switchId, values);
             }
         }
     }
             }
         }
     }
@@ -591,6 +626,20 @@ public class OFStatisticsManager implements IOFStatisticsManager,
             } else if (statsType == OFStatisticsType.DESC) {
                 type = "DESC";
             } else if (statsType == OFStatisticsType.TABLE) {
             } else if (statsType == OFStatisticsType.DESC) {
                 type = "DESC";
             } else if (statsType == OFStatisticsType.TABLE) {
+                if(target != null){
+                    if (!(target instanceof Byte)) {
+                        // Malformed request
+                        log.warn("Invalid table id for table stats request: {}",
+                                target.getClass());
+                        return null;
+                    }
+                    byte targetTable = (Byte) target;
+                    OFTableStatistics specificReq = new OFTableStatistics();
+                    specificReq.setTableId(targetTable);
+                    req.setStatistics(Collections
+                            .singletonList((OFStatistics) specificReq));
+                    requestLength += specificReq.getLength();
+                }
                 type = "TABLE";
             }
             req.setLengthU(requestLength);
                 type = "TABLE";
             }
             req.setLengthU(requestLength);
@@ -602,7 +651,7 @@ public class OFStatisticsManager implements IOFStatisticsManager,
             } else if (result instanceof OFError) {
                 log.warn("Switch {} failed to handle ({}) stats request: {}",
                         new Object[] { HexString.toHexString(switchId), type,
             } else if (result instanceof OFError) {
                 log.warn("Switch {} failed to handle ({}) stats request: {}",
                         new Object[] { HexString.toHexString(switchId), type,
-                                Utils.getOFErrorString((OFError) result) });
+                        Utils.getOFErrorString((OFError) result) });
                 if (this.switchSupportsVendorExtStats.get(switchId) == Boolean.TRUE) {
                     log.warn(
                             "Switching back to regular Flow stats requests for switch {}",
                 if (this.switchSupportsVendorExtStats.get(switchId) == Boolean.TRUE) {
                     log.warn(
                             "Switching back to regular Flow stats requests for switch {}",
@@ -791,6 +840,31 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         return list;
     }
 
         return list;
     }
 
+    @Override
+    public List<OFStatistics> getOFTableStatistics(Long switchId) {
+        if (!tableStatistics.containsKey(switchId)) {
+            return this.dummyList;
+        }
+
+        return tableStatistics.get(switchId);
+    }
+
+    @Override
+    public List<OFStatistics> getOFTableStatistics(Long switchId, Byte tableId) {
+        if (!tableStatistics.containsKey(switchId)) {
+            return this.dummyList;
+        }
+
+        List<OFStatistics> list = new ArrayList<OFStatistics>(1);
+        for (OFStatistics stats : tableStatistics.get(switchId)) {
+            if (((OFTableStatistics) stats).getTableId() == tableId) {
+                list.add(stats);
+                break;
+            }
+        }
+        return list;
+    }
+
     @Override
     public int getFlowsNumber(long switchId) {
         return this.flowStatistics.get(switchId).size();
     @Override
     public int getFlowsNumber(long switchId) {
         return this.flowStatistics.get(switchId).size();
@@ -938,6 +1012,7 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         ci.println("Flow Stats Period: " + statisticsTickNumber + " s");
         ci.println("Desc Stats Period: " + descriptionTickNumber + " s");
         ci.println("Port Stats Period: " + portTickNumber + " s");
         ci.println("Flow Stats Period: " + statisticsTickNumber + " s");
         ci.println("Desc Stats Period: " + descriptionTickNumber + " s");
         ci.println("Port Stats Period: " + portTickNumber + " s");
+        ci.println("Table Stats Period: " + tableTickNumber + " s");
     }
 
     public void _resetSwitchCapability(CommandInterpreter ci) {
     }
 
     public void _resetSwitchCapability(CommandInterpreter ci) {
@@ -1008,6 +1083,7 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         String flowStatsInterv = ci.nextArgument();
         String portStatsInterv = ci.nextArgument();
         String descStatsInterv = ci.nextArgument();
         String flowStatsInterv = ci.nextArgument();
         String portStatsInterv = ci.nextArgument();
         String descStatsInterv = ci.nextArgument();
+        String tableStatsInterv = ci.nextArgument();
 
         if (flowStatsInterv == null || portStatsInterv == null
                 || descStatsInterv == null) {
 
         if (flowStatsInterv == null || portStatsInterv == null
                 || descStatsInterv == null) {
@@ -1016,27 +1092,30 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                     + portTickNumber + "s dP=" + descriptionTickNumber + "s");
             return;
         }
                     + portTickNumber + "s dP=" + descriptionTickNumber + "s");
             return;
         }
-        Short fP, pP, dP;
+        Short fP, pP, dP, tP;
         try {
             fP = Short.parseShort(flowStatsInterv);
             pP = Short.parseShort(portStatsInterv);
             dP = Short.parseShort(descStatsInterv);
         try {
             fP = Short.parseShort(flowStatsInterv);
             pP = Short.parseShort(portStatsInterv);
             dP = Short.parseShort(descStatsInterv);
+            tP = Short.parseShort(tableStatsInterv);
         } catch (Exception e) {
             ci.println("Invalid format values: " + e.getMessage());
             return;
         }
 
         } catch (Exception e) {
             ci.println("Invalid format values: " + e.getMessage());
             return;
         }
 
-        if (pP <= 1 || fP <= 1 || dP <= 1) {
-            ci.println("Invalid values. fP, pP, dP have to be greater than 1.");
+        if (pP <= 1 || fP <= 1 || dP <= 1 || tP <= 1) {
+            ci.println("Invalid values. fP, pP, dP, tP have to be greater than 1.");
             return;
         }
 
         statisticsTickNumber = fP;
         portTickNumber = pP;
         descriptionTickNumber = dP;
             return;
         }
 
         statisticsTickNumber = fP;
         portTickNumber = pP;
         descriptionTickNumber = dP;
+        tableTickNumber = tP;
 
         ci.println("New Values: fP=" + statisticsTickNumber + "s pP="
 
         ci.println("New Values: fP=" + statisticsTickNumber + "s pP="
-                + portTickNumber + "s dP=" + descriptionTickNumber + "s");
+                + portTickNumber + "s dP=" + descriptionTickNumber + "s tP="
+                + tableTickNumber + "s");
     }
 
     /**
     }
 
     /**
@@ -1047,7 +1126,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         String fsStr = System.getProperty("of.flowStatsPollInterval");
         String psStr = System.getProperty("of.portStatsPollInterval");
         String dsStr = System.getProperty("of.descStatsPollInterval");
         String fsStr = System.getProperty("of.flowStatsPollInterval");
         String psStr = System.getProperty("of.portStatsPollInterval");
         String dsStr = System.getProperty("of.descStatsPollInterval");
-        Short fs, ps, ds;
+        String tsStr = System.getProperty("of.tableStatsPollInterval");
+        Short fs, ps, ds, ts;
 
         if (fsStr != null) {
             try {
 
         if (fsStr != null) {
             try {
@@ -1078,5 +1158,15 @@ public class OFStatisticsManager implements IOFStatisticsManager,
             } catch (Exception e) {
             }
         }
             } catch (Exception e) {
             }
         }
+
+        if (tsStr != null) {
+            try{
+                ts = Short.parseShort(tsStr);
+                if (ts > 0) {
+                    tableTickNumber = ts;
+                }
+            } catch (Exception e) {
+            }
+        }
     }
 }
     }
 }
index 9ff3d21ff0a5ddbff953066b9e2b3553f3807617..20d13b7a3dc9325244ff05f5f586cd1b8e31e1d9 100644 (file)
@@ -20,11 +20,13 @@ import org.slf4j.LoggerFactory;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.Node.NodeIDType;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.Node.NodeIDType;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.IPluginInReadService;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.IPluginInReadService;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 
 /**
  * Container Instance of IPluginInReadService implementation class
 
 /**
  * Container Instance of IPluginInReadService implementation class
@@ -146,4 +148,24 @@ public class ReadService implements IPluginInReadService {
         }
         return filter.getTransmitRate(containerName, connector);
     }
         }
         return filter.getTransmitRate(containerName, connector);
     }
+
+    @Override
+    public NodeTableStatistics readNodeTable(NodeTable table, boolean cached) {
+        if (!table.getNode().getType()
+                .equals(NodeIDType.OPENFLOW)) {
+            logger.error("Invalid node type");
+            return null;
+        }
+        return filter.readNodeTable(containerName, table, cached);
+    }
+
+    @Override
+    public List<NodeTableStatistics> readAllNodeTable(Node node, boolean cached) {
+        if (!node.getType().equals(NodeIDType.OPENFLOW)) {
+            logger.error("Invalid node type");
+            return null;
+        }
+
+        return filter.readAllNodeTable(containerName, node, cached);
+    }
 }
 }
index 1b71c3bec34f70b382af55c094e7acb7f86f0fdf..bcb01b1392ac8661f2ee6aeb3db5e34c47362a41 100644 (file)
@@ -33,6 +33,7 @@ import org.opendaylight.controller.sal.core.ContainerFlow;
 import org.opendaylight.controller.sal.core.IContainerListener;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.IContainerListener;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.core.UpdateType;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.core.UpdateType;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.match.Match;
@@ -40,10 +41,12 @@ import org.opendaylight.controller.sal.match.MatchType;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 import org.opendaylight.controller.sal.utils.NodeCreator;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 import org.opendaylight.controller.sal.utils.NodeCreator;
-
+import org.opendaylight.controller.sal.utils.NodeTableCreator;
+import org.openflow.protocol.statistics.OFTableStatistics;
 /**
  * Read Service shim layer which is in charge of filtering the flow statistics
  * based on container. It is a Global instance.
 /**
  * Read Service shim layer which is in charge of filtering the flow statistics
  * based on container. It is a Global instance.
@@ -58,6 +61,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter,
     private IController controller = null;
     private IOFStatisticsManager statsMgr = null;
     private Map<String, Set<NodeConnector>> containerToNc;
     private IController controller = null;
     private IOFStatisticsManager statsMgr = null;
     private Map<String, Set<NodeConnector>> containerToNc;
+    private Map<String, Set<NodeTable>> containerToNt;
 
     public void setController(IController core) {
         this.controller = core;
 
     public void setController(IController core) {
         this.controller = core;
@@ -76,6 +80,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter,
      */
     void init() {
         containerToNc = new HashMap<String, Set<NodeConnector>>();
      */
     void init() {
         containerToNc = new HashMap<String, Set<NodeConnector>>();
+        containerToNt = new HashMap<String, Set<NodeTable>>();
     }
 
     /**
     }
 
     /**
@@ -174,9 +179,9 @@ public class ReadServiceFilter implements IPluginReadServiceFilter,
         long sid = (Long) node.getID();
         List<OFStatistics> ofList = (cached == true) ? statsMgr
                 .getOFDescStatistics(sid) : statsMgr.queryStatistics(sid,
         long sid = (Long) node.getID();
         List<OFStatistics> ofList = (cached == true) ? statsMgr
                 .getOFDescStatistics(sid) : statsMgr.queryStatistics(sid,
-                OFStatisticsType.DESC, null);
+                        OFStatisticsType.DESC, null);
 
 
-        return new DescStatisticsConverter(ofList).getHwDescription();
+                return new DescStatisticsConverter(ofList).getHwDescription();
     }
 
     /**
     }
 
     /**
@@ -235,6 +240,28 @@ public class ReadServiceFilter implements IPluginReadServiceFilter,
         return newList;
     }
 
         return newList;
     }
 
+
+    public List<OFStatistics> filterTableListPerContainer(
+            String container, long switchId, List<OFStatistics> list) {
+        if (list == null) {
+            return null;
+        }
+
+        // Create new filtered list of node tables
+        List<OFStatistics> newList = new ArrayList<OFStatistics>();
+
+        for (OFStatistics stat : list) {
+            OFTableStatistics target = (OFTableStatistics) stat;
+            NodeTable nt = NodeTableCreator.createOFNodeTable(
+                    target.getTableId(), NodeCreator.createOFNode(switchId));
+            if (containerOwnsNodeTable(container, nt)) {
+                newList.add(target);
+            }
+        }
+
+        return newList;
+    }
+
     /**
      * Returns whether the specified flow (flow match + actions)
      * belongs to the container
     /**
      * Returns whether the specified flow (flow match + actions)
      * belongs to the container
@@ -251,7 +278,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter,
         }
         return (flowPortsBelongToContainer(container, node, flow)
                 && flowVlanBelongsToContainer(container, node, flow) && flowSpecAllowsFlow(
         }
         return (flowPortsBelongToContainer(container, node, flow)
                 && flowVlanBelongsToContainer(container, node, flow) && flowSpecAllowsFlow(
-                container, flow.getMatch()));
+                        container, flow.getMatch()));
     }
 
     /**
     }
 
     /**
@@ -270,6 +297,22 @@ public class ReadServiceFilter implements IPluginReadServiceFilter,
         return (portSet == null) ? false : portSet.contains(p);
     }
 
         return (portSet == null) ? false : portSet.contains(p);
     }
 
+    /**
+     * Returns whether the passed NodeConnector belongs to the container
+     *
+     * @param container        container name
+     * @param table            node table to test
+     * @return                 true if belongs false otherwise
+     */
+    public boolean containerOwnsNodeTable(String container, NodeTable table) {
+        // All node table belong to the default container
+        if (container.equals(GlobalConstants.DEFAULT.toString())) {
+            return true;
+        }
+        Set<NodeTable> tableSet = containerToNt.get(container);
+        return (tableSet == null) ? false : tableSet.contains(table);
+    }
+
     /**
      * Returns whether the container flowspec allows the passed flow
      *
     /**
      * Returns whether the container flowspec allows the passed flow
      *
@@ -382,11 +425,11 @@ public class ReadServiceFilter implements IPluginReadServiceFilter,
         short portId = (Short) connector.getID();
         List<OFStatistics> ofList = (cached == true) ? statsMgr
                 .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics(
         short portId = (Short) connector.getID();
         List<OFStatistics> ofList = (cached == true) ? statsMgr
                 .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics(
-                sid, OFStatisticsType.PORT, portId);
+                        sid, OFStatisticsType.PORT, portId);
 
 
-        List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(
-                sid, ofList).getNodeConnectorStatsList();
-        return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics()
+                List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(
+                        sid, ofList).getNodeConnectorStatsList();
+                return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics()
                 : ncStatistics.get(0);
     }
 
                 : ncStatistics.get(0);
     }
 
@@ -397,12 +440,12 @@ public class ReadServiceFilter implements IPluginReadServiceFilter,
         long sid = (Long) node.getID();
         List<OFStatistics> ofList = (cached == true) ? statsMgr
                 .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid,
         long sid = (Long) node.getID();
         List<OFStatistics> ofList = (cached == true) ? statsMgr
                 .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid,
-                OFStatisticsType.FLOW, null);
+                        OFStatisticsType.FLOW, null);
 
 
-        List<OFStatistics> filteredList = filterPortListPerContainer(
-                containerName, sid, ofList);
+                List<OFStatistics> filteredList = filterPortListPerContainer(
+                        containerName, sid, ofList);
 
 
-        return new PortStatisticsConverter(sid, filteredList)
+                return new PortStatisticsConverter(sid, filteredList)
                 .getNodeConnectorStatsList();
     }
 
                 .getNodeConnectorStatsList();
     }
 
@@ -418,4 +461,39 @@ public class ReadServiceFilter implements IPluginReadServiceFilter,
         return statsMgr.getTransmitRate(switchId, port);
     }
 
         return statsMgr.getTransmitRate(switchId, port);
     }
 
+    @Override
+    public NodeTableStatistics readNodeTable(String containerName,
+            NodeTable table, boolean cached) {
+        if (!containerOwnsNodeTable(containerName, table)) {
+            return null;
+        }
+        Node node = table.getNode();
+        long sid = (Long) node.getID();
+        Byte tableId = (Byte) table.getID();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFTableStatistics(sid, tableId) : statsMgr.queryStatistics(
+                        sid, OFStatisticsType.TABLE, tableId);
+
+                List<NodeTableStatistics> ntStatistics = new TableStatisticsConverter(
+                        sid, ofList).getNodeTableStatsList();
+
+                return (ntStatistics.isEmpty()) ? new NodeTableStatistics()
+                : ntStatistics.get(0);
+    }
+
+    @Override
+    public List<NodeTableStatistics> readAllNodeTable(String containerName,
+            Node node, boolean cached) {
+        long sid = (Long) node.getID();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFTableStatistics(sid) : statsMgr.queryStatistics(sid,
+                        OFStatisticsType.FLOW, null);
+
+                List<OFStatistics> filteredList = filterTableListPerContainer(
+                        containerName, sid, ofList);
+
+                return new TableStatisticsConverter(sid, filteredList)
+                .getNodeTableStatsList();
+    }
+
 }
 }
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TableConverter.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TableConverter.java
new file mode 100644 (file)
index 0000000..0b53284
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 Big Switch Networks, Inc.  All rights reserved.
+ *
+ * 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
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeTable;
+import org.opendaylight.controller.sal.utils.NodeTableCreator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TableConverter {
+    private static final Logger log = LoggerFactory
+            .getLogger(TableConverter.class);
+
+    public static NodeTable toNodeTable(byte tableId, Node node) {
+        log.trace("Openflow table ID: {}", Byte.toString(tableId));
+        return NodeTableCreator.createNodeTable(tableId, node);
+    }
+
+    public static byte toOFTable(NodeTable salTable) {
+        log.trace("SAL Table: {}", salTable);
+        return (Byte) salTable.getID();
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TableStatisticsConverter.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TableStatisticsConverter.java
new file mode 100644 (file)
index 0000000..993f897
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Big Switch Networks, Inc.  All rights reserved.
+ *
+ * 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
+ */
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFTableStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Converts an openflow list of table statistics in a SAL list of
+ * NodeTableStatistics objects
+ */
+public class TableStatisticsConverter {
+    private static final Logger log = LoggerFactory
+            .getLogger(TableStatisticsConverter.class);
+
+    private final long switchId;
+    private List<OFStatistics> ofStatsList;
+    private List<NodeTableStatistics> ntStatsList;
+
+    public TableStatisticsConverter(long switchId, List<OFStatistics> statsList) {
+        this.switchId = switchId;
+        if (statsList == null || statsList.isEmpty()) {
+            this.ofStatsList = new ArrayList<OFStatistics>(1); // dummy list
+        } else {
+            this.ofStatsList = new ArrayList<OFStatistics>(statsList);
+        }
+        this.ntStatsList = null;
+    }
+
+    public List<NodeTableStatistics> getNodeTableStatsList() {
+        if (this.ofStatsList != null && this.ntStatsList == null) {
+            this.ntStatsList = new ArrayList<NodeTableStatistics>();
+            OFTableStatistics ofTableStat;
+            Node node = NodeCreator.createOFNode(switchId);
+            for (OFStatistics ofStat : this.ofStatsList) {
+                ofTableStat = (OFTableStatistics) ofStat;
+                NodeTableStatistics ntStat = new NodeTableStatistics();
+                ntStat.setNodeTable(TableConverter.toNodeTable(
+                        ofTableStat.getTableId(), node));
+                ntStat.setActiveCount(ofTableStat.getActiveCount());
+                ntStat.setLookupCount(ofTableStat.getLookupCount());
+                ntStat.setMatchedCount(ofTableStat.getMatchedCount());
+                this.ntStatsList.add(ntStat);
+            }
+        }
+        log.trace("OFStatistics: {} NodeTableStatistics: {}", ofStatsList,
+                ntStatsList);
+        return this.ntStatsList;
+    }
+}
index 68bd3af751036c6a7c7a120e0813844efe4b0ed8..27ba897fdfc57b44e0d2d4c2ae391ffeae9364c3 100644 (file)
@@ -36,6 +36,7 @@ import org.opendaylight.controller.sal.action.SwPath;
 import org.opendaylight.controller.sal.core.ConstructionException;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.ConstructionException;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.match.MatchType;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.match.MatchType;
@@ -43,7 +44,7 @@ import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.IPluginInReadService;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.reader.IPluginInReadService;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
-
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 /**
  * Stub Implementation for IPluginInReadService used by SAL
  * 
 /**
  * Stub Implementation for IPluginInReadService used by SAL
  * 
@@ -233,4 +234,33 @@ public class ReadService implements IPluginInReadService {
         return 100;
     }
 
         return 100;
     }
 
+    @Override
+    public NodeTableStatistics readNodeTable(NodeTable table, boolean b) {
+        NodeTableStatistics stats = new NodeTableStatistics();
+        stats.setNodeTable(table);
+        stats.setActiveCount(4);
+        stats.setLookupCount(4);
+        stats.setMatchedCount(4);
+
+        return stats;
+    }
+
+    @Override
+    public List<NodeTableStatistics> readAllNodeTable(Node node, boolean cached) {
+        NodeTableStatistics stats = new NodeTableStatistics();
+        try {
+            NodeTable nt = new NodeTable(NodeTable.NodeTableIDType.OPENFLOW, Byte.valueOf("10"), node);
+            stats.setNodeTable(nt);
+        } catch (ConstructionException e) {
+            // couldn't create nodetable.
+        }
+
+        stats.setActiveCount(4);
+        stats.setLookupCount(4);
+        stats.setMatchedCount(4);
+
+        List<NodeTableStatistics> result = new ArrayList<NodeTableStatistics>();
+        result.add(stats);
+        return result;
+    }
 }
 }
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/NodeTable.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/NodeTable.java
new file mode 100644 (file)
index 0000000..22c3796
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2013 Big Switch Networks, Inc.  All rights reserved.
+ *
+ * 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
+ */
+package org.opendaylight.controller.sal.core;
+
+import java.io.Serializable;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NodeTable implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    public static final Short SPECIALNODETABLEID = (short) 0;
+
+    /**
+     * Enum-like static class created with the purpose of identifing
+     * multiple type of nodes in the SDN network. The type is
+     * necessary to figure out to later on correctly use the
+     * nodeTableID. Using a static class instead of an Enum so we can add
+     * dynamically new types without changing anything in the
+     * surround.
+     */
+    public static final class NodeTableIDType {
+        private static final ConcurrentHashMap<String, Class<? extends Object>> compatibleType =
+                new ConcurrentHashMap<String, Class<? extends Object>>();
+        /**
+         * These are in compliance with the compatibility types in 'Node'
+         */
+        public static String OPENFLOW = "OF";
+        public static String PCEP = "PE";
+        public static String ONEPK = "PK";
+        public static String PRODUCTION = "PR";
+
+        // Pre-populated types, just here for convenience and ease of
+        // unit-testing, but certainly those could live also outside.
+        // Currently we allow these 4. It can be changed later.
+        static {
+            compatibleType.put(OPENFLOW, Byte.class);
+            compatibleType.put(PCEP, UUID.class);
+            compatibleType.put(ONEPK, String.class);
+            compatibleType.put(PRODUCTION, String.class);
+        }
+
+        /**
+         * Return the type of the class expected for the
+         * NodeTableID, it's used for validity check in the constructor
+         *
+         * @param type, the type of the NodeTable for which we
+         * want to retrieve the compatible class to be used as ID.
+         *
+         * @return The Class which is supposed to instantiate the ID
+         * for the NodeTableID
+         */
+        public static Class<?> getClassType(String type) {
+            return compatibleType.get(type);
+        }
+
+        /**
+         * Returns all the registered nodeTableIDTypes currently available
+         *
+         * @return The current registered NodeTableIDTypes
+         */
+        public static Set<String> values() {
+            return compatibleType.keySet();
+        }
+
+        /**
+         * Register a new ID for which NodeTable can be created
+         *
+         * @param type, the new type being registered
+         * @param compatibleID, the type of class to be accepted as ID
+         *
+         * @return true if registered, false otherwise
+         */
+        public static boolean registerIDType(String type,
+                Class<? extends Object> compatibleID) {
+            if (compatibleType.get(type) != null) {
+                return false;
+            }  else {
+                compatibleType.put(type, compatibleID);
+                return true;
+            }
+        }
+
+        /**
+         * UNRegister a new ID for which Node can be created
+         *
+         * @param type, the type being UN-registered
+         *
+         */
+        public static void unRegisterIDType(String type) {
+            compatibleType.remove(type);
+        }
+    }
+
+    // Elements that constitute the NodeTable
+    private Object nodeTableID;
+    private String nodeTableType;
+    @XmlElement(name = "node")
+    private Node nodeTableNode;
+
+    // Helper field for JAXB
+    private String nodeTableIDString;
+
+    /**
+     * Private constructor used for JAXB mapping
+     */
+    private NodeTable() {
+        this.nodeTableIDString = null;
+        this.nodeTableID = null;
+        this.nodeTableType = null;
+        this.nodeTableNode = null;
+    }
+
+    public NodeTable(String nodeTableType, Object id, Node node) throws ConstructionException {
+        if (NodeTableIDType.getClassType(nodeTableType) != null &&
+                NodeTableIDType.getClassType(nodeTableType).isInstance(id) &&
+                node.getType().equals(nodeTableType)) {
+            this.nodeTableType = nodeTableType;
+            this.nodeTableID = id;
+            this.nodeTableNode = node;
+        } else {
+            throw new ConstructionException("Type of incoming object:"
+                    + id.getClass() + " not compatible with expected type:"
+                    + NodeTableIDType.getClassType(nodeTableType)
+                    + " or Node type incompatible:" + node.getType());
+        }
+    }
+
+    /**
+     * Copy constructor for NodeTable
+     *
+     * @param src NodeTable to copy from
+     *
+     */
+    public NodeTable(NodeTable src) throws ConstructionException {
+        if (src != null) {
+            this.nodeTableType = src.getType();
+            // Here we can reference the object because that is
+            // supposed to be an immutable identifier as well like a
+            // UUID/Integer and so on, hence no need to create a copy
+            // of it
+            this.nodeTableID = src.getID();
+            this.nodeTableNode = new Node(src.getNode());
+        } else {
+            throw
+            new ConstructionException("Null incoming object to copy from");
+        }
+    }
+
+    /**
+     * @return the nodeTableID
+     */
+    public Object getID() {
+        return this.nodeTableID;
+    }
+
+    /**
+     * @return the nodeTableType
+     */
+    public String getType() {
+        return this.nodeTableType;
+    }
+
+    /**
+     * @param type the nodeTableType to set
+     *
+     * Private setter for nodeConnectorType to be called by JAXB not by anyone
+     * else, NodeConnector is immutable
+     */
+    private void setType(String type) {
+        this.nodeTableType = type;
+        if (this.nodeTableIDString != null) {
+            this.fillmeFromString(type, this.nodeTableIDString);
+        }
+    }
+
+    /**
+     * @return the nodeTableNode
+     */
+    public Node getNode() {
+        return this.nodeTableNode;
+    }
+
+    /**
+     * @param nodeTableNode the nodeTableNode to set
+     */
+    public void setNodeTableNode(Node nodeTableNode) {
+        this.nodeTableNode = nodeTableNode;
+    }
+
+    /**
+     * @return the nodeTableIDString
+     */
+    @XmlAttribute(name = "id")
+    public String getNodeTableIDString() {
+        return this.nodeTableIDString.toString();
+    }
+
+    /**
+     * @param nodeTableIDString the nodeTableIDString to set
+     */
+    @SuppressWarnings("unused")
+    private void setNodeTableIDString(String IDStr) {
+        this.nodeTableIDString = IDStr;
+        if (this.nodeTableType != null) {
+            this.fillmeFromString(this.nodeTableType, IDStr);
+        }
+    }
+
+    /**
+     * fill the current object from the string parameters passed, will
+     * be only used by JAXB
+     *
+     * @param typeStr string representing the type of the Node
+     * @param IDStr String representation of the ID
+     */
+    private void fillmeFromString(String typeStr, String IDStr) {
+        if (typeStr == null) {
+            return;
+        }
+
+        if (IDStr == null) {
+            return;
+        }
+
+        this.nodeTableType = typeStr;
+        this.nodeTableID = (byte) Byte.parseByte(IDStr);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result
+                + ((nodeTableID == null) ? 0 : nodeTableID.hashCode());
+        result = prime
+                * result
+                + ((nodeTableNode == null) ? 0 : nodeTableNode
+                        .hashCode());
+        result = prime
+                * result
+                + ((nodeTableType == null) ? 0 : nodeTableType
+                        .hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        NodeTable other = (NodeTable) obj;
+        if (nodeTableID == null) {
+            if (other.nodeTableID != null)
+                return false;
+        } else if (!nodeTableID.equals(other.nodeTableID))
+            return false;
+        if (nodeTableNode == null) {
+            if (other.nodeTableNode != null)
+                return false;
+        } else if (!nodeTableNode.equals(other.nodeTableNode))
+            return false;
+        if (nodeTableType == null) {
+            if (other.nodeTableType != null)
+                return false;
+        } else if (!nodeTableType.equals(other.nodeTableType))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return this.getNodeTableIdAsString() + "@" + this.nodeTableNode;
+    }
+
+    public String getNodeTableIdAsString() {
+        return this.nodeTableType.toString() + "|"
+                + this.nodeTableID.toString();
+    }
+
+}
index c563037f1e6be9bce538780ba0dd8c93b2c3e31c..1b950d7cf592df1a78fc775d3a4c390a274d4efa 100644 (file)
@@ -13,6 +13,7 @@ import java.util.List;
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 
 /**
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 
 /**
@@ -63,10 +64,25 @@ public interface IPluginInReadService {
     public List<NodeConnectorStatistics> readAllNodeConnector(Node node,
             boolean cached);
 
     public List<NodeConnectorStatistics> readAllNodeConnector(Node node,
             boolean cached);
 
+    /**
+     * Returns the table statistics for the node
+     * @param node
+     * @return
+     */
+    public NodeTableStatistics readNodeTable(NodeTable table, boolean cached);
+
+    /**
+     * Returns all the table statistics for the node
+     * @param node
+     * @return
+     */
+    public List<NodeTableStatistics> readAllNodeTable(Node node, boolean cached);
+
     /**
      * Returns the averaged transmit rate for the specified node connector
      * @param connector
      * @return tx rate [bps]
      */
     public long getTransmitRate(NodeConnector connector);
     /**
      * Returns the averaged transmit rate for the specified node connector
      * @param connector
      * @return tx rate [bps]
      */
     public long getTransmitRate(NodeConnector connector);
+
 }
 }
index 3a9f828d942fc294d01e93606802c86233894058..ae975f1a58d21c7d30b52f7e878b48db4db905f0 100644 (file)
@@ -13,6 +13,7 @@ import java.util.List;
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 
 /**
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 
 /**
@@ -88,6 +89,28 @@ public interface IReadService {
      */
     List<NodeConnectorStatistics> readNodeConnectors(Node node);
 
      */
     List<NodeConnectorStatistics> readNodeConnectors(Node node);
 
+    /**
+     * Read the Table statistics for the given node table
+     * @param table
+     */
+    NodeTableStatistics readNodeTable(NodeTable table);
+
+    /**
+     * Read the Table statistics for the given node
+     * This is not used. Querying all tables on a node is not currently a feature.
+     * @param table
+     */
+    List<NodeTableStatistics> readNodeTable(Node node);
+
+    /**
+     * Get the table statistics for the given node table
+     * This call results in a direct polling of the information from the node
+     * Caller will be blocked until the node replies or request times out
+     *
+     * @param table
+     */
+    NodeTableStatistics nonCachedReadNodeTable(NodeTable table);
+
     /**
      * Get the node connectors statistics information for the network node
      * This call results in a direct polling of the information from the node
     /**
      * Get the node connectors statistics information for the network node
      * This call results in a direct polling of the information from the node
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/NodeTableStatistics.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/NodeTableStatistics.java
new file mode 100644 (file)
index 0000000..3ccf8f5
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2013 Big Switch Networks, Inc.  All rights reserved.
+ *
+ * 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
+ */
+package org.opendaylight.controller.sal.reader;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.opendaylight.controller.sal.core.NodeTable;
+
+/**
+ * @author Aditya Prakash Vaja <aditya.vaja@bigswitch.com>
+ * Represents the Table statistics for the node
+ * 
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NodeTableStatistics {
+    @XmlElement
+    private NodeTable nodeTable;
+    @XmlElement
+    private String name;
+    @XmlElement
+    private int activeCount;
+    @XmlElement
+    private long lookupCount;
+    @XmlElement
+    private long matchedCount;
+
+
+    //To Satisfy JAXB
+    public NodeTableStatistics() {
+
+    }
+
+    /**
+     * @return the node table
+     */
+    public NodeTable getNodeTable() {
+        return nodeTable;
+    }
+
+    /**
+     * @param table of the node
+     */
+    public void setNodeTable(NodeTable table) {
+        this.nodeTable = table;
+    }
+
+    /**
+     * @return name of the table
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name - set the table name to name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the activeCount
+     */
+    public int getActiveCount() {
+        return activeCount;
+    }
+
+    /**
+     * @param activeCount the activeCount to set
+     */
+    public void setActiveCount(int activeCount) {
+        this.activeCount = activeCount;
+    }
+
+    /**
+     * @return the lookupCount
+     */
+    public long getLookupCount() {
+        return lookupCount;
+    }
+
+    /**
+     * @param lookupCount the lookupCount to set
+     */
+    public void setLookupCount(long lookupCount) {
+        this.lookupCount = lookupCount;
+    }
+
+    /**
+     * @return the matchedCount
+     */
+    public long getMatchedCount() {
+        return matchedCount;
+    }
+
+    /**
+     * @param matchedCount the matchedCount to set
+     */
+    public void setMatchedCount(long matchedCount) {
+        this.matchedCount = matchedCount;
+    }
+
+    @Override
+    public String toString() {
+        return "NodeTableStats[tableId = " + nodeTable
+                + ", activeCount = " + activeCount
+                + ", lookupCount = " + lookupCount
+                + ", matchedCount = " + matchedCount + "]";
+    }
+}
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeTableCreator.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeTableCreator.java
new file mode 100644 (file)
index 0000000..5d69810
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Big Switch Networks, Inc.  All rights reserved.
+ *
+ * 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
+ */
+package org.opendaylight.controller.sal.utils;
+
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeTable;
+import org.opendaylight.controller.sal.core.NodeTable.NodeTableIDType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NodeTableCreator {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(NodeTableCreator.class);
+
+    /**
+     * Generic NodeTable creator
+     * The nodeTable type is OPENFLOW only for the time being
+     *
+     * @param portId
+     * @param node
+     * @return
+     */
+    public static NodeTable createNodeTable(byte tableId, Node node) {
+        try {
+            return new NodeTable(NodeTableIDType.OPENFLOW, tableId, node);
+        } catch (ConstructionException e1) {
+            logger.error("",e1);
+            return null;
+        }
+    }
+
+    public static NodeTable createOFNodeTable(byte tableId, Node node) {
+        try {
+            return new NodeTable(NodeTableIDType.OPENFLOW, tableId, node);
+        } catch (ConstructionException e1) {
+            logger.error("",e1);
+            return null;
+        }
+    }
+
+}
diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/core/NodeTableTest.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/core/NodeTableTest.java
new file mode 100644 (file)
index 0000000..57286fe
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013 Big Switch Networks, Inc.  All rights reserved.
+ *
+ * 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
+ */
+package org.opendaylight.controller.sal.core;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+
+public class NodeTableTest {
+    @Test
+    public void testNodeTableOpenFlowOfWrongType() {
+        try {
+            Node node = NodeCreator.createOFNode((long) 20);
+            NodeTable of1 = new NodeTable(NodeTable.NodeTableIDType.OPENFLOW, "name", node);
+
+            // If we reach this point the exception was not raised
+            // which should have been the case
+            Assert.assertTrue(false);
+        } catch (ConstructionException e) {
+            // If we reach this point the exception has been raised
+            // and so test passed
+            System.out.println("Got exception as expected!:" + e);
+            Assert.assertTrue(true);
+        }
+    }
+
+    @Test
+    public void testNodeTableOpenFlowOfCorrectType() {
+        try {
+            Node node = NodeCreator.createOFNode((long) 20);
+            NodeTable of1 = new NodeTable(NodeTable.NodeTableIDType.OPENFLOW, Byte.valueOf("10"), node);
+
+            // If we reach this point the exception has not been
+            // raised so we passed the test
+            System.out.println("Got node table:" + of1);
+            Assert.assertTrue(true);
+        } catch (ConstructionException e) {
+            // If we reach this point the exception was raised
+            // which is not expected
+            Assert.assertTrue(false);
+        }
+    }
+
+    @Test
+    public void testTwoOpenFlowNodeTableEquals() {
+        try {
+            Node node1 = NodeCreator.createOFNode((long) 20);
+            NodeTable of1 = new NodeTable(NodeTable.NodeTableIDType.OPENFLOW, Byte.valueOf("10"), node1);
+            NodeTable of2 = new NodeTable(NodeTable.NodeTableIDType.OPENFLOW, Byte.valueOf("10"), node1);
+
+            Assert.assertTrue(of1.equals(of2));
+        } catch (ConstructionException e) {
+            // If we reach this point the exception was raised
+            // which is not expected
+            Assert.assertTrue(false);
+        }
+    }
+
+    @Test
+    public void testTwoOpenFlowNodeTableDifferents() {
+        try {
+            Node node1 = NodeCreator.createOFNode((long) 20);
+            NodeTable of1 = new NodeTable(NodeTable.NodeTableIDType.OPENFLOW, Byte.valueOf("10"), node1);
+            Node node2 = NodeCreator.createOFNode((long) 40);
+            NodeTable of2 = new NodeTable(NodeTable.NodeTableIDType.OPENFLOW, Byte.valueOf("20"), node2);
+
+            Assert.assertTrue(!of1.equals(of2));
+        } catch (ConstructionException e) {
+            // If we reach this point the exception was raised
+            // which is not expected
+            Assert.assertTrue(false);
+        }
+    }
+}
diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/reader/NodeTableStatisticsTest.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/reader/NodeTableStatisticsTest.java
new file mode 100644 (file)
index 0000000..c0d6bb6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 Big Switch Networks, Inc.  All rights reserved.
+ *
+ * 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
+ */
+package org.opendaylight.controller.sal.reader;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.sal.core.NodeTable;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+import org.opendaylight.controller.sal.utils.NodeTableCreator;
+
+public class NodeTableStatisticsTest {
+
+    @Test
+    public void testNodeTableStatisticsMethods() {
+        NodeTable nt = NodeTableCreator.createNodeTable(Byte.valueOf("2") , NodeCreator.createOFNode((long)20));
+        NodeTableStatistics ntStats = new NodeTableStatistics();
+
+        ntStats.setNodeTable(nt);
+        ntStats.setActiveCount(100);
+        ntStats.setLookupCount(200);
+        ntStats.setMatchedCount(500);
+        ntStats.setName("Test");
+
+        Assert.assertTrue(ntStats.getNodeTable().equals(nt));
+        Assert.assertTrue(ntStats.getActiveCount() == 100);
+        Assert.assertTrue(ntStats.getLookupCount() == 200);
+        Assert.assertTrue(ntStats.getMatchedCount() == 500);
+        Assert.assertTrue(ntStats.getName().equals("Test"));
+    }
+}
index 0ee48d5b880b8efd4039e98d0d8c217aaf095a96..fce0a39719234a58e1d37c98b5d84d3ae67fe6d7 100644 (file)
@@ -25,6 +25,7 @@ import org.opendaylight.controller.sal.action.Output;
 import org.opendaylight.controller.sal.action.PopVlan;
 import org.opendaylight.controller.sal.core.ConstructionException;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.action.PopVlan;
 import org.opendaylight.controller.sal.core.ConstructionException;
 import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.Node.NodeIDType;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.Node.NodeIDType;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
@@ -35,10 +36,12 @@ import org.opendaylight.controller.sal.reader.IPluginInReadService;
 import org.opendaylight.controller.sal.reader.IReadService;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.reader.IReadService;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.IPProtocols;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 import org.opendaylight.controller.sal.utils.NodeCreator;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.IPProtocols;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 import org.opendaylight.controller.sal.utils.NodeCreator;
+import org.opendaylight.controller.sal.utils.NodeTableCreator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.slf4j.Logger;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.slf4j.Logger;
@@ -110,7 +113,7 @@ public class ReadService implements IReadService, CommandProvider {
         for (Object e : props.entrySet()) {
             Map.Entry entry = (Map.Entry) e;
             logger.trace("Prop key:({}) value:({})", entry.getKey(),
         for (Object e : props.entrySet()) {
             Map.Entry entry = (Map.Entry) e;
             logger.trace("Prop key:({}) value:({})", entry.getKey(),
-                       entry.getValue());
+                    entry.getValue());
         }
 
         Object value = props.get("protocolPluginType");
         }
 
         Object value = props.get("protocolPluginType");
@@ -137,7 +140,7 @@ public class ReadService implements IReadService, CommandProvider {
         for (Object e : props.entrySet()) {
             Map.Entry entry = (Map.Entry) e;
             logger.trace("Prop key:({}) value:({})", entry.getKey(),
         for (Object e : props.entrySet()) {
             Map.Entry entry = (Map.Entry) e;
             logger.trace("Prop key:({}) value:({})", entry.getKey(),
-                       entry.getValue());
+                    entry.getValue());
         }
 
         Object value = props.get("protocoloPluginType");
         }
 
         Object value = props.get("protocoloPluginType");
@@ -158,7 +161,7 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .readFlow(node, flow, true);
+                        .readFlow(node, flow, true);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -170,7 +173,7 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .readFlow(node, flow, false);
+                        .readFlow(node, flow, false);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -182,7 +185,7 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .readAllFlow(node, true);
+                        .readAllFlow(node, true);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -194,7 +197,7 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .readAllFlow(node, false);
+                        .readAllFlow(node, false);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -206,7 +209,7 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .readDescription(node, true);
+                        .readDescription(node, true);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -218,7 +221,7 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .readDescription(node, false);
+                        .readDescription(node, false);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -231,7 +234,7 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null && node != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null && node != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .readNodeConnector(connector, true);
+                        .readNodeConnector(connector, true);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -245,7 +248,7 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null && node != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null && node != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .readNodeConnector(connector, false);
+                        .readNodeConnector(connector, false);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -257,7 +260,46 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .readAllNodeConnector(node, true);
+                        .readAllNodeConnector(node, true);
+            }
+        }
+        logger.warn("Plugin unavailable");
+        return null;
+    }
+
+    @Override
+    public List<NodeTableStatistics> readNodeTable(Node node) {
+        if (pluginReader != null) {
+            if (this.pluginReader.get(node.getType()) != null) {
+                return this.pluginReader.get(node.getType())
+                        .readAllNodeTable(node, true);
+            }
+        }
+        logger.warn("Plugin unavailable");
+        return null;
+    }
+
+
+    @Override
+    public NodeTableStatistics nonCachedReadNodeTable(NodeTable table) {
+        Node node = table.getNode();
+        if (pluginReader != null && node != null) {
+            if (this.pluginReader.get(node.getType()) != null) {
+                return this.pluginReader.get(node.getType())
+                        .readNodeTable(table, false);
+            }
+        }
+        logger.warn("Plugin unavailable");
+        return null;
+    }
+
+    @Override
+    public NodeTableStatistics readNodeTable(NodeTable table) {
+        Node node = table.getNode();
+        if (pluginReader != null && node != null) {
+            if (this.pluginReader.get(node.getType()) != null) {
+                return this.pluginReader.get(node.getType())
+                        .readNodeTable(table, true);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -269,7 +311,7 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .readAllNodeConnector(node, false);
+                        .readAllNodeConnector(node, false);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -282,7 +324,7 @@ public class ReadService implements IReadService, CommandProvider {
         if (pluginReader != null && node != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
         if (pluginReader != null && node != null) {
             if (this.pluginReader.get(node.getType()) != null) {
                 return this.pluginReader.get(node.getType())
-                    .getTransmitRate(connector);
+                        .getTransmitRate(connector);
             }
         }
         logger.warn("Plugin unavailable");
             }
         }
         logger.warn("Plugin unavailable");
@@ -303,15 +345,15 @@ public class ReadService implements IReadService, CommandProvider {
         StringBuffer help = new StringBuffer();
         help.append("---SAL Reader testing commands---\n");
         help
         StringBuffer help = new StringBuffer();
         help.append("---SAL Reader testing commands---\n");
         help
-                .append("\t readflows <sid> <cached>  - Read all the (cached) flows from the openflow switch <sid>\n");
+        .append("\t readflows <sid> <cached>  - Read all the (cached) flows from the openflow switch <sid>\n");
         help
         help
-                .append("\t readflow  <sid> <cached>  - Read the (cached) sample flow from the openflow switch <sid>\n");
+        .append("\t readflow  <sid> <cached>  - Read the (cached) sample flow from the openflow switch <sid>\n");
         help
         help
-                .append("\t readdesc  <sid> <cached>  - Read the (cached) description from openflow switch <sid>\n");
+        .append("\t readdesc  <sid> <cached>  - Read the (cached) description from openflow switch <sid>\n");
         help
         help
-                .append("\t           cached=true/false. If false or not specified, the protocol plugin cached info\n");
+        .append("\t           cached=true/false. If false or not specified, the protocol plugin cached info\n");
         help
         help
-                .append("\t           is returned. If true, the info is directly retrieved from the switch\n");
+        .append("\t           is returned. If true, the info is directly retrieved from the switch\n");
         return help.toString();
     }
 
         return help.toString();
     }
 
@@ -389,11 +431,11 @@ public class ReadService implements IReadService, CommandProvider {
         List<NodeConnectorStatistics> list = (cached) ? this
                 .readNodeConnectors(node) : this
                 .nonCachedReadNodeConnectors(node);
         List<NodeConnectorStatistics> list = (cached) ? this
                 .readNodeConnectors(node) : this
                 .nonCachedReadNodeConnectors(node);
-        if (list != null) {
-            ci.println(list.toString());
-        } else {
-            ci.println("null");
-        }
+                if (list != null) {
+                    ci.println(list.toString());
+                } else {
+                    ci.println("null");
+                }
     }
 
     public void _readport(CommandInterpreter ci) {
     }
 
     public void _readport(CommandInterpreter ci) {
@@ -417,11 +459,39 @@ public class ReadService implements IReadService, CommandProvider {
         NodeConnectorStatistics stats = (cached) ? this
                 .readNodeConnector(nodeConnector) : this
                 .nonCachedReadNodeConnector(nodeConnector);
         NodeConnectorStatistics stats = (cached) ? this
                 .readNodeConnector(nodeConnector) : this
                 .nonCachedReadNodeConnector(nodeConnector);
-        if (stats != null) {
-            ci.println(stats.toString());
-        } else {
-            ci.println("null");
+                if (stats != null) {
+                    ci.println(stats.toString());
+                } else {
+                    ci.println("null");
+                }
+    }
+
+    public void _readtable(CommandInterpreter ci) {
+        String nodeId = ci.nextArgument();
+        String tableId = ci.nextArgument();
+        String cacheReq = ci.nextArgument();
+        boolean cached;
+        if (nodeId == null) {
+            ci.print("Node id not specified");
+            return;
+        }
+        if (tableId == null) {
+            ci.print("Table id not specified");
+            return;
         }
         }
+        cached = (cacheReq == null) ? true : cacheReq.equals("true");
+        NodeTable nodeTable = null;
+        Node node = NodeCreator.createOFNode(Long.parseLong(nodeId));
+        nodeTable = NodeTableCreator.createNodeTable(Byte
+                .valueOf(tableId), node);
+        NodeTableStatistics stats = (cached) ? this
+                .readNodeTable(nodeTable) : this
+                .nonCachedReadNodeTable(nodeTable);
+                if (stats != null) {
+                    ci.println(stats.toString());
+                } else {
+                    ci.println("null");
+                }
     }
 
     public void _readdescr(CommandInterpreter ci) {
     }
 
     public void _readdescr(CommandInterpreter ci) {
index db7489d47073c8e0a3423819aeab84cb8ef8a490..98977f6e91d15b6eee512d941365133cdb387697 100644 (file)
@@ -15,9 +15,11 @@ import java.util.Map;
 import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 
 /**
  * Interface which defines the available methods for retrieving
 
 /**
  * Interface which defines the available methods for retrieving
@@ -79,4 +81,20 @@ public interface IStatisticsManager {
      * @return
      */
     List<NodeConnectorStatistics> getNodeConnectorStatistics(Node node);
      * @return
      */
     List<NodeConnectorStatistics> getNodeConnectorStatistics(Node node);
+
+    /**
+     * Returns the statistics for the specified table of the node
+     *
+     * @param nodeTable
+     * @return
+     */
+    NodeTableStatistics getNodeTableStatistics(NodeTable nodeTable);
+
+    /**
+     * Returns the statistics for all the tables of the node
+     *
+     * @param nodeTable
+     * @return
+     */
+    List <NodeTableStatistics> getNodeTableStatistics(Node node);
 }
 }
index f5f56fc70f887f3002c9f84a888d61a4e75476bc..9aef40c4134424a5cc955557c585e301dd279c68 100644 (file)
@@ -17,11 +17,13 @@ import java.util.Map;
 import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.IReadService;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.IReadService;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -130,4 +132,14 @@ public class StatisticsManager implements IStatisticsManager {
     public List<NodeConnectorStatistics> getNodeConnectorStatistics(Node node) {
         return reader.readNodeConnectors(node);
     }
     public List<NodeConnectorStatistics> getNodeConnectorStatistics(Node node) {
         return reader.readNodeConnectors(node);
     }
+
+    @Override
+    public NodeTableStatistics getNodeTableStatistics(NodeTable nodeTable) {
+        return reader.readNodeTable(nodeTable);
+    }
+
+    @Override
+    public List<NodeTableStatistics> getNodeTableStatistics(Node node){
+        return reader.readNodeTable(node);
+    }
 }
 }