From cb84401ff36666443d7659f49713fff3c423cb26 Mon Sep 17 00:00:00 2001 From: Aditya Prakash Vaja Date: Fri, 31 May 2013 12:28:15 -0700 Subject: [PATCH] Add 'TableStatistics' to SAL and Northbound Statistics API. It is similar to the FlowStats and PortStats (NodeConnectorStats) that are present now. Change-Id: Ibecb95c9c4a4f911e5fd3847bbf1f2e77eb16be1 Signed-off-by: Aditya Prakash Vaja --- .../main/resources/configuration/config.ini | 2 + .../northbound/AllTableStatistics.java | 38 +++ .../northbound/StatisticsNorthbound.java | 127 +++++++- .../northbound/TableStatistics.java | 54 ++++ .../northbound/StatisticsNorthboundTest.java | 38 ++- .../openflow/IOFStatisticsManager.java | 41 ++- .../openflow/IPluginReadServiceFilter.java | 20 ++ .../internal/OFStatisticsManager.java | 106 ++++++- .../openflow/internal/ReadService.java | 22 ++ .../openflow/internal/ReadServiceFilter.java | 102 +++++- .../openflow/internal/TableConverter.java | 30 ++ .../internal/TableStatisticsConverter.java | 63 ++++ .../stub/internal/ReadService.java | 32 +- .../controller/sal/core/NodeTable.java | 298 ++++++++++++++++++ .../sal/reader/IPluginInReadService.java | 16 + .../controller/sal/reader/IReadService.java | 23 ++ .../sal/reader/NodeTableStatistics.java | 120 +++++++ .../sal/utils/NodeTableCreator.java | 47 +++ .../controller/sal/core/NodeTableTest.java | 79 +++++ .../sal/reader/NodeTableStatisticsTest.java | 35 ++ .../implementation/internal/ReadService.java | 124 ++++++-- .../statisticsmanager/IStatisticsManager.java | 18 ++ .../internal/StatisticsManager.java | 12 + 23 files changed, 1373 insertions(+), 74 deletions(-) create mode 100644 opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/AllTableStatistics.java create mode 100644 opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/TableStatistics.java create mode 100644 opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TableConverter.java create mode 100644 opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TableStatisticsConverter.java create mode 100644 opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/NodeTable.java create mode 100644 opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/NodeTableStatistics.java create mode 100644 opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeTableCreator.java create mode 100644 opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/core/NodeTableTest.java create mode 100644 opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/reader/NodeTableStatisticsTest.java diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini index df4526e6f9..a8d7beb49b 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini @@ -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 +# 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) 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 index 0000000000..5b998ee21a --- /dev/null +++ b/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/AllTableStatistics.java @@ -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; + //To satisfy JAXB + private AllTableStatistics() { + } + + public AllTableStatistics(List tableStatistics) { + this.tableStatistics = tableStatistics; + } + + public List getTableStatistics() { + return tableStatistics; + } + + public void setTableStatistics(List tableStatistics) { + this.tableStatistics = tableStatistics; + } + +} diff --git a/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthbound.java b/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthbound.java index 5cddc663c6..dee52932bd 100644 --- a/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthbound.java +++ b/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthbound.java @@ -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.reader.NodeTableStatistics; 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({ - @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( @@ -168,9 +169,9 @@ public class StatisticsNorthbound { @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, @@ -216,9 +217,9 @@ public class StatisticsNorthbound { @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) { @@ -270,9 +271,9 @@ public class StatisticsNorthbound { @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, @@ -304,6 +305,108 @@ public class StatisticsNorthbound { 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 statistics = new ArrayList(); + for (Node node : switchManager.getNodes()) { + List 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); 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 index 0000000000..a1c20190e6 --- /dev/null +++ b/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/TableStatistics.java @@ -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 tableStats; + + // To satisfy JAXB + @SuppressWarnings("unused") + private TableStatistics() { + } + + public TableStatistics(Node node, List tableStats) { + super(); + this.node = node; + this.tableStats = tableStats; + } + + public Node getNode() { + return node; + } + + public void setNode(Node node) { + this.node = node; + } + + public List getTableStats() { + return tableStats; + } + + public void setTableStats(List tableStats) { + this.tableStats = tableStats; + } + +} diff --git a/opendaylight/northbound/statistics/src/test/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthboundTest.java b/opendaylight/northbound/statistics/src/test/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthboundTest.java index 3790ae8ea9..0764c0b007 100644 --- a/opendaylight/northbound/statistics/src/test/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthboundTest.java +++ b/opendaylight/northbound/statistics/src/test/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthboundTest.java @@ -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; +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.opendaylight.controller.sal.reader.NodeTableStatistics; import org.opendaylight.controller.sal.utils.NodeCreator; -import junit.framework.TestCase; - public class StatisticsNorthboundTest extends TestCase { @Test @@ -64,4 +74,28 @@ public class StatisticsNorthboundTest extends TestCase { Assert.assertTrue(aps.getPortStatistics() == null); } + @Test + public void testTableStatistics() { + List nts = new ArrayList(); + 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 ts = new ArrayList(); + AllTableStatistics ats = new AllTableStatistics(ts); + Assert.assertTrue(ats.getTableStatistics().equals(ts)); + ats.setTableStatistics(null); + Assert.assertTrue(ats.getTableStatistics() == null); + } + } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IOFStatisticsManager.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IOFStatisticsManager.java index 18fe686dd5..74dc84aec9 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IOFStatisticsManager.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IOFStatisticsManager.java @@ -22,9 +22,9 @@ public interface IOFStatisticsManager { /** * 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 getOFFlowStatistics(Long switchId); /** @@ -39,7 +39,7 @@ public interface IOFStatisticsManager { /** * 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 getOFDescStatistics(Long switchId); @@ -47,7 +47,7 @@ public interface IOFStatisticsManager { /** * 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 getOFPortStatistics(Long switchId); @@ -55,7 +55,7 @@ public interface IOFStatisticsManager { /** * 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 */ @@ -64,7 +64,7 @@ public interface IOFStatisticsManager { /** * 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); @@ -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. - * 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 - * from the switch, before declaring failure + * from the switch, before declaring failure * @return the list of openflow statistics */ List queryStatistics(Long switchId, @@ -97,4 +97,21 @@ public interface IOFStatisticsManager { */ 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 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 getOFTableStatistics(Long switchId); + } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IPluginReadServiceFilter.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IPluginReadServiceFilter.java index a000024e9e..af474f0e67 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IPluginReadServiceFilter.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IPluginReadServiceFilter.java @@ -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.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.reader.NodeTableStatistics; /** * Interface to serve the hardware information requests coming from SAL @@ -77,6 +79,24 @@ public interface IPluginReadServiceFilter { public List 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 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 diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java index d6100e3fdc..78fddc7736 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java @@ -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.OFTableStatistics; 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, - 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 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 short tableTickNumber = (short) (tableStatsPeriod / tickPeriod); private static short factoredSamples = (short) 2; private static short counter = 1; private IController controller = null; private ConcurrentMap> flowStatistics; private ConcurrentMap> descStatistics; private ConcurrentMap> portStatistics; + private ConcurrentMap> tableStatistics; private List dummyList; private ConcurrentMap statisticsTimerTicks; protected BlockingQueue pendingStatsRequests; @@ -164,6 +168,7 @@ public class OFStatisticsManager implements IOFStatisticsManager, flowStatistics = new ConcurrentHashMap>(); descStatistics = new ConcurrentHashMap>(); portStatistics = new ConcurrentHashMap>(); + tableStatistics = new ConcurrentHashMap>(); dummyList = new ArrayList(1); statisticsTimerTicks = new ConcurrentHashMap( initialSize); @@ -283,6 +288,7 @@ public class OFStatisticsManager implements IOFStatisticsManager, type = t; } + @Override 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 tableStatisticsTicks; 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); + tableStatisticsTicks = (short) (1 + counter % tableTickNumber); } else { flowStatisticsTicks = statisticsTickNumber; descriptionTicks = descriptionTickNumber; portStatisticsTicks = portTickNumber; + tableStatisticsTicks = tableTickNumber; } } @@ -387,9 +396,20 @@ public class OFStatisticsManager implements IOFStatisticsManager, 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 - + ",pT=" + portStatisticsTicks + "}"; + + ",pT=" + portStatisticsTicks + ",tT=" + tableStatisticsTicks + "}"; } } @@ -438,6 +458,16 @@ public class OFStatisticsManager implements IOFStatisticsManager, 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)); + pendingStatsRequests.remove(new StatsRequest(switchId, + OFStatisticsType.TABLE)); // 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); + } 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) { + 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); @@ -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, - 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 {}", @@ -791,6 +840,31 @@ public class OFStatisticsManager implements IOFStatisticsManager, return list; } + @Override + public List getOFTableStatistics(Long switchId) { + if (!tableStatistics.containsKey(switchId)) { + return this.dummyList; + } + + return tableStatistics.get(switchId); + } + + @Override + public List getOFTableStatistics(Long switchId, Byte tableId) { + if (!tableStatistics.containsKey(switchId)) { + return this.dummyList; + } + + List list = new ArrayList(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(); @@ -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("Table Stats Period: " + tableTickNumber + " s"); } 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 tableStatsInterv = ci.nextArgument(); if (flowStatsInterv == null || portStatsInterv == null || descStatsInterv == null) { @@ -1016,27 +1092,30 @@ public class OFStatisticsManager implements IOFStatisticsManager, + 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); + tP = Short.parseShort(tableStatsInterv); } 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; + tableTickNumber = tP; 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"); - Short fs, ps, ds; + String tsStr = System.getProperty("of.tableStatsPollInterval"); + Short fs, ps, ds, ts; if (fsStr != null) { try { @@ -1078,5 +1158,15 @@ public class OFStatisticsManager implements IOFStatisticsManager, } catch (Exception e) { } } + + if (tsStr != null) { + try{ + ts = Short.parseShort(tsStr); + if (ts > 0) { + tableTickNumber = ts; + } + } catch (Exception e) { + } + } } } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadService.java index 9ff3d21ff0..20d13b7a3d 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadService.java @@ -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.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.reader.NodeTableStatistics; /** * Container Instance of IPluginInReadService implementation class @@ -146,4 +148,24 @@ public class ReadService implements IPluginInReadService { } 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 readAllNodeTable(Node node, boolean cached) { + if (!node.getType().equals(NodeIDType.OPENFLOW)) { + logger.error("Invalid node type"); + return null; + } + + return filter.readAllNodeTable(containerName, node, cached); + } } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java index 1b71c3bec3..bcb01b1392 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java @@ -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.NodeTable; 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.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.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. @@ -58,6 +61,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, private IController controller = null; private IOFStatisticsManager statsMgr = null; private Map> containerToNc; + private Map> containerToNt; public void setController(IController core) { this.controller = core; @@ -76,6 +80,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, */ void init() { containerToNc = new HashMap>(); + containerToNt = new HashMap>(); } /** @@ -174,9 +179,9 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, long sid = (Long) node.getID(); List 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; } + + public List filterTableListPerContainer( + String container, long switchId, List list) { + if (list == null) { + return null; + } + + // Create new filtered list of node tables + List newList = new ArrayList(); + + 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 @@ -251,7 +278,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, } 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); } + /** + * 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 tableSet = containerToNt.get(container); + return (tableSet == null) ? false : tableSet.contains(table); + } + /** * Returns whether the container flowspec allows the passed flow * @@ -382,11 +425,11 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, short portId = (Short) connector.getID(); List ofList = (cached == true) ? statsMgr .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics( - sid, OFStatisticsType.PORT, portId); + sid, OFStatisticsType.PORT, portId); - List ncStatistics = new PortStatisticsConverter( - sid, ofList).getNodeConnectorStatsList(); - return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics() + List ncStatistics = new PortStatisticsConverter( + sid, ofList).getNodeConnectorStatsList(); + return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics() : ncStatistics.get(0); } @@ -397,12 +440,12 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, long sid = (Long) node.getID(); List ofList = (cached == true) ? statsMgr .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid, - OFStatisticsType.FLOW, null); + OFStatisticsType.FLOW, null); - List filteredList = filterPortListPerContainer( - containerName, sid, ofList); + List filteredList = filterPortListPerContainer( + containerName, sid, ofList); - return new PortStatisticsConverter(sid, filteredList) + return new PortStatisticsConverter(sid, filteredList) .getNodeConnectorStatsList(); } @@ -418,4 +461,39 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, 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 ofList = (cached == true) ? statsMgr + .getOFTableStatistics(sid, tableId) : statsMgr.queryStatistics( + sid, OFStatisticsType.TABLE, tableId); + + List ntStatistics = new TableStatisticsConverter( + sid, ofList).getNodeTableStatsList(); + + return (ntStatistics.isEmpty()) ? new NodeTableStatistics() + : ntStatistics.get(0); + } + + @Override + public List readAllNodeTable(String containerName, + Node node, boolean cached) { + long sid = (Long) node.getID(); + List ofList = (cached == true) ? statsMgr + .getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, + OFStatisticsType.FLOW, null); + + List 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 index 0000000000..0b532848f7 --- /dev/null +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TableConverter.java @@ -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 index 0000000000..993f8976fc --- /dev/null +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TableStatisticsConverter.java @@ -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 ofStatsList; + private List ntStatsList; + + public TableStatisticsConverter(long switchId, List statsList) { + this.switchId = switchId; + if (statsList == null || statsList.isEmpty()) { + this.ofStatsList = new ArrayList(1); // dummy list + } else { + this.ofStatsList = new ArrayList(statsList); + } + this.ntStatsList = null; + } + + public List getNodeTableStatsList() { + if (this.ofStatsList != null && this.ntStatsList == null) { + this.ntStatsList = new ArrayList(); + 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; + } +} diff --git a/opendaylight/protocol_plugins/stub/src/main/java/org/opendaylight/controller/protocol_plugins/stub/internal/ReadService.java b/opendaylight/protocol_plugins/stub/src/main/java/org/opendaylight/controller/protocol_plugins/stub/internal/ReadService.java index 68bd3af751..27ba897fdf 100644 --- a/opendaylight/protocol_plugins/stub/src/main/java/org/opendaylight/controller/protocol_plugins/stub/internal/ReadService.java +++ b/opendaylight/protocol_plugins/stub/src/main/java/org/opendaylight/controller/protocol_plugins/stub/internal/ReadService.java @@ -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.NodeTable; 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.NodeTableStatistics; /** * Stub Implementation for IPluginInReadService used by SAL * @@ -233,4 +234,33 @@ public class ReadService implements IPluginInReadService { 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 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 result = new ArrayList(); + 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 index 0000000000..22c379614d --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/NodeTable.java @@ -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> compatibleType = + new ConcurrentHashMap>(); + /** + * 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 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 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(); + } + +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IPluginInReadService.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IPluginInReadService.java index c563037f1e..1b950d7cf5 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IPluginInReadService.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IPluginInReadService.java @@ -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.NodeTable; import org.opendaylight.controller.sal.flowprogrammer.Flow; /** @@ -63,10 +64,25 @@ public interface IPluginInReadService { public List 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 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); + } diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IReadService.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IReadService.java index 3a9f828d94..ae975f1a58 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IReadService.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IReadService.java @@ -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.NodeTable; import org.opendaylight.controller.sal.flowprogrammer.Flow; /** @@ -88,6 +89,28 @@ public interface IReadService { */ List 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 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 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 index 0000000000..3ccf8f5929 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/NodeTableStatistics.java @@ -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 + * 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 index 0000000000..5d69810c25 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeTableCreator.java @@ -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 index 0000000000..57286fe140 --- /dev/null +++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/core/NodeTableTest.java @@ -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 index 0000000000..c0d6bb698a --- /dev/null +++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/reader/NodeTableStatisticsTest.java @@ -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")); + } +} diff --git a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ReadService.java b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ReadService.java index 0ee48d5b88..fce0a39719 100644 --- a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ReadService.java +++ b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ReadService.java @@ -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.core.NodeTable; 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.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.NodeTableCreator; 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(), - entry.getValue()); + entry.getValue()); } 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(), - entry.getValue()); + entry.getValue()); } 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()) - .readFlow(node, flow, true); + .readFlow(node, flow, true); } } 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()) - .readFlow(node, flow, false); + .readFlow(node, flow, false); } } 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()) - .readAllFlow(node, true); + .readAllFlow(node, true); } } 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()) - .readAllFlow(node, false); + .readAllFlow(node, false); } } 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()) - .readDescription(node, true); + .readDescription(node, true); } } 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()) - .readDescription(node, false); + .readDescription(node, false); } } 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()) - .readNodeConnector(connector, true); + .readNodeConnector(connector, true); } } 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()) - .readNodeConnector(connector, false); + .readNodeConnector(connector, false); } } 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()) - .readAllNodeConnector(node, true); + .readAllNodeConnector(node, true); + } + } + logger.warn("Plugin unavailable"); + return null; + } + + @Override + public List 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"); @@ -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()) - .readAllNodeConnector(node, false); + .readAllNodeConnector(node, false); } } 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()) - .getTransmitRate(connector); + .getTransmitRate(connector); } } 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 - .append("\t readflows - Read all the (cached) flows from the openflow switch \n"); + .append("\t readflows - Read all the (cached) flows from the openflow switch \n"); help - .append("\t readflow - Read the (cached) sample flow from the openflow switch \n"); + .append("\t readflow - Read the (cached) sample flow from the openflow switch \n"); help - .append("\t readdesc - Read the (cached) description from openflow switch \n"); + .append("\t readdesc - Read the (cached) description from openflow switch \n"); 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 - .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(); } @@ -389,11 +431,11 @@ public class ReadService implements IReadService, CommandProvider { List 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) { @@ -417,11 +459,39 @@ public class ReadService implements IReadService, CommandProvider { 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) { diff --git a/opendaylight/statisticsmanager/api/src/main/java/org/opendaylight/controller/statisticsmanager/IStatisticsManager.java b/opendaylight/statisticsmanager/api/src/main/java/org/opendaylight/controller/statisticsmanager/IStatisticsManager.java index db7489d470..98977f6e91 100644 --- a/opendaylight/statisticsmanager/api/src/main/java/org/opendaylight/controller/statisticsmanager/IStatisticsManager.java +++ b/opendaylight/statisticsmanager/api/src/main/java/org/opendaylight/controller/statisticsmanager/IStatisticsManager.java @@ -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.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.NodeTableStatistics; /** * Interface which defines the available methods for retrieving @@ -79,4 +81,20 @@ public interface IStatisticsManager { * @return */ List 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 getNodeTableStatistics(Node node); } diff --git a/opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java b/opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java index f5f56fc70f..9aef40c413 100644 --- a/opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java +++ b/opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java @@ -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.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.reader.NodeTableStatistics; 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 getNodeConnectorStatistics(Node node) { return reader.readNodeConnectors(node); } + + @Override + public NodeTableStatistics getNodeTableStatistics(NodeTable nodeTable) { + return reader.readNodeTable(nodeTable); + } + + @Override + public List getNodeTableStatistics(Node node){ + return reader.readNodeTable(node); + } } -- 2.36.6