package org.opendaylight.controller.protocol_plugin.openflow.internal;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import 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.core.ContainerFlow;
+import org.opendaylight.controller.sal.core.IContainerAware;
import org.opendaylight.controller.sal.core.IContainerListener;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeTable;
import org.opendaylight.controller.sal.core.UpdateType;
import org.opendaylight.controller.sal.flowprogrammer.Flow;
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.sal.reader.FlowOnNode;
import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
import org.opendaylight.controller.sal.utils.NodeCreator;
-
+import org.opendaylight.controller.sal.utils.NodeTableCreator;
+import org.openflow.protocol.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, IContainerAware {
private static final Logger logger = LoggerFactory
.getLogger(ReadServiceFilter.class);
private IController controller = null;
private IOFStatisticsManager statsMgr = null;
- private Map<String, Set<NodeConnector>> containerToNc;
+ private ConcurrentMap<String, Set<NodeConnector>> containerToNc;
+ private ConcurrentMap<String, Set<Node>> containerToNode;
+ private ConcurrentMap<String, Set<NodeTable>> containerToNt;
+ private ConcurrentMap<String, Set<ContainerFlow>> containerFlows;
+ private ConcurrentMap<String, IReadFilterInternalListener> readFilterInternalListeners =
+ new ConcurrentHashMap<String, IReadFilterInternalListener>();
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>>();
+ containerToNc = new ConcurrentHashMap<String, Set<NodeConnector>>();
+ containerToNt = new ConcurrentHashMap<String, Set<NodeTable>>();
+ containerToNode = new ConcurrentHashMap<String, Set<Node>>();
+ containerFlows = new ConcurrentHashMap<String, Set<ContainerFlow>>();
}
/**
*
*/
void destroy() {
+ readFilterInternalListeners.clear();
}
/**
}
@Override
- public FlowOnNode readFlow(String container, Node node, Flow flow,
- boolean cached) {
+ public FlowOnNode readFlow(String container, Node node, Flow flow, boolean cached) {
if (controller == null) {
// Avoid to provide cached statistics if controller went down.
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
- */
- List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList)
- .getFlowOnNodeList(node);
- List<FlowOnNode> filteredList = filterFlowListPerContainer(container,
- node, flowOnNodeList);
+ // Convert and filter the statistics per container
+ List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList).getFlowOnNodeList(node);
+ List<FlowOnNode> filteredList = filterFlowListPerContainer(container, node, flowOnNodeList);
- return (filteredList == null || filteredList.isEmpty()) ? null
- : filteredList.get(0);
+ return (filteredList.isEmpty()) ? null : filteredList.get(0);
}
@Override
.getOFFlowStatistics(sid) : statsMgr.queryStatistics(sid,
OFStatisticsType.FLOW, null);
- /*
- * Convert and filter the statistics per container
- */
- List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList)
- .getFlowOnNodeList(node);
- List<FlowOnNode> filteredList = filterFlowListPerContainer(container,
- node, flowOnNodeList);
-
- return (filteredList == null) ? null : filteredList;
+ // Convert and filter the statistics per container
+ List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList).getFlowOnNodeList(node);
+ return filterFlowListPerContainer(container, node, flowOnNodeList);
}
@Override
long sid = (Long) node.getID();
List<OFStatistics> ofList = (cached == true) ? statsMgr
.getOFDescStatistics(sid) : statsMgr.queryStatistics(sid,
- OFStatisticsType.DESC, null);
+ OFStatisticsType.DESC, null);
return new DescStatisticsConverter(ofList).getHwDescription();
}
* @param list
* @return
*/
- public List<FlowOnNode> filterFlowListPerContainer(String container,
+ private List<FlowOnNode> filterFlowListPerContainer(String container,
Node nodeId, List<FlowOnNode> list) {
if (list == null) {
- return null;
+ return Collections.emptyList();
}
// Create new filtered list of flows
}
/**
- * 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 list
* @return
*/
- public List<OFStatistics> filterPortListPerContainer(String container,
- long switchId, List<OFStatistics> list) {
+ private List<OFStatistics> filterPortListPerContainer(String container, long switchId, List<OFStatistics> list) {
if (list == null) {
- return null;
+ return Collections.emptyList();
}
// Create new filtered list of flows
return newList;
}
+
+ private List<OFStatistics> filterTableListPerContainer(
+ String container, long switchId, List<OFStatistics> list) {
+ if (list == null) {
+ return Collections.emptyList();
+ }
+
+ // Create new filtered list of node tables
+ List<OFStatistics> newList = new ArrayList<OFStatistics>();
+
+ for (OFStatistics stat : list) {
+ OFTableStatistics target = (OFTableStatistics) stat;
+ NodeTable nt = NodeTableCreator.createOFNodeTable(target.getTableId(), NodeCreator.createOFNode(switchId));
+ if (containerOwnsNodeTable(container, nt)) {
+ newList.add(target);
+ }
+ }
+
+ return newList;
+ }
+
/**
* Returns whether the specified flow (flow match + actions)
* belongs to the container
if (container.equals(GlobalConstants.DEFAULT.toString())) {
return true;
}
- return (flowPortsBelongToContainer(container, node, flow)
- && flowVlanBelongsToContainer(container, node, flow) && flowSpecAllowsFlow(
- container, flow.getMatch()));
+ return (flowPortsBelongToContainer(container, node, flow) &&
+ flowVlanBelongsToContainer(container, node, flow) &&
+ isFlowAllowedByContainer(container, flow));
}
/**
* Returns whether the passed NodeConnector belongs to the container
*
- * @param container container name
- * @param p node connector to test
- * @return true if belongs false otherwise
+ * @param container container name
+ * @param p node connector to test
+ * @return true if belongs false otherwise
*/
public boolean containerOwnsNodeConnector(String container, NodeConnector p) {
// All node connectors belong to the default container
}
/**
- * Returns whether the container flowspec allows the passed flow
+ * Returns whether the passed NodeConnector belongs to the container
+ *
+ * @param container container name
+ * @param table node table to test
+ * @return true if belongs false otherwise
+ */
+ public boolean containerOwnsNodeTable(String container, NodeTable table) {
+ // All node table belong to the default container
+ if (container.equals(GlobalConstants.DEFAULT.toString())) {
+ return true;
+ }
+ Set<NodeTable> tableSet = containerToNt.get(container);
+ return (tableSet == null) ? false : tableSet.contains(table);
+ }
+
+ /**
+ * Returns whether the container flows allow the passed flow
*
* @param container
* @param match
* @return
*/
- private boolean flowSpecAllowsFlow(String container, Match match) {
- return true; // Always true for now
+ private boolean isFlowAllowedByContainer(String container, Flow flow) {
+ Set<ContainerFlow> cFlowSet = this.containerFlows.get(container);
+ if (cFlowSet == null || cFlowSet.isEmpty()) {
+ return true;
+ }
+ for (ContainerFlow cFlow : cFlowSet) {
+ if (cFlow.allowsFlow(flow)) {
+ return true;
+ }
+ }
+ return false;
}
/**
* @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
}
Flow flow) {
Match m = flow.getMatch();
if (m.isPresent(MatchType.IN_PORT)) {
- NodeConnector inPort = (NodeConnector) m
- .getField(MatchType.IN_PORT).getValue();
-
+ NodeConnector inPort = (NodeConnector) m.getField(MatchType.IN_PORT).getValue();
// If the incoming port is specified, check if it belongs to
if (!containerOwnsNodeConnector(container, inPort)) {
return false;
// 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)
- .getPort();
+ 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) {
+ Set<ContainerFlow> cFlowSet = containerFlows.get(containerName);
+ switch (t) {
+ case ADDED:
+ if (cFlowSet == null) {
+ cFlowSet = new HashSet<ContainerFlow>();
+ containerFlows.put(containerName, cFlowSet);
+ }
+ cFlowSet.add(currentFlow);
+ case CHANGED:
+ break;
+ case REMOVED:
+ if (cFlowSet != null) {
+ cFlowSet.remove(currentFlow);
+ }
+ break;
+ default:
+ break;
+ }
}
@Override
- public void nodeConnectorUpdated(String containerName, NodeConnector p,
- UpdateType type) {
- Set<NodeConnector> target = null;
+ public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType type) {
switch (type) {
case ADDED:
if (!containerToNc.containsKey(containerName)) {
- containerToNc.put(containerName, new HashSet<NodeConnector>());
+ containerToNc.put(containerName,
+ Collections.newSetFromMap(new ConcurrentHashMap<NodeConnector,Boolean>()));
}
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;
}
short portId = (Short) connector.getID();
List<OFStatistics> ofList = (cached == true) ? statsMgr
.getOFPortStatistics(sid, portId) : statsMgr.queryStatistics(
- sid, OFStatisticsType.PORT, portId);
+ sid, OFStatisticsType.PORT, portId);
- List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(
- sid, ofList).getNodeConnectorStatsList();
- return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics()
- : ncStatistics.get(0);
+ List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(sid, ofList)
+ .getNodeConnectorStatsList();
+ return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics() : ncStatistics.get(0);
}
@Override
- public List<NodeConnectorStatistics> readAllNodeConnector(
- String containerName, Node node, boolean cached) {
+ public List<NodeConnectorStatistics> readAllNodeConnector(String containerName, Node node, boolean cached) {
long sid = (Long) node.getID();
List<OFStatistics> ofList = (cached == true) ? statsMgr
.getOFPortStatistics(sid) : statsMgr.queryStatistics(sid,
- OFStatisticsType.FLOW, null);
+ OFStatisticsType.PORT, null);
- List<OFStatistics> filteredList = filterPortListPerContainer(
- containerName, sid, ofList);
+ List<OFStatistics> filteredList = filterPortListPerContainer(containerName, sid, ofList);
- return new PortStatisticsConverter(sid, filteredList)
- .getNodeConnectorStatsList();
+ return new PortStatisticsConverter(sid, filteredList).getNodeConnectorStatsList();
}
@Override
return statsMgr.getTransmitRate(switchId, port);
}
+ @Override
+ public NodeTableStatistics readNodeTable(String containerName,
+ NodeTable table, boolean cached) {
+ if (!containerOwnsNodeTable(containerName, table)) {
+ return null;
+ }
+ Node node = table.getNode();
+ long sid = (Long) node.getID();
+ Byte tableId = (Byte) table.getID();
+ List<OFStatistics> ofList = (cached == true) ? statsMgr.getOFTableStatistics(sid, tableId) :
+ statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, tableId);
+
+ List<NodeTableStatistics> ntStatistics = new TableStatisticsConverter(sid, ofList).getNodeTableStatsList();
+
+ return (ntStatistics.isEmpty()) ? new NodeTableStatistics() : ntStatistics.get(0);
+ }
+
+ @Override
+ public List<NodeTableStatistics> readAllNodeTable(String containerName, Node node, boolean cached) {
+ long sid = (Long) node.getID();
+ List<OFStatistics> ofList = (cached == true) ?
+ statsMgr.getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, null);
+
+ List<OFStatistics> filteredList = filterTableListPerContainer(containerName, sid, ofList);
+
+ return new TableStatisticsConverter(sid, filteredList).getNodeTableStatsList();
+ }
+
+ @Override
+ public void descriptionStatisticsRefreshed(Long switchId, List<OFStatistics> description) {
+ String container;
+ IReadFilterInternalListener listener;
+ Node node = NodeCreator.createOFNode(switchId);
+ NodeDescription nodeDescription = new DescStatisticsConverter(description).getHwDescription();
+ for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
+ container = l.getKey();
+ listener = l.getValue();
+ if (container == GlobalConstants.DEFAULT.toString()
+ || (containerToNode.containsKey(container) && containerToNode.get(container).contains(node))) {
+ listener.nodeDescriptionStatisticsUpdated(node, nodeDescription);
+ }
+ }
+ }
+
+ @Override
+ public void flowStatisticsRefreshed(Long switchId, List<OFStatistics> flows) {
+ String container;
+ IReadFilterInternalListener listener;
+ Node node = NodeCreator.createOFNode(switchId);
+ for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
+ container = l.getKey();
+ listener = l.getValue();
+
+ // Convert and filter the statistics per container
+ List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(flows).getFlowOnNodeList(node);
+ flowOnNodeList = filterFlowListPerContainer(container, node, flowOnNodeList);
+
+ // notify listeners
+ listener.nodeFlowStatisticsUpdated(node, flowOnNodeList);
+ }
+ }
+
+ @Override
+ public void portStatisticsRefreshed(Long switchId, List<OFStatistics> ports) {
+ String container;
+ IReadFilterInternalListener listener;
+ Node node = NodeCreator.createOFNode(switchId);
+ for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
+ container = l.getKey();
+ listener = l.getValue();
+
+ // Convert and filter the statistics per container
+ List<OFStatistics> filteredPorts = filterPortListPerContainer(container, switchId, ports);
+ List<NodeConnectorStatistics> ncStatsList = new PortStatisticsConverter(switchId, filteredPorts)
+ .getNodeConnectorStatsList();
+
+ // notify listeners
+ listener.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
+ l.getValue().nodeTableStatisticsUpdated(node, tableStatsList);
+ }
+ }
+
+ @Override
+ public void containerCreate(String containerName) {
+ // do nothing
+ }
+
+ @Override
+ public void containerDestroy(String containerName) {
+ containerToNc.remove(containerName);
+ containerToNode.remove(containerName);
+ containerToNt.remove(containerName);
+ containerFlows.remove(containerName);
+ }
}