package org.opendaylight.controller.northbound.integrationtest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.Bundle;
-import javax.inject.Inject;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemPackages;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.BundleContext;
-import static org.junit.Assert.*;
-import org.ops4j.pax.exam.junit.Configuration;
-import static org.ops4j.pax.exam.CoreOptions.*;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.util.PathUtils;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Set;
-import org.apache.commons.codec.binary.Base64;
+import javax.inject.Inject;
+import org.apache.commons.codec.binary.Base64;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.codehaus.jettison.json.JSONTokener;
-
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import org.opendaylight.controller.hosttracker.IfIptoHost;
import org.opendaylight.controller.sal.core.Bandwidth;
import org.opendaylight.controller.sal.core.ConstructionException;
import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
import org.opendaylight.controller.switchmanager.IInventoryListener;
import org.opendaylight.controller.usermanager.IUserManager;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.util.PathUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@RunWith(PaxExam.class)
public class NorthboundIT {
// get the OSGI bundle context
@Inject
private BundleContext bc;
- private IUserManager users = null;
+ private IUserManager userManager = null;
private IInventoryListener invtoryListener = null;
private IListenTopoUpdates topoUpdates = null;
ServiceReference r = bc.getServiceReference(IUserManager.class.getName());
if (r != null) {
- this.users = (IUserManager) bc.getService(r);
+ this.userManager = (IUserManager) bc.getService(r);
}
// If UserManager is null, cannot login to run tests.
- assertNotNull(this.users);
+ assertNotNull(this.userManager);
r = bc.getServiceReference(IfIptoHost.class.getName());
if (r != null) {
try {
URL url = new URL(restUrl);
- this.users.getAuthorizationList();
- this.users.authenticate("admin", "admin");
+ this.userManager.getAuthorizationList();
+ this.userManager.authenticate("admin", "admin");
String authString = "admin:admin";
byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
String authStringEnc = new String(authEncBytes);
@Test
public void testStatistics() throws JSONException {
- String actionTypes[] = { "drop", "loopback", "flood", "floodAll", "controller", "swPath", "hwPath", "output",
+ final String actionTypes[] = { "drop", "loopback", "flood", "floodAll", "controller", "swPath", "hwPath", "output",
"setDlSrc", "setDlDst", "setDlType", "setVlanId", "setVlanPcp", "setVlanCfi", "popVlan", "pushVlan",
"setNwSrc", "setNwDst", "setNwTos", "setTpSrc", "setTpDst" };
System.out.println("Starting Statistics JAXB client.");
for (int i = 0; i < flowStats.length(); i++) {
JSONObject flowStat = flowStats.getJSONObject(i);
- testFlowStat(flowStat, actionTypes[i]);
+ testFlowStat(flowStat, actionTypes[i], i);
}
flowStats = json.getJSONArray("flowStat");
for (int i = 0; i < flowStats.length(); i++) {
JSONObject flowStat = flowStats.getJSONObject(i);
- testFlowStat(flowStat, actionTypes[i]);
+ testFlowStat(flowStat, actionTypes[i], i);
}
result = getJsonResult(baseURL + "portstats/STUB/51966");
Assert.assertTrue(portStat.getInt("collisionCount") == 4);
}
- private void testFlowStat(JSONObject flowStat, String actionType) throws JSONException {
+ private void testFlowStat(JSONObject flowStat, String actionType, int actIndex) throws JSONException {
Assert.assertTrue(flowStat.getInt("tableId") == 1);
Assert.assertTrue(flowStat.getInt("durationSeconds") == 40);
Assert.assertTrue(flowStat.getInt("durationNanoseconds") == 400);
// test that flow information is correct
JSONObject flow = flowStat.getJSONObject("flow");
- Assert.assertTrue(flow.getInt("priority") == 3500);
+ Assert.assertTrue(flow.getInt("priority") == (3500 + actIndex));
Assert.assertTrue(flow.getInt("idleTimeout") == 1000);
Assert.assertTrue(flow.getInt("hardTimeout") == 2000);
Assert.assertTrue(flow.getInt("id") == 12345);
mavenBundle("org.opendaylight.controller", "protocol_plugins.stub", "0.4.0-SNAPSHOT"),
// List all the opendaylight modules
- mavenBundle("org.opendaylight.controller", "security", "0.4.0-SNAPSHOT").noStart(),
- mavenBundle("org.opendaylight.controller", "sal", "0.5.0-SNAPSHOT"),
- mavenBundle("org.opendaylight.controller", "sal.implementation", "0.4.0-SNAPSHOT"),
- mavenBundle("org.opendaylight.controller", "statisticsmanager", "0.4.0-SNAPSHOT"),
- mavenBundle("org.opendaylight.controller", "statisticsmanager.implementation", "0.4.0-SNAPSHOT"),
+ mavenBundle("org.opendaylight.controller", "configuration", "0.4.0-SNAPSHOT"),
+ mavenBundle("org.opendaylight.controller", "configuration.implementation", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "containermanager", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "containermanager.implementation", "0.4.0-SNAPSHOT"),
- mavenBundle("org.opendaylight.controller", "forwardingrulesmanager", "0.4.0-SNAPSHOT"),
- mavenBundle("org.opendaylight.controller", "forwardingrulesmanager.implementation", "0.4.0-SNAPSHOT"),
- mavenBundle("org.opendaylight.controller", "arphandler", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "clustering.services", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "clustering.services-implementation", "0.4.0-SNAPSHOT"),
+ mavenBundle("org.opendaylight.controller", "security", "0.4.0-SNAPSHOT").noStart(),
+ mavenBundle("org.opendaylight.controller", "sal", "0.5.0-SNAPSHOT"),
+ mavenBundle("org.opendaylight.controller", "sal.implementation", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "switchmanager", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "switchmanager.implementation", "0.4.0-SNAPSHOT"),
- mavenBundle("org.opendaylight.controller", "configuration", "0.4.0-SNAPSHOT"),
- mavenBundle("org.opendaylight.controller", "configuration.implementation", "0.4.0-SNAPSHOT"),
+ mavenBundle("org.opendaylight.controller", "forwardingrulesmanager", "0.4.0-SNAPSHOT"),
+ mavenBundle("org.opendaylight.controller", "forwardingrulesmanager.implementation", "0.4.0-SNAPSHOT"),
+ mavenBundle("org.opendaylight.controller", "statisticsmanager", "0.4.0-SNAPSHOT"),
+ mavenBundle("org.opendaylight.controller", "statisticsmanager.implementation", "0.4.0-SNAPSHOT"),
+ mavenBundle("org.opendaylight.controller", "arphandler", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "hosttracker", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "hosttracker.implementation", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "arphandler", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "routing.dijkstra_implementation", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "topologymanager", "0.4.0-SNAPSHOT"),
-
mavenBundle("org.opendaylight.controller", "usermanager", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "usermanager.implementation", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "logging.bridge", "0.4.0-SNAPSHOT"),
mavenBundle("org.opendaylight.controller", "clustering.test", "0.4.0-SNAPSHOT"),
-
mavenBundle("org.opendaylight.controller", "forwarding.staticrouting", "0.4.0-SNAPSHOT"),
// Northbound bundles
--- /dev/null
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import java.util.List;
+
+import org.openflow.protocol.statistics.OFStatistics;
+
+/**
+ * Interface defines the api which gets called when the information
+ * contained in the OF statistics reply message from a network is updated with
+ * new one.
+ */
+public interface IOFStatisticsListener {
+ public void descriptionStatisticsRefreshed(Long switchId, List<OFStatistics> description);
+
+ public void flowStatisticsRefreshed(Long switchId, List<OFStatistics> flows);
+
+ public void portStatisticsRefreshed(Long switchId, List<OFStatistics> ports);
+
+ public void tableStatisticsRefreshed(Long switchId, List<OFStatistics> tables);
+}
*
* @param switchId the openflow datapath id
* @param ofMatch the openflow match to query. If null, the query is intended for all the flows
+ * @param priority Priority of the wanted flow
* @return the list of openflow statistics
*/
- List<OFStatistics> getOFFlowStatistics(Long switchId, OFMatch ofMatch);
+ List<OFStatistics> getOFFlowStatistics(Long switchId, OFMatch ofMatch, short priority);
/**
* Return the description statistics for the specified switch.
--- /dev/null
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import java.util.List;
+
+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.NodeDescription;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
+
+/**
+ * The Interface provides statistics updates to ReaderFilter listeners within
+ * the protocol plugin
+ */
+public interface IReadFilterInternalListener {
+
+ /**
+ * Notifies the hardware view of all the flow installed on the specified network node
+ * @param node
+ * @return
+ */
+ public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList);
+
+ /**
+ * Notifies the hardware view of the specified network node connector
+ * @param node
+ * @return
+ */
+ public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList);
+
+ /**
+ * Notifies all the table statistics for a node
+ * @param node
+ * @return
+ */
+ public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList);
+
+ /**
+ * Notifies the hardware view of all the flow installed on the specified network node
+ * @param node
+ * @return
+ */
+ public void nodeDescriptionStatisticsUpdated(Node node, NodeDescription nodeDescription);
+
+
+}
* It is implemented by the respective OF1.0 plugin component
*
*/
-public interface IPluginReadServiceFilter {
+public interface IReadServiceFilter {
/**
* Returns the hardware image for the specified flow
* on the specified network node for the passed container
+++ /dev/null
-package org.opendaylight.controller.protocol_plugin.openflow;
-
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
-
-/**
- * Interface which defines the api which gets called when the information
- * contained in the OF description statistics reply message from a network
- * is updated with new one.
- */
-public interface IStatisticsListener {
- public void descriptionRefreshed(Long switchId,
- OFDescriptionStatistics description);
-}
import org.opendaylight.controller.protocol_plugin.openflow.IInventoryProvider;
import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsListener;
import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
-import org.opendaylight.controller.protocol_plugin.openflow.IPluginReadServiceFilter;
+import org.opendaylight.controller.protocol_plugin.openflow.IReadFilterInternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IReadServiceFilter;
import org.opendaylight.controller.protocol_plugin.openflow.IRefreshInternalProvider;
-import org.opendaylight.controller.protocol_plugin.openflow.IStatisticsListener;
import org.opendaylight.controller.protocol_plugin.openflow.ITopologyServiceShimListener;
import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
import org.opendaylight.controller.sal.packet.IPluginInDataPacketService;
import org.opendaylight.controller.sal.packet.IPluginOutDataPacketService;
import org.opendaylight.controller.sal.reader.IPluginInReadService;
+import org.opendaylight.controller.sal.reader.IPluginOutReadService;
import org.opendaylight.controller.sal.topology.IPluginInTopologyService;
import org.opendaylight.controller.sal.topology.IPluginOutTopologyService;
import org.opendaylight.controller.sal.utils.GlobalConstants;
// export the service to be used by SAL
c.setInterface(
new String[] { IPluginInTopologyService.class.getName(),
- ITopologyServiceShimListener.class.getName() },
- null);
+ ITopologyServiceShimListener.class.getName() }, null);
// Hook the services coming in from SAL, as optional in
// case SAL is not yet there, could happen
c.add(createContainerServiceDependency(containerName)
if (imp.equals(InventoryService.class)) {
// export the service
c.setInterface(
- new String[] { IPluginInInventoryService.class.getName(),
+ new String[] {
+ IPluginInInventoryService.class.getName(),
IInventoryShimInternalListener.class.getName(),
IInventoryProvider.class.getName() }, null);
// Set the protocolPluginType property which will be used
// by SAL
props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), Node.NodeIDType.OPENFLOW);
- c.setInterface(IPluginInReadService.class.getName(), props);
+ c.setInterface(new String[] {
+ IReadFilterInternalListener.class.getName(),
+ IPluginInReadService.class.getName() }, props);
+
c.add(createServiceDependency()
- .setService(IPluginReadServiceFilter.class)
+ .setService(IReadServiceFilter.class)
.setCallbacks("setService", "unsetService")
.setRequired(true));
+ c.add(createContainerServiceDependency(containerName)
+ .setService(IPluginOutReadService.class)
+ .setCallbacks("setPluginOutReadServices",
+ "unsetPluginOutReadServices")
+ .setRequired(false));
}
if (imp.equals(FlowProgrammerNotifier.class)) {
IMessageListener.class.getName(),
IContainerListener.class.getName(),
IInventoryShimExternalListener.class.getName() },
- props);
+ props);
c.add(createServiceDependency()
.setService(IController.class, "(name=Controller)")
if (imp.equals(ReadServiceFilter.class)) {
- c.setInterface(
- new String[] { IPluginReadServiceFilter.class.getName(),
- IContainerListener.class.getName() }, null);
+ c.setInterface(new String[] {
+ IReadServiceFilter.class.getName(),
+ IContainerListener.class.getName(),
+ IOFStatisticsListener.class.getName() }, null);
c.add(createServiceDependency()
.setService(IController.class, "(name=Controller)")
.setService(IOFStatisticsManager.class)
.setCallbacks("setService", "unsetService")
.setRequired(true));
+ c.add(createServiceDependency()
+ .setService(IReadFilterInternalListener.class)
+ .setCallbacks("setReadFilterInternalListener",
+ "unsetReadFilterInternalListener")
+ .setRequired(false));
+
}
if (imp.equals(OFStatisticsManager.class)) {
.setCallbacks("setController", "unsetController")
.setRequired(true));
c.add(createServiceDependency()
- .setService(IStatisticsListener.class)
+ .setService(IOFStatisticsListener.class)
.setCallbacks("setStatisticsListener",
"unsetStatisticsListener").setRequired(false));
}
if (imp.equals(InventoryServiceShim.class)) {
c.setInterface(new String[] { IContainerListener.class.getName(),
- IStatisticsListener.class.getName()}, null);
+ IOFStatisticsListener.class.getName()}, null);
c.add(createServiceDependency()
.setService(IController.class, "(name=Controller)")
this.ofDesc = (statsList == null || statsList.isEmpty())?
null : (OFDescriptionStatistics) statsList.get(0);
}
+ public DescStatisticsConverter(OFDescriptionStatistics desc) {
+ this.hwDesc = null;
+ this.ofDesc = desc;
+ }
public NodeDescription getHwDescription() {
if (hwDesc == null && ofDesc != null) {
package org.opendaylight.controller.protocol_plugin.openflow.internal;
-import java.util.Collections;
-import java.util.Date;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArraySet;
import org.apache.felix.dm.Component;
import org.opendaylight.controller.protocol_plugin.openflow.IInventoryProvider;
import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener;
import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
-import org.opendaylight.controller.sal.core.ConstructionException;
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.Property;
import org.opendaylight.controller.sal.core.UpdateType;
IPluginInInventoryService, IInventoryProvider {
protected static final Logger logger = LoggerFactory
.getLogger(InventoryService.class);
- private Set<IPluginOutInventoryService> pluginOutInventoryServices = Collections
- .synchronizedSet(new HashSet<IPluginOutInventoryService>());
+ private Set<IPluginOutInventoryService> pluginOutInventoryServices;
private IController controller = null;
private ConcurrentMap<Node, Map<String, Property>> nodeProps; // properties are maintained in global container only
private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps; // properties are maintained in global container only
nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
+ pluginOutInventoryServices = new CopyOnWriteArraySet<IPluginOutInventoryService>();
}
/**
}
}
- protected Node OFSwitchToNode(ISwitch sw) {
- Node node = null;
- Object id = sw.getId();
-
- try {
- node = new Node(NodeIDType.OPENFLOW, id);
- } catch (ConstructionException e) {
- logger.error("", e);
- }
-
- return node;
- }
-
/**
* Retrieve nodes from openflow
*/
}
// update sal and discovery
- synchronized (pluginOutInventoryServices) {
- for (IPluginOutInventoryService service : pluginOutInventoryServices) {
- service.updateNodeConnector(nodeConnector, type, props);
- }
+ for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+ service.updateNodeConnector(nodeConnector, type, props);
}
+
}
private void addNode(Node node, Set<Property> props) {
nodeProps.put(node, propMap);
// update sal
- synchronized (pluginOutInventoryServices) {
- for (IPluginOutInventoryService service : pluginOutInventoryServices) {
- service.updateNode(node, UpdateType.ADDED, props);
- }
+ for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+ service.updateNode(node, UpdateType.ADDED, props);
}
}
}
// update sal
- synchronized (pluginOutInventoryServices) {
- for (IPluginOutInventoryService service : pluginOutInventoryServices) {
- service.updateNode(node, UpdateType.REMOVED, null);
- }
+ for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+ service.updateNode(node, UpdateType.REMOVED, null);
}
}
// Update SAL if we got new properties
if (!newProperties.isEmpty()) {
- synchronized (pluginOutInventoryServices) {
- for (IPluginOutInventoryService service : pluginOutInventoryServices) {
- service.updateNode(node, UpdateType.CHANGED, newProperties);
- }
+ for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+ service.updateNode(node, UpdateType.CHANGED, newProperties);
}
}
}
import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener;
-import org.opendaylight.controller.protocol_plugin.openflow.IStatisticsListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsListener;
import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
import org.opendaylight.controller.sal.core.TimeStamp;
import org.opendaylight.controller.sal.core.UpdateType;
import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.NodeCreator;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPortStatus;
import org.openflow.protocol.OFPortStatus.OFPortReason;
import org.openflow.protocol.OFType;
import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import org.openflow.protocol.statistics.OFStatistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*
*/
public class InventoryServiceShim implements IContainerListener,
- IMessageListener, ISwitchStateListener, IStatisticsListener {
+ IMessageListener, ISwitchStateListener, IOFStatisticsListener {
protected static final Logger logger = LoggerFactory
.getLogger(InventoryServiceShim.class);
private IController controller = null;
protected void handlePortStatusMessage(ISwitch sw, OFPortStatus m)
throws ConstructionException {
- Node node = new Node(NodeIDType.OPENFLOW, sw.getId());
+ Node node = NodeCreator.createOFNode(sw.getId());
NodeConnector nodeConnector = PortConverter.toNodeConnector(m.getDesc()
.getPortNumber(), node);
UpdateType type = null;
}
private void addNode(ISwitch sw) {
- Node node;
- try {
- node = new Node(NodeIDType.OPENFLOW, sw.getId());
- } catch (ConstructionException e) {
- logger.error("{}", e.getMessage());
- return;
- }
-
+ Node node = NodeCreator.createOFNode(sw.getId());
UpdateType type = UpdateType.ADDED;
Set<Property> props = new HashSet<Property>();
}
@Override
- public void descriptionRefreshed(Long switchId,
- OFDescriptionStatistics descriptionStats) {
- Node node;
- try {
- node = new Node(NodeIDType.OPENFLOW, switchId);
- } catch (ConstructionException e) {
- logger.error("{}", e.getMessage());
- return;
- }
-
+ public void descriptionStatisticsRefreshed(Long switchId, List<OFStatistics> descriptionStats) {
+ Node node = NodeCreator.createOFNode(switchId);
Set<Property> properties = new HashSet<Property>(1);
- Description desc = new Description(
- descriptionStats.getDatapathDescription());
+ OFDescriptionStatistics ofDesc = (OFDescriptionStatistics) descriptionStats.get(0);
+ Description desc = new Description(ofDesc.getDatapathDescription());
properties.add(desc);
// Notify all internal and external listeners
return mac;
}
+
+ @Override
+ public void flowStatisticsRefreshed(Long switchId, List<OFStatistics> flows) {
+ // Nothing to do
+ }
+
+ @Override
+ public void portStatisticsRefreshed(Long switchId, List<OFStatistics> ports) {
+ // Nothing to do
+ }
+
+ @Override
+ public void tableStatisticsRefreshed(Long switchId, List<OFStatistics> tables) {
+ // Nothing to do
+ }
}
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsListener;
import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
-import org.opendaylight.controller.protocol_plugin.openflow.IStatisticsListener;
import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Match;
import org.openflow.protocol.OFPort;
import org.openflow.protocol.OFStatisticsRequest;
import org.openflow.protocol.statistics.OFAggregateStatisticsRequest;
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
import org.openflow.protocol.statistics.OFFlowStatisticsReply;
import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
import org.openflow.protocol.statistics.OFPortStatisticsReply;
*/
public class OFStatisticsManager implements IOFStatisticsManager,
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 final Logger log = LoggerFactory.getLogger(OFStatisticsManager.class);
+ private static final int INITIAL_SIZE = 64;
+ private static final long FLOW_STATS_PERIOD = 10000;
+ private static final long DESC_STATS_PERIOD = 60000;
+ private static final long PORT_STATS_PERIOD = 5000;
+ private static final long TABLE_STATS_PERIOD = 10000;
+ private static final long TICK = 1000;
+ private static short statisticsTickNumber = (short) (FLOW_STATS_PERIOD / TICK);
+ private static short descriptionTickNumber = (short) (DESC_STATS_PERIOD / TICK);
+ private static short portTickNumber = (short) (PORT_STATS_PERIOD / TICK);
+ private static short tableTickNumber = (short) (TABLE_STATS_PERIOD / TICK);
private static short factoredSamples = (short) 2;
private static short counter = 1;
private IController controller = null;
private Timer statisticsTimer;
private TimerTask statisticsTimerTask;
private ConcurrentMap<Long, Boolean> switchSupportsVendorExtStats;
- private Map<Long, Map<Short, TxRates>> txRates; // Per port sampled (every
- // portStatsPeriod) transmit
- // rate
- private Set<IStatisticsListener> descriptionListeners;
+ // Per port sampled (every portStatsPeriod) transmit rate
+ private Map<Long, Map<Short, TxRates>> txRates;
+ private Set<IOFStatisticsListener> statisticsListeners;
/**
* The object containing the latest factoredSamples tx rate samples for a
* given switch port
*/
protected class TxRates {
- Deque<Long> sampledTxBytes; // contains the latest factoredSamples
- // sampled transmitted bytes
+ // contains the latest factoredSamples sampled transmitted bytes
+ Deque<Long> sampledTxBytes;
public TxRates() {
sampledTxBytes = new LinkedBlockingDeque<Long>();
if (sampledTxBytes.size() < factoredSamples) {
return average;
}
- long increment = (long) (sampledTxBytes.getFirst() - sampledTxBytes
- .getLast());
- long timePeriod = (long) (factoredSamples * portStatsPeriod)
- / (long) tickPeriod;
+ long increment = sampledTxBytes.getFirst() - sampledTxBytes
+ .getLast();
+ long timePeriod = factoredSamples * PORT_STATS_PERIOD / TICK;
average = (8L * increment) / timePeriod;
return average;
}
portStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
tableStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
dummyList = new ArrayList<OFStatistics>(1);
- statisticsTimerTicks = new ConcurrentHashMap<Long, StatisticsTicks>(
- initialSize);
- pendingStatsRequests = new LinkedBlockingQueue<StatsRequest>(
- initialSize);
- switchPortStatsUpdated = new LinkedBlockingQueue<Long>(initialSize);
- switchSupportsVendorExtStats = new ConcurrentHashMap<Long, Boolean>(
- initialSize);
- txRates = new HashMap<Long, Map<Short, TxRates>>(initialSize);
- descriptionListeners = new HashSet<IStatisticsListener>();
+ statisticsTimerTicks = new ConcurrentHashMap<Long, StatisticsTicks>(INITIAL_SIZE);
+ pendingStatsRequests = new LinkedBlockingQueue<StatsRequest>(INITIAL_SIZE);
+ switchPortStatsUpdated = new LinkedBlockingQueue<Long>(INITIAL_SIZE);
+ switchSupportsVendorExtStats = new ConcurrentHashMap<Long, Boolean>(INITIAL_SIZE);
+ txRates = new HashMap<Long, Map<Short, TxRates>>(INITIAL_SIZE);
+ statisticsListeners = new CopyOnWriteArraySet<IOFStatisticsListener>();
configStatsPollIntervals();
while (true) {
try {
StatsRequest req = pendingStatsRequests.take();
- acquireStatistics(req.switchId, req.type);
+ queryStatisticsInternal(req.switchId, req.type);
} catch (InterruptedException e) {
log.warn("Flow Statistics Collector thread "
+ "interrupted", e);
*/
void start() {
// Start managed timers
- statisticsTimer.scheduleAtFixedRate(statisticsTimerTask, 0, tickPeriod);
+ statisticsTimer.scheduleAtFixedRate(statisticsTimerTask, 0, TICK);
// Start statistics collector thread
statisticsCollector.start();
statisticsTimer.cancel();
}
- public void setStatisticsListener(IStatisticsListener s) {
- this.descriptionListeners.add(s);
+ public void setStatisticsListener(IOFStatisticsListener s) {
+ this.statisticsListeners.add(s);
}
- public void unsetStatisticsListener(IStatisticsListener s) {
+ public void unsetStatisticsListener(IOFStatisticsListener s) {
if (s != null) {
- this.descriptionListeners.remove(s);
+ this.statisticsListeners.remove(s);
}
}
private void registerWithOSGIConsole() {
- BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
- .getBundleContext();
- bundleContext.registerService(CommandProvider.class.getName(), this,
- null);
+ BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+ bundleContext.registerService(CommandProvider.class.getName(), this, null);
}
private static class StatsRequest {
// extension
// stats
statisticsTimerTicks.put(switchId, new StatisticsTicks(true));
- log.info("Added Switch {} to target pool",
+ log.debug("Added Switch {} to target pool",
HexString.toHexString(switchId.longValue()));
}
}
private void printInfoMessage(String type, StatsRequest request) {
- log.info(
- "{} stats request not inserted for switch: {}. Queue size: {}. Collector state: {}.",
- new Object[] { type, HexString.toHexString(request.switchId),
- pendingStatsRequests.size(),
- statisticsCollector.getState().toString() });
+ log.info("{} stats request not inserted for switch: {}. Queue size: {}. Collector state: {}.",
+ new Object[] {type, HexString.toHexString(request.switchId), pendingStatsRequests.size(),
+ statisticsCollector.getState().toString() });
}
protected void decrementTicks() {
.entrySet()) {
StatisticsTicks clock = entry.getValue();
Long switchId = entry.getKey();
- if (clock.decrementFlowTicksIsZero() == true) {
- request = (switchSupportsVendorExtStats.get(switchId) == Boolean.TRUE) ? new StatsRequest(
- switchId, OFStatisticsType.VENDOR) : new StatsRequest(
- switchId, OFStatisticsType.FLOW);
+ if (clock.decrementFlowTicksIsZero()) {
+ request = (switchSupportsVendorExtStats.get(switchId) == Boolean.TRUE) ?
+ new StatsRequest(switchId, OFStatisticsType.VENDOR) :
+ new StatsRequest(switchId, OFStatisticsType.FLOW);
// If a request for this switch is already in the queue, skip to
// add this new request
if (!pendingStatsRequests.contains(request)
}
}
- if (clock.decrementDescTicksIsZero() == true) {
+ if (clock.decrementDescTicksIsZero()) {
request = new StatsRequest(switchId, OFStatisticsType.DESC);
// If a request for this switch is already in the queue, skip to
// add this new request
}
}
- if (clock.decrementPortTicksIsZero() == true) {
+ if (clock.decrementPortTicksIsZero()) {
request = new StatsRequest(switchId, OFStatisticsType.PORT);
// If a request for this switch is already in the queue, skip to
// add this new request
}
}
- if(clock.decrementTableTicksIsZero() == true) {
+ if(clock.decrementTableTicksIsZero()) {
request = new StatsRequest(switchId, OFStatisticsType.TABLE);
// If a request for this switch is already in the queue, skip to
// add this new request
}
private void removeStatsRequestTasks(Long switchId) {
- log.info("Cleaning Statistics database for switch {}",
+ log.debug("Cleaning Statistics database for switch {}",
HexEncode.longToHexString(switchId));
// To be safe, let's attempt removal of both VENDOR and FLOW request. It
// does not hurt
statisticsTimerTicks.remove(switchId);
removeStatsRequestTasks(switchId);
flowStatistics.remove(switchId);
- log.info("Statistics removed for switch {}",
+ log.debug("Statistics removed for switch {}",
HexString.toHexString(switchId));
}
- private void acquireStatistics(Long switchId, OFStatisticsType statType) {
+ private void queryStatisticsInternal(Long switchId, OFStatisticsType statType) {
// Query the switch on all matches
- List<OFStatistics> values = this.acquireStatistics(switchId, statType,
- null);
+ List<OFStatistics> values = this.fetchStatisticsFromSwitch(switchId, statType, null);
- // Update local caching database if got a valid response
+ // If got a valid response update local cache and notify listeners
if (values != null && !values.isEmpty()) {
- if ((statType == OFStatisticsType.FLOW)
- || (statType == OFStatisticsType.VENDOR)) {
- flowStatistics.put(switchId, values);
- } else if (statType == OFStatisticsType.DESC) {
- // Notify who may be interested in a description change
- notifyDescriptionListeners(switchId, values);
-
- // Overwrite cache
- descStatistics.put(switchId, values);
- } else if (statType == OFStatisticsType.PORT) {
- // Overwrite cache with new port statistics for this switch
- portStatistics.put(switchId, values);
-
- // 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);
+ switch (statType) {
+ case FLOW:
+ case VENDOR:
+ flowStatistics.put(switchId, values);
+ notifyFlowUpdate(switchId, values);
+ break;
+ case DESC:
+ // Overwrite cache
+ descStatistics.put(switchId, values);
+ // Notify who may be interested in a description change
+ notifyDescriptionUpdate(switchId, values);
+ break;
+ case PORT:
+ // Overwrite cache with new port statistics for this switch
+ portStatistics.put(switchId, values);
+
+ // Wake up the thread which maintains the TX byte counters for
+ // each port
+ switchPortStatsUpdated.offer(switchId);
+ notifyPortUpdate(switchId, values);
+ break;
+ case TABLE:
+ // Overwrite cache
+ tableStatistics.put(switchId, values);
+ notifyTableUpdate(switchId, values);
+ break;
+ default:
}
}
}
- private void notifyDescriptionListeners(Long switchId,
- List<OFStatistics> values) {
- for (IStatisticsListener l : this.descriptionListeners) {
- l.descriptionRefreshed(switchId,
- ((OFDescriptionStatistics) values.get(0)));
+ private void notifyDescriptionUpdate(Long switchId, List<OFStatistics> values) {
+ for (IOFStatisticsListener l : this.statisticsListeners) {
+ l.descriptionStatisticsRefreshed(switchId, values);
+ }
+ }
+
+ private void notifyFlowUpdate(Long switchId, List<OFStatistics> values) {
+ if (values.get(0) instanceof OFVendorStatistics) {
+ values = this.v6StatsListToOFStatsList(values);
+ }
+
+ if (!values.isEmpty()) { //possiblly filtered out by v6StatsListToOFStatsList()
+ for (IOFStatisticsListener l : this.statisticsListeners) {
+ l.flowStatisticsRefreshed(switchId, values);
+ }
+ }
+ }
+
+ private void notifyPortUpdate(Long switchId, List<OFStatistics> values) {
+ for (IOFStatisticsListener l : this.statisticsListeners) {
+ l.portStatisticsRefreshed(switchId, values);
+ }
+ }
+
+ private void notifyTableUpdate(Long switchId, List<OFStatistics> values) {
+ for (IOFStatisticsListener l : this.statisticsListeners) {
+ l.tableStatisticsRefreshed(switchId, values);
}
}
/*
- * Generic function to get the statistics form a OF switch
+ * Generic function to get the statistics form an OF switch
*/
@SuppressWarnings("unchecked")
- private List<OFStatistics> acquireStatistics(Long switchId,
+ private List<OFStatistics> fetchStatisticsFromSwitch(Long switchId,
OFStatisticsType statsType, Object target) {
List<OFStatistics> values = null;
String type = null;
short targetPort;
if (target == null) {
// All ports request
- targetPort = (short) OFPort.OFPP_NONE.getValue();
+ targetPort = OFPort.OFPP_NONE.getValue();
} else if (!(target instanceof Short)) {
// Malformed request
log.warn("Invalid target type for Port stats request: {}",
type = "PORT";
} else if (statsType == OFStatisticsType.QUEUE) {
OFQueueStatisticsRequest specificReq = new OFQueueStatisticsRequest();
- specificReq.setPortNumber((short) OFPort.OFPP_ALL.getValue());
+ specificReq.setPortNumber(OFPort.OFPP_ALL.getValue());
specificReq.setQueueId(0xffffffff);
req.setStatistics(Collections
.singletonList((OFStatistics) specificReq));
}
@Override
- public List<OFStatistics> getOFFlowStatistics(Long switchId, OFMatch ofMatch) {
+ public List<OFStatistics> getOFFlowStatistics(Long switchId, OFMatch ofMatch, short priority) {
List<OFStatistics> statsList = flowStatistics.get(switchId);
/*
for (OFStatistics stats : targetList) {
V6StatsReply v6Stats = (V6StatsReply) stats;
V6Match v6Match = v6Stats.getMatch();
- if (v6Match.equals(targetMatch)) {
+ if (v6Stats.getPriority() == priority && v6Match.equals(targetMatch)) {
List<OFStatistics> list = new ArrayList<OFStatistics>();
list.add(stats);
return list;
} else {
for (OFStatistics stats : statsList) {
OFFlowStatisticsReply flowStats = (OFFlowStatisticsReply) stats;
- if (flowStats.getMatch().equals(ofMatch)) {
+ if (flowStats.getPriority() == priority && flowStats.getMatch().equals(ofMatch)) {
List<OFStatistics> list = new ArrayList<OFStatistics>();
list.add(stats);
return list;
}
}
- List<OFStatistics> list = this.acquireStatistics(switchId, statType,
+ List<OFStatistics> list = this.fetchStatisticsFromSwitch(switchId, statType,
target);
- return (list == null) ? null
- : (statType == OFStatisticsType.VENDOR) ? v6StatsListToOFStatsList(list)
- : list;
+ return (list == null) ? null :
+ (statType == OFStatisticsType.VENDOR) ? v6StatsListToOFStatsList(list) : list;
}
@Override
* @param switchId
*/
private synchronized void updatePortsTxRate(long switchId) {
- List<OFStatistics> newPortStatistics = this.portStatistics
- .get(switchId);
+ List<OFStatistics> newPortStatistics = this.portStatistics.get(switchId);
if (newPortStatistics == null) {
return;
}
help.append("---OF Statistics Manager utilities---\n");
help.append("\t ofdumpstatsmgr - "
+ "Print Internal Stats Mgr db\n");
- help.append("\t ofstatsmgrintervals <fP> <pP> <dP>(in seconds) - "
+ help.append("\t ofstatsmgrintervals <fP> <pP> <dP> <tP> (all in seconds) - "
+ "Set/Show flow/port/dedscription stats poll intervals\n");
return help.toString();
}
if (flowStatsInterv == null || portStatsInterv == null
|| descStatsInterv == null) {
- ci.println("Usage: ostatsmgrintervals <fP> <pP> <dP>(in seconds)");
- ci.println("Current Values: fP=" + statisticsTickNumber + "s pP="
- + portTickNumber + "s dP=" + descriptionTickNumber + "s");
+ ci.println("Usage: ofstatsmgrintervals <fP> <pP> <dP> <tP> (all in seconds)");
+ ci.println("Current Values: fP=" + statisticsTickNumber + "sec pP="
+ + portTickNumber + "sec dP=" + descriptionTickNumber + "sec tP=" + tableTickNumber + " sec");
return;
}
Short fP, pP, dP, tP;
import java.util.Dictionary;
import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
import org.apache.felix.dm.Component;
-import org.opendaylight.controller.protocol_plugin.openflow.IPluginReadServiceFilter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
+import org.opendaylight.controller.protocol_plugin.openflow.IReadFilterInternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IReadServiceFilter;
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.flowprogrammer.Flow;
import org.opendaylight.controller.sal.reader.FlowOnNode;
import org.opendaylight.controller.sal.reader.IPluginInReadService;
+import org.opendaylight.controller.sal.reader.IPluginOutReadService;
import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
import org.opendaylight.controller.sal.reader.NodeDescription;
import org.opendaylight.controller.sal.reader.NodeTableStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Container Instance of IPluginInReadService implementation class
- *
- *
- *
*/
-public class ReadService implements IPluginInReadService {
+public class ReadService implements IPluginInReadService, IReadFilterInternalListener {
private static final Logger logger = LoggerFactory
.getLogger(ReadService.class);
- private IPluginReadServiceFilter filter;
+ private IReadServiceFilter filter;
+ private Set<IPluginOutReadService> pluginOutReadServices;
private String containerName;
/**
Dictionary<Object, Object> props = c.getServiceProperties();
containerName = (props != null) ? (String) props.get("containerName")
: null;
+ pluginOutReadServices = new CopyOnWriteArraySet<IPluginOutReadService>();
}
/**
void stop() {
}
- public void setService(IPluginReadServiceFilter filter) {
+ public void setService(IReadServiceFilter filter) {
this.filter = filter;
}
- public void unsetService(IPluginReadServiceFilter filter) {
+ public void unsetService(IReadServiceFilter filter) {
this.filter = null;
}
+ public void setPluginOutReadServices(IPluginOutReadService service) {
+ logger.trace("Got a service set request {}", service);
+ if (this.pluginOutReadServices != null) {
+ this.pluginOutReadServices.add(service);
+ }
+ }
+
+ public void unsetPluginOutReadServices(
+ IPluginOutReadService service) {
+ logger.trace("Got a service UNset request");
+ if (this.pluginOutReadServices != null) {
+ this.pluginOutReadServices.remove(service);
+ }
+ }
@Override
public FlowOnNode readFlow(Node node, Flow flow, boolean cached) {
if (!node.getType().equals(NodeIDType.OPENFLOW)) {
return filter.readAllNodeTable(containerName, node, cached);
}
+
+ @Override
+ public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
+ for (IPluginOutReadService service : pluginOutReadServices) {
+ service.nodeFlowStatisticsUpdated(node, flowStatsList);
+ }
+ }
+
+ @Override
+ public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
+ for (IPluginOutReadService service : pluginOutReadServices) {
+ service.nodeConnectorStatisticsUpdated(node, ncStatsList);
+ }
+ }
+
+ @Override
+ public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
+ for (IPluginOutReadService service : pluginOutReadServices) {
+ service.nodeTableStatisticsUpdated(node, tableStatsList);
+ }
+ }
+
+ @Override
+ public void nodeDescriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
+ for (IPluginOutReadService service : pluginOutReadServices) {
+ service.descriptionStatisticsUpdated(node, nodeDescription);
+ }
+ }
}
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsListener;
import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
-import org.opendaylight.controller.protocol_plugin.openflow.IPluginReadServiceFilter;
+import org.opendaylight.controller.protocol_plugin.openflow.IReadFilterInternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IReadServiceFilter;
import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
-import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.statistics.OFPortStatisticsReply;
-import org.openflow.protocol.statistics.OFStatistics;
-import org.openflow.protocol.statistics.OFStatisticsType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import org.opendaylight.controller.sal.action.Action;
import org.opendaylight.controller.sal.action.ActionType;
import org.opendaylight.controller.sal.action.Output;
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.OFMatch;
+import org.openflow.protocol.statistics.OFFlowStatisticsReply;
+import org.openflow.protocol.statistics.OFPortStatisticsReply;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
import org.openflow.protocol.statistics.OFTableStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Read Service shim layer which is in charge of filtering the flow statistics
* based on container. It is a Global instance.
*
*
*/
-public class ReadServiceFilter implements IPluginReadServiceFilter,
- IContainerListener {
+public class ReadServiceFilter implements IReadServiceFilter, IContainerListener, IOFStatisticsListener {
private static final Logger logger = LoggerFactory
.getLogger(ReadServiceFilter.class);
private IController controller = null;
private IOFStatisticsManager statsMgr = null;
private Map<String, Set<NodeConnector>> containerToNc;
+ private Map<String, Set<Node>> containerToNode;
private Map<String, Set<NodeTable>> containerToNt;
+ private ConcurrentMap<String, IReadFilterInternalListener> readFilterInternalListeners;
public void setController(IController core) {
this.controller = core;
}
}
+ public void setReadFilterInternalListener(Map<?, ?> props, IReadFilterInternalListener s) {
+ if (props == null) {
+ logger.error("Failed setting Read Filter Listener, property map is null.");
+ return;
+ }
+ String containerName = (String) props.get("containerName");
+ if (containerName == null) {
+ logger.error("Failed setting Read Filter Listener, container name not supplied.");
+ return;
+ }
+ if ((this.readFilterInternalListeners != null) && !this.readFilterInternalListeners.containsValue(s)) {
+ this.readFilterInternalListeners.put(containerName, s);
+ logger.trace("Added Read Filter Listener for container {}", containerName);
+ }
+ }
+
+ public void unsetReadFilterInternalListener(Map<?, ?> props, IReadFilterInternalListener s) {
+ if (props == null) {
+ logger.error("Failed unsetting Read Filter Listener, property map is null.");
+ return;
+ }
+ String containerName = (String) props.get("containerName");
+ if (containerName == null) {
+ logger.error("Failed unsetting Read Filter Listener, containerName not supplied");
+ return;
+ }
+ if ((this.readFilterInternalListeners != null) && this.readFilterInternalListeners.get(containerName) != null
+ && this.readFilterInternalListeners.get(containerName).equals(s)) {
+ this.readFilterInternalListeners.remove(containerName);
+ logger.trace("Removed Read Filter Listener for container {}", containerName);
+ }
+ }
+
/**
* Function called by the dependency manager when all the required
* dependencies are satisfied
void init() {
containerToNc = new HashMap<String, Set<NodeConnector>>();
containerToNt = new HashMap<String, Set<NodeTable>>();
+ containerToNode = new HashMap<String, Set<Node>>();
+ readFilterInternalListeners = new ConcurrentHashMap<String, IReadFilterInternalListener>();
}
/**
long sid = (Long) node.getID();
OFMatch ofMatch = new FlowConverter(flow).getOFMatch();
- List<OFStatistics> ofList = (cached == true) ? statsMgr
- .getOFFlowStatistics(sid, ofMatch) : statsMgr.queryStatistics(
- sid, OFStatisticsType.FLOW, ofMatch);
+ List<OFStatistics> ofList;
+ if (cached == true){
+ ofList = statsMgr.getOFFlowStatistics(sid, ofMatch, flow.getPriority());
+ } else {
+ ofList = statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, ofMatch);
+ for (OFStatistics ofStat : ofList) {
+ if (((OFFlowStatisticsReply)ofStat).getPriority() == flow.getPriority()){
+ ofList = new ArrayList<OFStatistics>(1);
+ ofList.add(ofStat);
+ break;
+ }
+ }
+ }
+
/*
* Convert and filter the statistics per container
}
/**
- * Filters a list of FlowOnNode elements based on the container
+ * Filters a list of OFStatistics elements based on the container
*
* @param container
* @param nodeId
* @param flow
* @return
*/
- private boolean flowVlanBelongsToContainer(String container, Node node,
- Flow flow) {
+ private boolean flowVlanBelongsToContainer(String container, Node node, Flow flow) {
return true; // Always true for now
}
// If an outgoing port is specified, it must belong to this container
for (Action action : flow.getActions()) {
if (action.getType() == ActionType.OUTPUT) {
- NodeConnector outPort = (NodeConnector) ((Output) action)
+ NodeConnector outPort = ((Output) action)
.getPort();
if (!containerOwnsNodeConnector(container, outPort)) {
return false;
}
@Override
- public void containerFlowUpdated(String containerName,
- ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
-
+ public void containerFlowUpdated(String containerName, ContainerFlow previousFlow,
+ ContainerFlow currentFlow, UpdateType t) {
+ // TODO
}
@Override
public void nodeConnectorUpdated(String containerName, NodeConnector p,
UpdateType type) {
- Set<NodeConnector> target = null;
switch (type) {
case ADDED:
if (!containerToNc.containsKey(containerName)) {
- containerToNc.put(containerName, new HashSet<NodeConnector>());
+ containerToNc.put(containerName, new ConcurrentSkipListSet<NodeConnector>());
}
containerToNc.get(containerName).add(p);
- break;
- case CHANGED:
+ if (!containerToNode.containsKey(containerName)) {
+ containerToNode.put(containerName, new HashSet<Node>());
+ }
+ containerToNode.get(containerName).add(p.getNode());
break;
case REMOVED:
- target = containerToNc.get(containerName);
- if (target != null) {
- target.remove(p);
+ Set<NodeConnector> ncSet = containerToNc.get(containerName);
+ if (ncSet != null) {
+ //remove this nc from container map
+ ncSet.remove(p);
+
+ //check if there are still ports of this node in this container
+ //and if not, remove its mapping
+ boolean nodeInContainer = false;
+ Node node = p.getNode();
+ for (NodeConnector nodeConnector : ncSet) {
+ if (nodeConnector.getNode().equals(node)){
+ nodeInContainer = true;
+ break;
+ }
+ }
+ if (! nodeInContainer) {
+ Set<Node> nodeSet = containerToNode.get(containerName);
+ if (nodeSet != null) {
+ nodeSet.remove(node);
+ }
+ }
+
}
break;
+ case CHANGED:
default:
}
}
@Override
- public void tagUpdated(String containerName, Node n, short oldTag,
- short newTag, UpdateType t) {
+ public void tagUpdated(String containerName, Node n, short oldTag, short newTag, UpdateType t) {
// Not interested in this event
}
@Override
public void containerModeUpdated(UpdateType t) {
- // do nothing
+ // Not interested in this event
}
@Override
- public NodeConnectorStatistics readNodeConnector(String containerName,
- NodeConnector connector, boolean cached) {
+ public NodeConnectorStatistics readNodeConnector(
+ String containerName, NodeConnector connector, boolean cached) {
if (!containerOwnsNodeConnector(containerName, connector)) {
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<OFStatistics> ofList = (cached == true) ? statsMgr.getOFTableStatistics(sid, tableId) :
+ statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, tableId);
- List<NodeTableStatistics> ntStatistics = new TableStatisticsConverter(
- sid, ofList).getNodeTableStatsList();
+ List<NodeTableStatistics> ntStatistics =
+ new TableStatisticsConverter(sid, ofList).getNodeTableStatsList();
- return (ntStatistics.isEmpty()) ? new NodeTableStatistics()
- : ntStatistics.get(0);
+ return (ntStatistics.isEmpty()) ? new NodeTableStatistics() : ntStatistics.get(0);
}
@Override
- public List<NodeTableStatistics> readAllNodeTable(String containerName,
- Node node, boolean cached) {
+ 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> ofList = (cached == true) ?
+ statsMgr.getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, null);
- List<OFStatistics> filteredList = filterTableListPerContainer(
- containerName, sid, ofList);
+ List<OFStatistics> filteredList = filterTableListPerContainer(containerName, sid, ofList);
- return new TableStatisticsConverter(sid, filteredList)
- .getNodeTableStatsList();
+ return new TableStatisticsConverter(sid, filteredList).getNodeTableStatsList();
}
+ @Override
+ public void descriptionStatisticsRefreshed(Long switchId, List<OFStatistics> description) {
+ String container;
+ Node node = NodeCreator.createOFNode(switchId);
+ NodeDescription nodeDescription = new DescStatisticsConverter(description).getHwDescription();
+ for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
+ container = l.getKey();
+ if (container == GlobalConstants.DEFAULT.toString()
+ || (containerToNode.containsKey(container) && containerToNode.get(container).contains(node))) {
+ l.getValue().nodeDescriptionStatisticsUpdated(node, nodeDescription);
+ }
+ }
+ }
+
+ @Override
+ public void flowStatisticsRefreshed(Long switchId, List<OFStatistics> flows) {
+ String container;
+ Node node = NodeCreator.createOFNode(switchId);
+ for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
+ container = l.getKey();
+
+ // Convert and filter the statistics per container
+ List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(flows).getFlowOnNodeList(node);
+ flowOnNodeList = filterFlowListPerContainer(container, node, flowOnNodeList);
+
+ // notify listeners
+ if (!flowOnNodeList.isEmpty()) {
+ l.getValue().nodeFlowStatisticsUpdated(node, flowOnNodeList);
+ }
+ }
+ }
+
+ @Override
+ public void portStatisticsRefreshed(Long switchId, List<OFStatistics> ports) {
+ String container;
+ Node node = NodeCreator.createOFNode(switchId);
+ for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
+ container = l.getKey();
+
+ // Convert and filter the statistics per container
+ List<OFStatistics> filteredPorts = filterPortListPerContainer(container, switchId, ports);
+ List<NodeConnectorStatistics> ncStatsList = new PortStatisticsConverter(switchId, filteredPorts)
+ .getNodeConnectorStatsList();
+
+ // notify listeners
+ if (!ncStatsList.isEmpty()) {
+ l.getValue().nodeConnectorStatisticsUpdated(node, ncStatsList);
+ }
+ }
+ }
+
+ @Override
+ public void tableStatisticsRefreshed(Long switchId, List<OFStatistics> tables) {
+ String container;
+ Node node = NodeCreator.createOFNode(switchId);
+ for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
+ container = l.getKey();
+
+ // Convert and filter the statistics per container
+ List<OFStatistics> filteredList = filterTableListPerContainer(container, switchId, tables);
+ List<NodeTableStatistics> tableStatsList = new TableStatisticsConverter(switchId, filteredList)
+ .getNodeTableStatsList();
+
+ // notify listeners
+ if (!tableStatsList.isEmpty()) {
+ l.getValue().nodeTableStatisticsUpdated(node, tableStatsList);
+ }
+ }
+ }
}
import org.openflow.protocol.OFError.OFPortModFailedCode;
import org.openflow.protocol.OFError.OFQueueOpFailedCode;
-public abstract class Utils {
- public static String getOFErrorString(OFError error) {
+public final class Utils {
+
+ private Utils() { //prevent instantiation
+ throw new AssertionError();
+ }
+ static String getOFErrorString(OFError error) {
// Handle VENDOR extension errors here
if (error.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) {
V6Error er = new V6Error(error);
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
-import java.util.Dictionary;
import java.util.List;
-import org.apache.felix.dm.Component;
-//import org.opendaylight.controller.protocol_plugin_stubs.IPluginReadServiceFilter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import org.opendaylight.controller.sal.action.Action;
import org.opendaylight.controller.sal.action.Controller;
import org.opendaylight.controller.sal.action.Drop;
import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
import org.opendaylight.controller.sal.reader.NodeDescription;
import org.opendaylight.controller.sal.reader.NodeTableStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Stub Implementation for IPluginInReadService used by SAL
*
ArrayList<FlowOnNode> list = new ArrayList<FlowOnNode>();
ArrayList<Action> actionList = new ArrayList<Action>();
- actionList.add(new Drop());
+ actionList.add(new Drop()); //IT assumes this is first element
actionList.add(new Loopback());
actionList.add(new Flood());
actionList.add(new FloodAll());
actionList.add(new SetTpSrc(4201));
actionList.add(new SetTpDst(8080));
+ short priority = 3500; //IT assumes this value
for (Action a : actionList) {
Flow flow = new Flow();
Match match = new Match();
List<Action> actions = new ArrayList<Action>();
actions.add(a);
flow.setActions(actions);
- flow.setPriority((short) 3500);
+ flow.setPriority(priority++);
flow.setIdleTimeout((short) 1000);
flow.setHardTimeout((short) 2000);
flow.setId(12345);
package org.opendaylight.controller.sal.reader;
+import java.io.Serializable;
+
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@XmlRootElement (name="FlowStat")
@XmlAccessorType(XmlAccessType.NONE)
-public class FlowOnNode {
+public class FlowOnNode implements Serializable{
+ private static final long serialVersionUID = 1L;
+
@XmlElement
private Flow flow; // Flow descriptor
@XmlElement
--- /dev/null
+
+/*
+ * 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.sal.reader;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.core.Node;
+
+/**
+ * @file IPluginOutReadService.java
+ *
+ * @brief Hardware statistics updates service to be offered by protocol plugins
+ */
+public interface IPluginOutReadService {
+
+ /**
+ * Notifies the hardware view of all the flow installed on the specified network node
+ * @param node
+ * @return
+ */
+ public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList);
+
+ /**
+ * Notifies the hardware view of the specified network node connector
+ * @param node
+ * @return
+ */
+ public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList);
+
+ /**
+ * Notifies all the table statistics for a node
+ * @param node
+ * @return
+ */
+ public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList);
+ /**
+ * Notifies the hardware view of node description changes
+ * @param node
+ * @return
+ */
+ public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription );
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.reader;
+
+
+/**
+ * @file IReadServiceListener.java
+ *
+ * @brief SAL service to be consumed by functional modules that are interested in reader updates
+ */
+public interface IReadServiceListener extends IPluginOutReadService {
+
+}
-
/*
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
package org.opendaylight.controller.sal.reader;
+import java.io.Serializable;
+
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
/**
* Represents the statistics for the node conenctor
- *
- *
- *
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
-public class NodeConnectorStatistics {
- @XmlElement
+public class NodeConnectorStatistics implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement
private NodeConnector nodeConnector;
- @XmlElement
+ @XmlElement
private long receivePackets;
- @XmlElement
+ @XmlElement
private long transmitPackets;
- @XmlElement
+ @XmlElement
private long receiveBytes;
- @XmlElement
+ @XmlElement
private long transmitBytes;
- @XmlElement
+ @XmlElement
private long receiveDrops;
- @XmlElement
+ @XmlElement
private long transmitDrops;
- @XmlElement
+ @XmlElement
private long receiveErrors;
- @XmlElement
+ @XmlElement
private long transmitErrors;
- @XmlElement
+ @XmlElement
private long receiveFrameError;
- @XmlElement
+ @XmlElement
private long receiveOverRunError;
- @XmlElement
+ @XmlElement
private long receiveCrcError;
- @XmlElement
+ @XmlElement
private long collisionCount;
- //To Satisfy JAXB
- public NodeConnectorStatistics() {
+ // To Satisfy JAXB
+ public NodeConnectorStatistics() {
+
+ }
- }
/**
* Set the node connector
+ *
* @param port
*/
public void setNodeConnector(NodeConnector port) {
/**
* Returns the node connector
+ *
* @return
*/
public NodeConnector getNodeConnector() {
/**
* Set the rx packet count's value
+ *
* @param count
*/
public void setReceivePacketCount(long count) {
/**
* Returns the rx packet count for the port
+ *
* @return
*/
public long getReceivePacketCount() {
/**
* Set the tx packet count's value
+ *
* @param count
*/
public void setTransmitPacketCount(long count) {
/**
* Returns the tx packet count for the port
+ *
* @return
*/
public long getTransmitPacketCount() {
/**
* Set the rx byte count's value
+ *
* @param count
*/
public void setReceiveByteCount(long count) {
/**
* Return the rx byte count for the port
+ *
* @return
*/
public long getReceiveByteCount() {
/**
* Set the tx byte count's value
+ *
* @param count
*/
public void setTransmitByteCount(long count) {
/**
* Return the tx byte count for the port
+ *
* @return
*/
public long getTransmitByteCount() {
/**
* Set the rx drop count's value
+ *
* @param count
*/
public void setReceiveDropCount(long count) {
/**
* Returns the rx drop count for the port
+ *
* @return
*/
public long getReceiveDropCount() {
/**
* Set the tx drop count's value
+ *
* @param count
*/
public void setTransmitDropCount(long count) {
/**
* Returns the tx drop count for the port
+ *
* @return
*/
public long getTransmitDropCount() {
/**
* Set the rx error count's value
+ *
* @param count
*/
public void setReceiveErrorCount(long count) {
/**
* Return the rx error count for the port
+ *
* @return
*/
public long getReceiveErrorCount() {
/**
* Set the tx error count's value
+ *
* @param count
*/
public void setTransmitErrorCount(long count) {
/**
* Return the tx error count for the port
+ *
* @return
*/
public long getTransmitErrorCount() {
/**
* Set the rx frame error value
+ *
* @param count
*/
public void setReceiveFrameErrorCount(long count) {
/**
* Returns the rx frame error for the port
+ *
* @return
*/
public long getReceiveFrameErrorCount() {
/**
* Set the rx overrun error value
+ *
* @param count
*/
public void setReceiveOverRunErrorCount(long count) {
/**
* Return the rx overrun error for the port
+ *
* @return
*/
public long getReceiveOverRunErrorCount() {
/**
* Set the rx CRC Error value
+ *
* @param count
*/
public void setReceiveCRCErrorCount(long count) {
/**
* Return the rx CRC error for the port
+ *
* @return
*/
public long getReceiveCRCErrorCount() {
/**
* Set the collisionCount count's value
+ *
* @param count
*/
public void setCollisionCount(long count) {
/**
* Return the collisionCount count for the port
+ *
* @return
*/
public long getCollisionCount() {
@Override
public String toString() {
return "NodeConnectorStats[portNumber = " + nodeConnector
- + ", receivePackets = " + receivePackets
- + ", transmitPackets = " + transmitPackets
- + ", receiveBytes = " + receiveBytes + ", transmitBytes = "
- + transmitBytes + ", receiveDrops = " + receiveDrops
- + ", transmitDrops = " + transmitDrops + ", receiveErrors = "
- + receiveErrors + ", transmitErrors = " + transmitErrors
- + ", receiveFrameError = " + receiveFrameError
- + ", receiveOverRunError = " + receiveOverRunError
- + ", receiveCrcError = " + receiveCrcError
- + ", collisionCount = " + collisionCount + "]";
+ + ", receivePackets = " + receivePackets
+ + ", transmitPackets = " + transmitPackets
+ + ", receiveBytes = " + receiveBytes + ", transmitBytes = "
+ + transmitBytes + ", receiveDrops = " + receiveDrops
+ + ", transmitDrops = " + transmitDrops + ", receiveErrors = "
+ + receiveErrors + ", transmitErrors = " + transmitErrors
+ + ", receiveFrameError = " + receiveFrameError
+ + ", receiveOverRunError = " + receiveOverRunError
+ + ", receiveCrcError = " + receiveCrcError
+ + ", collisionCount = " + collisionCount + "]";
}
}
package org.opendaylight.controller.sal.reader;
+import java.io.Serializable;
+
/**
* Represents the network node description information
*/
-public class NodeDescription {
+public class NodeDescription implements Serializable, Cloneable{
+ private static final long serialVersionUID = 1L;
+
private String manufacturer;
private String hardware;
private String software;
+ hardware + ", software=" + software + ", serialNumber="
+ serialNumber + ", description=" + description + "]";
}
+ @Override
+ public NodeDescription clone() {
+ NodeDescription nd = new NodeDescription();
+ nd.setDescription(description);
+ nd.setHardware(hardware);
+ nd.setManufacturer(manufacturer);
+ nd.setSerialNumber(serialNumber);
+ nd.setSoftware(software);
+
+ return nd;
+ }
}
*/
package org.opendaylight.controller.sal.reader;
+import java.io.Serializable;
+
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
-public class NodeTableStatistics {
+public class NodeTableStatistics implements Serializable {
+ private static final long serialVersionUID = 1L;
+
@XmlElement
private NodeTable nodeTable;
@XmlElement
*
*/
public abstract class NodeCreator {
- protected static final Logger logger = LoggerFactory
- .getLogger(NodeCreator.class);
+ protected static final Logger logger = LoggerFactory.getLogger(NodeCreator.class);
+
public static Node createOFNode(Long switchId) {
try {
return new Node(NodeIDType.OPENFLOW, switchId);
import org.opendaylight.controller.sal.packet.IPluginInDataPacketService;
import org.opendaylight.controller.sal.packet.IPluginOutDataPacketService;
import org.opendaylight.controller.sal.reader.IPluginInReadService;
+import org.opendaylight.controller.sal.reader.IPluginOutReadService;
import org.opendaylight.controller.sal.reader.IReadService;
+import org.opendaylight.controller.sal.reader.IReadServiceListener;
import org.opendaylight.controller.sal.topology.IListenTopoUpdates;
import org.opendaylight.controller.sal.topology.IPluginInTopologyService;
import org.opendaylight.controller.sal.topology.IPluginOutTopologyService;
}
if (imp.equals(ReadService.class)) {
- // It is the provider of IReadService
- c.setInterface(IReadService.class.getName(), null);
+ // export services
+ c.setInterface(new String[] {
+ IReadService.class.getName(),IPluginOutReadService.class.getName()}, null);
// It is also the consumer of IPluginInReadService
c.add(createContainerServiceDependency(containerName)
.setService(IPluginInReadService.class)
.setCallbacks("setService", "unsetService")
- .setRequired(true));
+ .setRequired(false));
+
+ //consumes plugins' reader updates
+ c.add(createContainerServiceDependency(containerName)
+ .setService(IReadServiceListener.class)
+ .setCallbacks("setReaderListener", "unsetReaderListener")
+ .setRequired(false));
+
}
/************************/
package org.opendaylight.controller.sal.implementation.internal;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
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.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.FlowOnNode;
import org.opendaylight.controller.sal.reader.IPluginInReadService;
+import org.opendaylight.controller.sal.reader.IPluginOutReadService;
import org.opendaylight.controller.sal.reader.IReadService;
+import org.opendaylight.controller.sal.reader.IReadServiceListener;
import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
import org.opendaylight.controller.sal.reader.NodeDescription;
import org.opendaylight.controller.sal.reader.NodeTableStatistics;
import org.slf4j.LoggerFactory;
/**
- * The SAL Read Service. It dispatches the read request to
- * the proper SDN protocol plugin
- *
- *
- *
+ * The SAL Read Service. Dispatches read requests to the proper SDN protocol
+ * plugin, and notifies any listeners on updates from any plugin readers
*/
-public class ReadService implements IReadService, CommandProvider {
+public class ReadService implements IReadService, CommandProvider, IPluginOutReadService {
- protected static final Logger logger = LoggerFactory
- .getLogger(ReadService.class);
- private ConcurrentHashMap<String, IPluginInReadService>
- pluginReader =
- new ConcurrentHashMap<String, IPluginInReadService>();
+ protected static final Logger logger = LoggerFactory.getLogger(ReadService.class);
+ private ConcurrentHashMap<String, IPluginInReadService> pluginReader;
+ private Set<IReadServiceListener> readerListeners;
/**
* Function called by the dependency manager when all the required
*
*/
void init() {
+ pluginReader = new ConcurrentHashMap<String, IPluginInReadService>();
+ readerListeners = new CopyOnWriteArraySet<IReadServiceListener>();
}
/**
}
// Set the reference to the plugin flow Reader service
- public void setService(Map props, IPluginInReadService s) {
+ public void setService(Map<?, ?> props, IPluginInReadService s) {
if (this.pluginReader == null) {
logger.error("pluginReader store null");
return;
logger.trace("Got a service set request {}", s);
String type = null;
for (Object e : props.entrySet()) {
- Map.Entry entry = (Map.Entry) e;
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
logger.trace("Prop key:({}) value:({})", entry.getKey(),
entry.getValue());
}
}
}
- public void unsetService(Map props, IPluginInReadService s) {
+ public void unsetService(Map<?, ?> props, IPluginInReadService s) {
if (this.pluginReader == null) {
logger.error("pluginReader store null");
return;
String type = null;
logger.debug("Received unsetpluginReader request");
for (Object e : props.entrySet()) {
- Map.Entry entry = (Map.Entry) e;
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
logger.trace("Prop key:({}) value:({})", entry.getKey(),
entry.getValue());
}
logger.debug("Removed the pluginReader for type: {}", type);
}
}
+ public void setReaderListener(IReadServiceListener service) {
+ logger.trace("Got a listener set request {}", service);
+ this.readerListeners.add(service);
+ }
+
+ public void unsetReaderListener(IReadServiceListener service) {
+ logger.trace("Got a listener Unset request");
+ this.readerListeners.remove(service);
+ }
@Override
public FlowOnNode readFlow(Node node, Flow flow) {
.readFlow(node, flow, true);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readFlow(node, flow, false);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readAllFlow(node, true);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readAllFlow(node, false);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readDescription(node, true);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readDescription(node, false);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readNodeConnector(connector, true);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readNodeConnector(connector, false);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readAllNodeConnector(node, true);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readAllNodeTable(node, true);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readNodeTable(table, false);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readNodeTable(table, true);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.readAllNodeConnector(node, false);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return null;
}
.getTransmitRate(connector);
}
}
- logger.warn("Plugin unavailable");
+ logger.warn("Plugin {} unavailable", node.getType());
return 0;
}
+ @Override
+ public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
+ for (IReadServiceListener l : readerListeners){
+ l.nodeFlowStatisticsUpdated(node, flowStatsList);
+ }
+ }
+
+ @Override
+ public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
+ for (IReadServiceListener l : readerListeners){
+ l.nodeConnectorStatisticsUpdated(node, ncStatsList);
+ }
+ }
+
+ @Override
+ public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
+ for (IReadServiceListener l : readerListeners){
+ l.nodeTableStatisticsUpdated(node, tableStatsList);
+ }
+ }
+
+ @Override
+ public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
+ for (IReadServiceListener l : readerListeners){
+ l.descriptionStatisticsUpdated(node, nodeDescription);
+ }
+ }
+
// ---------------- OSGI TEST CODE ------------------------------//
private void registerWithOSGIConsole() {
actions.add(new Controller());
return new Flow(match, actions);
}
-
}
package org.opendaylight.controller.sal.implementation.internal;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import java.util.Collections;
import org.opendaylight.controller.sal.core.Edge;
-import org.opendaylight.controller.sal.core.Property;
-import org.opendaylight.controller.sal.core.UpdateType;
import org.opendaylight.controller.sal.topology.IListenTopoUpdates;
import org.opendaylight.controller.sal.topology.IPluginInTopologyService;
import org.opendaylight.controller.sal.topology.IPluginOutTopologyService;
*/
public interface IStatisticsManager {
/**
- * Return all the statistics for all the flows present on the specified node in the current container context.
- * If the context is the default container, the returned statistics are for all the flows installed on the node,
- * regardless of the container they belong to
+ * Return all the statistics for all the flows present on the specified node
+ * in the current container context. If the context is the default
+ * container, the returned statistics are for all the flows installed on the
+ * node, regardless of the container they belong to
*
- * @param node the network node
- * @return the list of flows installed on the network node
+ * @param node
+ * The network node
+ * @return List of flows installed on the network node. Null if specified
+ * node is null. Empty list if node/stat is not present.
*/
List<FlowOnNode> getFlows(Node node);
* Returns the statistics for the flows specified in the list
*
* @param flows
- * @return the list of flows installed on the network node
+ * @return A map of flows per node installed on that node, empty map if
+ * flows is null/empty.
*/
- Map<Node, List<FlowOnNode>> getFlowStatisticsForFlowList(
- List<FlowEntry> flows);
+ Map<Node, List<FlowOnNode>> getFlowStatisticsForFlowList(List<FlowEntry> flows);
/**
- * Returns the number of flows installed on the switch in the current container context
- * If the context is the default container, the returned value is the number of all the
- * flows installed on the switch regardless of the container they belong to
+ * Returns the number of flows installed on the switch in the current
+ * container context If the context is the default container, the returned
+ * value is the number of all the flows installed on the switch regardless
+ * of the container they belong to
*
- * @param switchId
- * @return
+ * @param node
+ * @return number of flows on specified node or (-1) if node was not found
*/
int getFlowsNumber(Node node);
/**
- * Returns the node description for the specified node retrieved and cached by the
- * protocol plugin component which collects the node statistics
+ * Returns the node description for the specified node retrieved by the
+ * protocol plugin component and cached by statistics manager.
+ * Null if node not found.
*
* @param node
- * @return
+ * @return node description
*/
NodeDescription getNodeDescription(Node node);
/**
- * Returns the statistics for the specified node connector as it was retrieved
- * and cached by the protocol plugin component which collects the node connector statistics
+ * Returns the statistics for the specified node connector as it was
+ * retrieved by the protocol plugin component and cached by statistics
+ * manager.
*
* @param node
- * @return
+ * @return Node connector statistics or null if requested stats was not
+ * found.
*/
- NodeConnectorStatistics getNodeConnectorStatistics(
- NodeConnector nodeConnector);
+ NodeConnectorStatistics getNodeConnectorStatistics(NodeConnector nodeConnector);
/**
- * Returns the statistics for all the node connector present on the specified network node
+ * Returns the statistics for all the node connector present on the
+ * specified network node
*
* @param node
- * @return
+ * @return List of node connector statistics. Null if node is null. Empty
+ * list if node/stats is not present.
*/
List<NodeConnectorStatistics> getNodeConnectorStatistics(Node node);
* Returns the statistics for the specified table of the node
*
* @param nodeTable
- * @return
+ * @return Table statistics. Null if node table is null or stats not found.
*/
NodeTableStatistics getNodeTableStatistics(NodeTable nodeTable);
* Returns the statistics for all the tables of the node
*
* @param nodeTable
- * @return
+ * @return List of table stats. Null if node is null. Empty list if
+ * node/stats not found.
*/
List <NodeTableStatistics> getNodeTableStatistics(Node node);
}
<configuration>
<instructions>
<Import-Package>
+ org.opendaylight.controller.clustering.services,
org.opendaylight.controller.containermanager,
org.opendaylight.controller.sal.core,
- org.opendaylight.controller.sal.flowprogrammer, org.slf4j,
+ org.opendaylight.controller.sal.flowprogrammer,
org.opendaylight.controller.sal.reader,
+ org.opendaylight.controller.sal.utils,
+ org.slf4j,
+ org.opendaylight.controller.sal.inventory,
+ org.opendaylight.controller.sal.match,
+ org.opendaylight.controller.switchmanager,
org.opendaylight.controller.statisticsmanager,
org.opendaylight.controller.forwardingrulesmanager,
org.apache.felix.dm
package org.opendaylight.controller.statisticsmanager.internal;
import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.core.IContainer;
+import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
import org.opendaylight.controller.sal.reader.IReadService;
+import org.opendaylight.controller.sal.reader.IReadServiceListener;
import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Activator extends ComponentActivatorAbstractBase {
- protected static final Logger logger = LoggerFactory
- .getLogger(Activator.class);
+ protected static final Logger logger = LoggerFactory.getLogger(Activator.class);
/**
- * Function called when the activator starts just after some
- * initializations are done by the
- * ComponentActivatorAbstractBase.
+ * Function called when the activator starts just after some initializations
+ * are done by the ComponentActivatorAbstractBase.
*
*/
public void init() {
}
/**
- * Function called when the activator stops just before the
- * cleanup done by ComponentActivatorAbstractBase
+ * Function called when the activator stops just before the cleanup done by
+ * ComponentActivatorAbstractBase
*
*/
public void destroy() {
}
/**
- * Function that is used to communicate to dependency manager the
- * list of known implementations for services inside a container
+ * Function that is used to communicate to dependency manager the list of
+ * known implementations for services inside a container
*
*
* @return An array containing all the CLASS objects that will be
- * instantiated in order to get an fully working implementation
- * Object
+ * instantiated in order to get an fully working implementation
+ * Object
*/
public Object[] getImplementations() {
Object[] res = { StatisticsManager.class };
}
/**
- * Function that is called when configuration of the dependencies
- * is required.
+ * Function that is called when configuration of the dependencies is
+ * required.
*
- * @param c dependency manager Component object, used for
- * configuring the dependencies exported and imported
- * @param imp Implementation class that is being configured,
- * needed as long as the same routine can configure multiple
- * implementations
- * @param containerName The containerName being configured, this allow
- * also optional per-container different behavior if needed, usually
- * should not be the case though.
+ * @param c
+ * dependency manager Component object, used for configuring the
+ * dependencies exported and imported
+ * @param imp
+ * Implementation class that is being configured, needed as long
+ * as the same routine can configure multiple implementations
+ * @param containerName
+ * The containerName being configured, this allow also optional
+ * per-container different behavior if needed, usually should not
+ * be the case though.
*/
public void configureInstance(Component c, Object imp, String containerName) {
if (imp.equals(StatisticsManager.class)) {
// export the service
- c.setInterface(new String[] { IStatisticsManager.class.getName() },
- null);
+ c.setInterface(new String[] {
+ IStatisticsManager.class.getName(),
+ IReadServiceListener.class.getName(),
+ IListenInventoryUpdates.class.getName() }, null);
+
+ c.add(createContainerServiceDependency(containerName).setService(IReadService.class)
+ .setCallbacks("setReaderService", "unsetReaderService").setRequired(true));
+ c.add(createContainerServiceDependency(containerName).setService(IClusterContainerServices.class)
+ .setCallbacks("setClusterContainerService", "unsetClusterContainerService").setRequired(true));
+ c.add(createContainerServiceDependency(containerName).setService(IContainer.class)
+ .setCallbacks("setIContainer", "unsetIContainer").setRequired(true));
- c.add(createContainerServiceDependency(containerName).setService(
- IReadService.class).setCallbacks("setReaderService",
- "unsetReaderService").setRequired(false));
}
}
}
package org.opendaylight.controller.statisticsmanager.internal;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
+import org.opendaylight.controller.sal.core.IContainer;
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.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
import org.opendaylight.controller.sal.reader.FlowOnNode;
import org.opendaylight.controller.sal.reader.IReadService;
+import org.opendaylight.controller.sal.reader.IReadServiceListener;
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.ServiceHelper;
import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
+import org.opendaylight.controller.switchmanager.ISwitchManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * The class which implements the methods for retrieving
- * the network nodes statistics.
+ * The class caches latest network nodes statistics as notified by reader
+ * services and provides API to retrieve them.
*/
-public class StatisticsManager implements IStatisticsManager {
- private static final Logger log = LoggerFactory
- .getLogger(StatisticsManager.class);
+public class StatisticsManager implements IStatisticsManager, IReadServiceListener, IListenInventoryUpdates {
+ private static final Logger log = LoggerFactory.getLogger(StatisticsManager.class);
+ private IContainer container;
+ private IClusterContainerServices clusterContainerService;
private IReadService reader;
+ //statistics caches
+ private ConcurrentMap<Node, List<FlowOnNode>> flowStatistics;
+ private ConcurrentMap<Node, List<NodeConnectorStatistics>> nodeConnectorStatistics;
+ private ConcurrentMap<Node, List<NodeTableStatistics>> tableStatistics;
+ private ConcurrentMap<Node, NodeDescription> descriptionStatistics;
- public StatisticsManager() {
+ private void nonClusterObjectCreate() {
+ flowStatistics = new ConcurrentHashMap<Node, List<FlowOnNode>>();
+ nodeConnectorStatistics = new ConcurrentHashMap<Node, List<NodeConnectorStatistics>>();
+ tableStatistics = new ConcurrentHashMap<Node, List<NodeTableStatistics>>();
+ descriptionStatistics = new ConcurrentHashMap<Node, NodeDescription>();
+ }
+
+ @SuppressWarnings("deprecation")
+ private void allocateCaches() {
+ if (clusterContainerService == null) {
+ nonClusterObjectCreate();
+ log.error("Clustering service unavailable. Allocated non-cluster statistics manager cache.");
+ return;
+ }
+ try {
+ clusterContainerService.createCache("statisticsmanager.flowStatistics",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+ clusterContainerService.createCache("statisticsmanager.nodeConnectorStatistics",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+ clusterContainerService.createCache("statisticsmanager.tableStatistics",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+ clusterContainerService.createCache("statisticsmanager.descriptionStatistics",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+
+ } catch (CacheConfigException cce) {
+ log.error("Statistics cache configuration invalid - check cache mode");
+ } catch (CacheExistException ce) {
+ log.debug("Skipping statistics cache creation - already present");
+ }
+ }
+ @SuppressWarnings({ "unchecked", "deprecation" })
+ private void retrieveCaches() {
+ ConcurrentMap<?, ?> map;
+
+ if (this.clusterContainerService == null) {
+ log.warn("Can't retrieve statistics manager cache, Clustering service unavailable.");
+ return;
+ }
+
+ log.debug("Statistics Manager - retrieveCaches for Container {}", container);
+
+ map = clusterContainerService.getCache("statisticsmanager.flowStatistics");
+ if (map != null) {
+ this.flowStatistics = (ConcurrentMap<Node, List<FlowOnNode>>) map;
+ } else {
+ log.error("Cache allocation failed for statisticsmanager.flowStatistics in container {}", container.getName());
+ }
+
+ map = clusterContainerService.getCache("statisticsmanager.nodeConnectorStatistics");
+ if (map != null) {
+ this.nodeConnectorStatistics = (ConcurrentMap<Node, List<NodeConnectorStatistics>>) map;
+ } else {
+ log.error("Cache allocation failed for statisticsmanager.nodeConnectorStatistics in container {}", container.getName());
+ }
+
+ map = clusterContainerService.getCache("statisticsmanager.tableStatistics");
+ if (map != null) {
+ this.tableStatistics = (ConcurrentMap<Node, List<NodeTableStatistics>>) map;
+ } else {
+ log.error("Cache allocation failed for statisticsmanager.tableStatistics in container {}", container.getName());
+ }
+
+ map = clusterContainerService.getCache("statisticsmanager.descriptionStatistics");
+ if (map != null) {
+ this.descriptionStatistics = (ConcurrentMap<Node, NodeDescription>) map;
+ } else {
+ log.error("Cache allocation failed for statisticsmanager.descriptionStatistics in container {}", container.getName());
+ }
}
/**
*/
void init() {
log.debug("INIT called!");
+ allocateCaches();
+ retrieveCaches();
+
}
/**
log.debug("START called!");
}
+ /**
+ * Function called after registering the service in OSGi service registry.
+ */
+ void started(){
+ //retrieve current statistics so we don't have to wait for next refresh
+ ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(
+ ISwitchManager.class, container.getName(), this);
+ if (reader != null && switchManager != null) {
+ Set<Node> nodeSet = switchManager.getNodes();
+ for (Node node : nodeSet) {
+ flowStatistics.put(node, reader.readAllFlows(node));
+ descriptionStatistics.put(node, reader.readDescription(node));
+ tableStatistics.put(node, reader.readNodeTable(node));
+ nodeConnectorStatistics.put(node, reader.readNodeConnectors(node));
+ }
+
+ } else {
+ log.warn("Failed to retrieve current statistics. Statistics will not be immidiately available!");
+ }
+ }
+
/**
* Function called by the dependency manager before the services
* exported by the component are unregistered, this will be
log.debug("STOP called!");
}
+ void setClusterContainerService(IClusterContainerServices s) {
+ log.debug("Cluster Service set for Statistics Mgr");
+ this.clusterContainerService = s;
+ }
+
+ void unsetClusterContainerService(IClusterContainerServices s) {
+ if (this.clusterContainerService == s) {
+ log.debug("Cluster Service removed for Statistics Mgr!");
+ this.clusterContainerService = null;
+ }
+ }
+ void setIContainer(IContainer c){
+ container = c;
+ }
+ public void unsetIContainer(IContainer s) {
+ if (this.container == s) {
+ this.container = null;
+ }
+ }
+
public void setReaderService(IReadService service) {
log.debug("Got inventory service set request {}", service);
this.reader = service;
}
public void unsetReaderService(IReadService service) {
- log.debug("Got a service UNset request");
+ log.debug("Got a service UNset request {}", service);
this.reader = null;
}
@Override
public List<FlowOnNode> getFlows(Node node) {
- return reader.readAllFlows(node);
+ if (node == null) {
+ return null;
+ }
+
+ List<FlowOnNode> flowList = new ArrayList<FlowOnNode>();
+ List<FlowOnNode> cachedList = flowStatistics.get(node);
+ if (cachedList != null){
+ flowList.addAll(cachedList);
+ }
+ return flowList;
}
@Override
- public Map<Node, List<FlowOnNode>> getFlowStatisticsForFlowList(
- List<FlowEntry> flowList) {
- Map<Node, List<FlowOnNode>> map = new HashMap<Node, List<FlowOnNode>>();
- if (flowList != null) {
- for (FlowEntry entry : flowList) {
- Node node = entry.getNode();
- Flow flow = entry.getFlow();
- List<FlowOnNode> list = (map.containsKey(node)) ? map.get(node)
- : new ArrayList<FlowOnNode>();
- list.add(reader.readFlow(node, flow));
- map.put(node, list);
+ public Map<Node, List<FlowOnNode>> getFlowStatisticsForFlowList(List<FlowEntry> flowList) {
+ Map<Node, List<FlowOnNode>> statMapOutput = new HashMap<Node, List<FlowOnNode>>();
+
+ if (flowList == null || flowList.isEmpty()){
+ return statMapOutput;
+ }
+
+ Node node;
+ //index FlowEntries' flows by node so we don't traverse entire flow list for each flowEntry
+ Map<Node, Set<Flow>> index = new HashMap<Node, Set<Flow>>();
+ for (FlowEntry flowEntry : flowList) {
+ node = flowEntry.getNode();
+ Set<Flow> set = (index.containsKey(node) ? index.get(node) : new HashSet<Flow>());
+ set.add(flowEntry.getFlow());
+ index.put(node, set);
+ }
+
+ //iterate over flows per indexed node and add to output
+ for (Entry<Node, Set<Flow>> indexEntry : index.entrySet()) {
+ node = indexEntry.getKey();
+ List<FlowOnNode> flowsPerNode = flowStatistics.get(node);
+
+ if (flowsPerNode != null && !flowsPerNode.isEmpty()){
+ List<FlowOnNode> filteredFlows = statMapOutput.containsKey(node) ?
+ statMapOutput.get(node) : new ArrayList<FlowOnNode>();
+
+ for (FlowOnNode flowOnNode : flowsPerNode) {
+ if (indexEntry.getValue().contains(flowOnNode.getFlow())) {
+ filteredFlows.add(flowOnNode);
+ }
+ }
+ statMapOutput.put(node, filteredFlows);
}
}
- return map;
+ return statMapOutput;
}
@Override
public int getFlowsNumber(Node node) {
- return reader.readAllFlows(node).size();
+ List<FlowOnNode> l;
+ if (node == null || (l = flowStatistics.get(node)) == null){
+ return -1;
+ }
+ return l.size();
}
@Override
public NodeDescription getNodeDescription(Node node) {
- return reader.readDescription(node);
+ if (node == null){
+ return null;
+ }
+ NodeDescription nd = descriptionStatistics.get(node);
+ return nd != null? nd.clone() : null;
}
@Override
- public NodeConnectorStatistics getNodeConnectorStatistics(
- NodeConnector nodeConnector) {
- return reader.readNodeConnector(nodeConnector);
+ public NodeConnectorStatistics getNodeConnectorStatistics(NodeConnector nodeConnector) {
+ if (nodeConnector == null){
+ return null;
+ }
+
+ List<NodeConnectorStatistics> statList = nodeConnectorStatistics.get(nodeConnector.getNode());
+ if (statList != null){
+ for (NodeConnectorStatistics stat : statList) {
+ if (stat.getNodeConnector().equals(nodeConnector)){
+ return stat;
+ }
+ }
+ }
+ return null;
}
@Override
public List<NodeConnectorStatistics> getNodeConnectorStatistics(Node node) {
- return reader.readNodeConnectors(node);
+ if (node == null){
+ return null;
+ }
+
+ List<NodeConnectorStatistics> statList = new ArrayList<NodeConnectorStatistics>();
+ List<NodeConnectorStatistics> cachedList = nodeConnectorStatistics.get(node);
+ if (cachedList != null) {
+ statList.addAll(cachedList);
+ }
+ return statList;
}
@Override
public NodeTableStatistics getNodeTableStatistics(NodeTable nodeTable) {
- return reader.readNodeTable(nodeTable);
+ if (nodeTable == null){
+ return null;
+ }
+ List<NodeTableStatistics> statList = tableStatistics.get(nodeTable.getNode());
+ if (statList != null){
+ for (NodeTableStatistics stat : statList) {
+ if (stat.getNodeTable().getID().equals(nodeTable.getID())){
+ return stat;
+ }
+ }
+ }
+ return null;
}
@Override
public List<NodeTableStatistics> getNodeTableStatistics(Node node){
- return reader.readNodeTable(node);
+ if (node == null){
+ return null;
+ }
+ List<NodeTableStatistics> statList = new ArrayList<NodeTableStatistics>();
+ List<NodeTableStatistics> cachedList = tableStatistics.get(node);
+ if (cachedList != null) {
+ statList.addAll(cachedList);
+ }
+ return statList;
+ }
+
+ @Override
+ public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
+ this.flowStatistics.put(node, flowStatsList);
+ }
+
+ @Override
+ public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
+ this.nodeConnectorStatistics.put(node, ncStatsList);
+ }
+
+ @Override
+ public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
+ this.tableStatistics.put(node, tableStatsList);
+ }
+
+ @Override
+ public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
+ this.descriptionStatistics.put(node, nodeDescription);
+ }
+
+ @Override
+ public void updateNode(Node node, UpdateType type, Set<Property> props) {
+ //if node is removed, remove stats mappings
+ if (type == UpdateType.REMOVED) {
+ flowStatistics.remove(node);
+ nodeConnectorStatistics.remove(node);
+ tableStatistics.remove(node);
+ descriptionStatistics.remove(node);
+ }
+ }
+
+ @Override
+ public void updateNodeConnector(NodeConnector nodeConnector, UpdateType type, Set<Property> props) {
+ // not interested in this update
}
}
<artifactId>statisticsmanager.implementation</artifactId>
<version>0.4.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>switchmanager.implementation</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>switchmanager</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>configuration</artifactId>
package org.opendaylight.controller.statisticsmanager.internal;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemPackages;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.Bundle;
import javax.inject.Inject;
import org.junit.Assert;
-import org.junit.Test;
import org.junit.Before;
+import org.junit.Test;
import org.junit.runner.RunWith;
import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
import org.opendaylight.controller.sal.action.Action;
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.utils.NodeCreator;
-import org.opendaylight.controller.statisticsmanager.*;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.BundleContext;
-import static org.junit.Assert.*;
-import org.ops4j.pax.exam.junit.Configuration;
-import static org.ops4j.pax.exam.CoreOptions.*;
-
+import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.util.PathUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@RunWith(PaxExam.class)
public class StatisticsManagerIT {
.versionAsInProject(),
mavenBundle("ch.qos.logback", "logback-classic")
.versionAsInProject(),
- // List all the bundles on which the test case depends
- mavenBundle("org.opendaylight.controller", "sal")
- .versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "sal.implementation")
- .versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "statisticsmanager")
- .versionAsInProject(),
- mavenBundle("org.opendaylight.controller",
- "statisticsmanager.implementation")
- .versionAsInProject(),
- mavenBundle("org.opendaylight.controller",
- "protocol_plugins.stub").versionAsInProject(),
// needed by statisticsmanager
mavenBundle("org.opendaylight.controller", "containermanager")
- .versionAsInProject(),
- mavenBundle("org.opendaylight.controller",
- "containermanager.implementation").versionAsInProject(),
- mavenBundle("org.opendaylight.controller",
- "forwardingrulesmanager").versionAsInProject(),
-
- mavenBundle("org.opendaylight.controller",
- "clustering.services").versionAsInProject(),
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "containermanager.implementation")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "clustering.services")
+ .versionAsInProject(),
mavenBundle("org.opendaylight.controller", "clustering.stub")
- .versionAsInProject(),
-
+ .versionAsInProject(),
// needed by forwardingrulesmanager
- mavenBundle("org.opendaylight.controller", "switchmanager")
- .versionAsInProject(),
mavenBundle("org.opendaylight.controller", "configuration")
- .versionAsInProject(),
-
- mavenBundle("org.opendaylight.controller",
- "configuration.implementation").versionAsInProject(),
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "configuration.implementation")
+ .versionAsInProject(),
mavenBundle("org.opendaylight.controller", "hosttracker")
- .versionAsInProject(),
+ .versionAsInProject(),
+
+ // List all the bundles on which the test case depends
+ mavenBundle("org.opendaylight.controller", "sal")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "sal.implementation")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "protocol_plugins.stub")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "switchmanager")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "switchmanager.implementation")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "statisticsmanager")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "statisticsmanager.implementation")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "forwardingrulesmanager")
+ .versionAsInProject(),
// needed by hosttracker
mavenBundle("org.opendaylight.controller", "topologymanager")
.versionAsInProject(),
-
mavenBundle("org.jboss.spec.javax.transaction",
"jboss-transaction-api_1.1_spec").versionAsInProject(),
mavenBundle("org.apache.commons", "commons-lang3")
List<Action> actions = new ArrayList<Action>();
actions.add(action);
flow.setActions(actions);
+ // as in stub
+ flow.setPriority((short) 3500);
+ flow.setIdleTimeout((short) 1000);
+ flow.setHardTimeout((short) 2000);
+ flow.setId(12345);
try {
Node node = new Node("STUB", 0xCAFE);