X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fprotocol_plugins%2Fopenflow%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fprotocol_plugin%2Fopenflow%2Finternal%2FReadServiceFilter.java;h=d5a80370fbf106c5f03f87ef3f9d477f87131a0d;hb=f776809962df87deeaa533ba995cc6fceba64d0e;hp=bcb01b1392ac8661f2ee6aeb3db5e34c47362a41;hpb=7e760258c7948cbaa326a145291c424c8fe0f13b;p=controller.git diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java index bcb01b1392..d5a80370fb 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java @@ -10,26 +10,24 @@ 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; @@ -46,22 +44,29 @@ 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> containerToNc; - private Map> containerToNt; + private ConcurrentMap> containerToNc; + private ConcurrentMap> containerToNode; + private ConcurrentMap> containerToNt; + private ConcurrentMap> containerFlows; + private ConcurrentMap readFilterInternalListeners = + new ConcurrentHashMap(); public void setController(IController core) { this.controller = core; @@ -73,14 +78,49 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, } } + 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>(); - containerToNt = new HashMap>(); + containerToNc = new ConcurrentHashMap>(); + containerToNt = new ConcurrentHashMap>(); + containerToNode = new ConcurrentHashMap>(); + containerFlows = new ConcurrentHashMap>(); } /** @@ -90,6 +130,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, * */ void destroy() { + readFilterInternalListeners.clear(); } /** @@ -119,8 +160,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, } @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. @@ -131,20 +171,25 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, long sid = (Long) node.getID(); OFMatch ofMatch = new FlowConverter(flow).getOFMatch(); - List ofList = (cached == true) ? statsMgr - .getOFFlowStatistics(sid, ofMatch) : statsMgr.queryStatistics( - sid, OFStatisticsType.FLOW, ofMatch); + List 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(1); + ofList.add(ofStat); + break; + } + } + } - /* - * Convert and filter the statistics per container - */ - List flowOnNodeList = new FlowStatisticsConverter(ofList) - .getFlowOnNodeList(node); - List filteredList = filterFlowListPerContainer(container, - node, flowOnNodeList); + // Convert and filter the statistics per container + List flowOnNodeList = new FlowStatisticsConverter(ofList).getFlowOnNodeList(node); + List filteredList = filterFlowListPerContainer(container, node, flowOnNodeList); - return (filteredList == null || filteredList.isEmpty()) ? null - : filteredList.get(0); + return (filteredList.isEmpty()) ? null : filteredList.get(0); } @Override @@ -156,16 +201,10 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, .getOFFlowStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, null); - /* - * Convert and filter the statistics per container - */ - List flowOnNodeList = new FlowStatisticsConverter(ofList) - .getFlowOnNodeList(node); - List filteredList = filterFlowListPerContainer(container, - node, flowOnNodeList); - - return (filteredList == null) ? null : filteredList; + // Convert and filter the statistics per container + List flowOnNodeList = new FlowStatisticsConverter(ofList).getFlowOnNodeList(node); + return filterFlowListPerContainer(container, node, flowOnNodeList); } @Override @@ -181,7 +220,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, .getOFDescStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.DESC, null); - return new DescStatisticsConverter(ofList).getHwDescription(); + return new DescStatisticsConverter(ofList).getHwDescription(); } /** @@ -192,10 +231,10 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, * @param list * @return */ - public List filterFlowListPerContainer(String container, + private List filterFlowListPerContainer(String container, Node nodeId, List list) { if (list == null) { - return null; + return Collections.emptyList(); } // Create new filtered list of flows @@ -212,17 +251,16 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, } /** - * 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 filterPortListPerContainer(String container, - long switchId, List list) { + private List filterPortListPerContainer(String container, long switchId, List list) { if (list == null) { - return null; + return Collections.emptyList(); } // Create new filtered list of flows @@ -241,10 +279,10 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, } - public List filterTableListPerContainer( + private List filterTableListPerContainer( String container, long switchId, List list) { if (list == null) { - return null; + return Collections.emptyList(); } // Create new filtered list of node tables @@ -252,8 +290,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, for (OFStatistics stat : list) { OFTableStatistics target = (OFTableStatistics) stat; - NodeTable nt = NodeTableCreator.createOFNodeTable( - target.getTableId(), NodeCreator.createOFNode(switchId)); + NodeTable nt = NodeTableCreator.createOFNodeTable(target.getTableId(), NodeCreator.createOFNode(switchId)); if (containerOwnsNodeTable(container, nt)) { newList.add(target); } @@ -276,17 +313,17 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, 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 @@ -300,9 +337,9 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, /** * 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 + * @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 @@ -314,14 +351,23 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, } /** - * Returns whether the container flowspec allows the passed flow + * 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 cFlowSet = this.containerFlows.get(container); + if (cFlowSet == null || cFlowSet.isEmpty()) { + return true; + } + for (ContainerFlow cFlow : cFlowSet) { + if (cFlow.allowsFlow(flow)) { + return true; + } + } + return false; } /** @@ -333,8 +379,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, * @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 } @@ -351,9 +396,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, 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; @@ -363,8 +406,7 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, // 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; } @@ -374,49 +416,84 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, } @Override - public void containerFlowUpdated(String containerName, - ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) { - + public void containerFlowUpdated(String containerName, ContainerFlow previousFlow, + ContainerFlow currentFlow, UpdateType t) { + Set cFlowSet = containerFlows.get(containerName); + switch (t) { + case ADDED: + if (cFlowSet == null) { + cFlowSet = new HashSet(); + 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 target = null; + public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType type) { switch (type) { case ADDED: if (!containerToNc.containsKey(containerName)) { - containerToNc.put(containerName, new HashSet()); + containerToNc.put(containerName, + Collections.newSetFromMap(new ConcurrentHashMap())); } containerToNc.get(containerName).add(p); - break; - case CHANGED: + if (!containerToNode.containsKey(containerName)) { + containerToNode.put(containerName, new HashSet()); + } + containerToNode.get(containerName).add(p.getNode()); break; case REMOVED: - target = containerToNc.get(containerName); - if (target != null) { - target.remove(p); + Set 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 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; } @@ -427,26 +504,22 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics( sid, OFStatisticsType.PORT, portId); - List ncStatistics = new PortStatisticsConverter( - sid, ofList).getNodeConnectorStatsList(); - return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics() - : ncStatistics.get(0); + List ncStatistics = new PortStatisticsConverter(sid, ofList) + .getNodeConnectorStatsList(); + return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics() : ncStatistics.get(0); } @Override - public List readAllNodeConnector( - String containerName, Node node, boolean cached) { + public List readAllNodeConnector(String containerName, Node node, boolean cached) { long sid = (Long) node.getID(); List ofList = (cached == true) ? statsMgr .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, null); - List filteredList = filterPortListPerContainer( - containerName, sid, ofList); + List filteredList = filterPortListPerContainer(containerName, sid, ofList); - return new PortStatisticsConverter(sid, filteredList) - .getNodeConnectorStatsList(); + return new PortStatisticsConverter(sid, filteredList).getNodeConnectorStatsList(); } @Override @@ -470,30 +543,105 @@ public class ReadServiceFilter implements IPluginReadServiceFilter, Node node = table.getNode(); long sid = (Long) node.getID(); Byte tableId = (Byte) table.getID(); - List ofList = (cached == true) ? statsMgr - .getOFTableStatistics(sid, tableId) : statsMgr.queryStatistics( - sid, OFStatisticsType.TABLE, tableId); + List ofList = (cached == true) ? statsMgr.getOFTableStatistics(sid, tableId) : + statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, tableId); - List ntStatistics = new TableStatisticsConverter( - sid, ofList).getNodeTableStatsList(); + List 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 readAllNodeTable(String containerName, - Node node, boolean cached) { + public List readAllNodeTable(String containerName, Node node, boolean cached) { long sid = (Long) node.getID(); - List ofList = (cached == true) ? statsMgr - .getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, - OFStatisticsType.FLOW, null); + List ofList = (cached == true) ? + statsMgr.getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, null); - List filteredList = filterTableListPerContainer( - containerName, sid, ofList); + List filteredList = filterTableListPerContainer(containerName, sid, ofList); - return new TableStatisticsConverter(sid, filteredList) - .getNodeTableStatsList(); + return new TableStatisticsConverter(sid, filteredList).getNodeTableStatsList(); } + @Override + public void descriptionStatisticsRefreshed(Long switchId, List description) { + String container; + IReadFilterInternalListener listener; + Node node = NodeCreator.createOFNode(switchId); + NodeDescription nodeDescription = new DescStatisticsConverter(description).getHwDescription(); + for (Map.Entry 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 flows) { + String container; + IReadFilterInternalListener listener; + Node node = NodeCreator.createOFNode(switchId); + for (Map.Entry l : readFilterInternalListeners.entrySet()) { + container = l.getKey(); + listener = l.getValue(); + + // Convert and filter the statistics per container + List flowOnNodeList = new FlowStatisticsConverter(flows).getFlowOnNodeList(node); + flowOnNodeList = filterFlowListPerContainer(container, node, flowOnNodeList); + + // notify listeners + listener.nodeFlowStatisticsUpdated(node, flowOnNodeList); + } + } + + @Override + public void portStatisticsRefreshed(Long switchId, List ports) { + String container; + IReadFilterInternalListener listener; + Node node = NodeCreator.createOFNode(switchId); + for (Map.Entry l : readFilterInternalListeners.entrySet()) { + container = l.getKey(); + listener = l.getValue(); + + // Convert and filter the statistics per container + List filteredPorts = filterPortListPerContainer(container, switchId, ports); + List ncStatsList = new PortStatisticsConverter(switchId, filteredPorts) + .getNodeConnectorStatsList(); + + // notify listeners + listener.nodeConnectorStatisticsUpdated(node, ncStatsList); + } + } + + @Override + public void tableStatisticsRefreshed(Long switchId, List tables) { + String container; + Node node = NodeCreator.createOFNode(switchId); + for (Map.Entry l : readFilterInternalListeners.entrySet()) { + container = l.getKey(); + + // Convert and filter the statistics per container + List filteredList = filterTableListPerContainer(container, switchId, tables); + List 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); + } }