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>
# 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)
--- /dev/null
+/*
+ * 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;
+ }
+
+}
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;
@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(
@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,
@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) {
@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,
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);
--- /dev/null
+/*
+ * 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;
+ }
+
+}
+
+/*
+ * 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
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);
+ }
+
}
/**
* 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);
/**
/**
* 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);
/**
* 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);
/**
* 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
*/
/**
* 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);
* @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<OFStatistics> queryStatistics(Long switchId,
*/
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);
+
}
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
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
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;
* 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<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;
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);
type = t;
}
+ @Override
public String toString() {
return "SReq = {switchId=" + switchId + ", type=" + type + "}";
}
private short flowStatisticsTicks;
private short descriptionTicks;
private short portStatisticsTicks;
+ private short tableStatisticsTicks;
public StatisticsTicks(boolean scattered) {
if (scattered) {
% 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;
}
}
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 + "}";
}
}
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);
+ }
+ }
}
}
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);
// 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);
}
}
}
} 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);
} 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 {}",
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();
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) {
String flowStatsInterv = ci.nextArgument();
String portStatsInterv = ci.nextArgument();
String descStatsInterv = ci.nextArgument();
+ String tableStatsInterv = ci.nextArgument();
if (flowStatsInterv == null || portStatsInterv == null
|| descStatsInterv == null) {
+ 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");
}
/**
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 {
} catch (Exception e) {
}
}
+
+ if (tsStr != null) {
+ try{
+ ts = Short.parseShort(tsStr);
+ if (ts > 0) {
+ tableTickNumber = ts;
+ }
+ } catch (Exception e) {
+ }
+ }
}
}
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
}
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);
+ }
}
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.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.
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;
*/
void init() {
containerToNc = new HashMap<String, Set<NodeConnector>>();
+ containerToNt = new HashMap<String, Set<NodeTable>>();
}
/**
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();
}
/**
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
}
return (flowPortsBelongToContainer(container, node, flow)
&& flowVlanBelongsToContainer(container, node, flow) && flowSpecAllowsFlow(
- container, flow.getMatch()));
+ container, flow.getMatch()));
}
/**
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
*
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);
}
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();
}
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();
+ }
+
}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
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.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
*
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;
+ }
}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
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;
/**
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);
+
}
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;
/**
*/
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
--- /dev/null
+/*
+ * 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 + "]";
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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"));
+ }
+}
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.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;
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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
- .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
- .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
- .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();
}
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) {
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) {
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
* @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);
}
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;
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);
+ }
}