3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
10 package org.opendaylight.controller.protocol_plugin.openflow.internal;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
19 import java.util.concurrent.ConcurrentHashMap;
20 import java.util.concurrent.ConcurrentMap;
22 import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsListener;
23 import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
24 import org.opendaylight.controller.protocol_plugin.openflow.IReadFilterInternalListener;
25 import org.opendaylight.controller.protocol_plugin.openflow.IReadServiceFilter;
26 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
27 import org.opendaylight.controller.sal.action.Action;
28 import org.opendaylight.controller.sal.action.ActionType;
29 import org.opendaylight.controller.sal.action.Output;
30 import org.opendaylight.controller.sal.core.ContainerFlow;
31 import org.opendaylight.controller.sal.core.IContainerListener;
32 import org.opendaylight.controller.sal.core.Node;
33 import org.opendaylight.controller.sal.core.NodeConnector;
34 import org.opendaylight.controller.sal.core.NodeTable;
35 import org.opendaylight.controller.sal.core.UpdateType;
36 import org.opendaylight.controller.sal.flowprogrammer.Flow;
37 import org.opendaylight.controller.sal.match.Match;
38 import org.opendaylight.controller.sal.match.MatchType;
39 import org.opendaylight.controller.sal.reader.FlowOnNode;
40 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
41 import org.opendaylight.controller.sal.reader.NodeDescription;
42 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
43 import org.opendaylight.controller.sal.utils.GlobalConstants;
44 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
45 import org.opendaylight.controller.sal.utils.NodeCreator;
46 import org.opendaylight.controller.sal.utils.NodeTableCreator;
47 import org.openflow.protocol.OFMatch;
48 import org.openflow.protocol.statistics.OFFlowStatisticsReply;
49 import org.openflow.protocol.statistics.OFPortStatisticsReply;
50 import org.openflow.protocol.statistics.OFStatistics;
51 import org.openflow.protocol.statistics.OFStatisticsType;
52 import org.openflow.protocol.statistics.OFTableStatistics;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 * Read Service shim layer which is in charge of filtering the flow statistics
57 * based on container. It is a Global instance.
62 public class ReadServiceFilter implements IReadServiceFilter, IContainerListener, IOFStatisticsListener {
63 private static final Logger logger = LoggerFactory
64 .getLogger(ReadServiceFilter.class);
65 private IController controller = null;
66 private IOFStatisticsManager statsMgr = null;
67 private Map<String, Set<NodeConnector>> containerToNc;
68 private Map<String, Set<Node>> containerToNode;
69 private Map<String, Set<NodeTable>> containerToNt;
70 private ConcurrentMap<String, IReadFilterInternalListener> readFilterInternalListeners;
72 public void setController(IController core) {
73 this.controller = core;
76 public void unsetController(IController core) {
77 if (this.controller == core) {
78 this.controller = null;
82 public void setReadFilterInternalListener(Map<?, ?> props, IReadFilterInternalListener s) {
84 logger.error("Failed setting Read Filter Listener, property map is null.");
87 String containerName = (String) props.get("containerName");
88 if (containerName == null) {
89 logger.error("Failed setting Read Filter Listener, container name not supplied.");
92 if ((this.readFilterInternalListeners != null) && !this.readFilterInternalListeners.containsValue(s)) {
93 this.readFilterInternalListeners.put(containerName, s);
94 logger.trace("Added Read Filter Listener for container {}", containerName);
98 public void unsetReadFilterInternalListener(Map<?, ?> props, IReadFilterInternalListener s) {
100 logger.error("Failed unsetting Read Filter Listener, property map is null.");
103 String containerName = (String) props.get("containerName");
104 if (containerName == null) {
105 logger.error("Failed unsetting Read Filter Listener, containerName not supplied");
108 if ((this.readFilterInternalListeners != null) && this.readFilterInternalListeners.get(containerName) != null
109 && this.readFilterInternalListeners.get(containerName).equals(s)) {
110 this.readFilterInternalListeners.remove(containerName);
111 logger.trace("Removed Read Filter Listener for container {}", containerName);
116 * Function called by the dependency manager when all the required
117 * dependencies are satisfied
121 containerToNc = new HashMap<String, Set<NodeConnector>>();
122 containerToNt = new HashMap<String, Set<NodeTable>>();
123 containerToNode = new HashMap<String, Set<Node>>();
124 readFilterInternalListeners = new ConcurrentHashMap<String, IReadFilterInternalListener>();
128 * Function called by the dependency manager when at least one
129 * dependency become unsatisfied or when the component is shutting
130 * down because for example bundle is being stopped.
137 * Function called by dependency manager after "init ()" is called
138 * and after the services provided by the class are registered in
139 * the service registry
146 * Function called by the dependency manager before the services
147 * exported by the component are unregistered, this will be
148 * followed by a "destroy ()" calls
154 public void setService(IOFStatisticsManager service) {
155 this.statsMgr = service;
158 public void unsetService(IOFStatisticsManager service) {
159 this.statsMgr = null;
163 public FlowOnNode readFlow(String container, Node node, Flow flow,
166 if (controller == null) {
167 // Avoid to provide cached statistics if controller went down.
168 // They are not valid anymore anyway
169 logger.error("Internal plugin error");
173 long sid = (Long) node.getID();
174 OFMatch ofMatch = new FlowConverter(flow).getOFMatch();
175 List<OFStatistics> ofList;
177 ofList = statsMgr.getOFFlowStatistics(sid, ofMatch, flow.getPriority());
179 ofList = statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, ofMatch);
180 for (OFStatistics ofStat : ofList) {
181 if (((OFFlowStatisticsReply)ofStat).getPriority() == flow.getPriority()){
182 ofList = new ArrayList<OFStatistics>(1);
191 * Convert and filter the statistics per container
193 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList)
194 .getFlowOnNodeList(node);
195 List<FlowOnNode> filteredList = filterFlowListPerContainer(container,
196 node, flowOnNodeList);
198 return (filteredList == null || filteredList.isEmpty()) ? null
199 : filteredList.get(0);
203 public List<FlowOnNode> readAllFlow(String container, Node node,
206 long sid = (Long) node.getID();
207 List<OFStatistics> ofList = (cached == true) ? statsMgr
208 .getOFFlowStatistics(sid) : statsMgr.queryStatistics(sid,
209 OFStatisticsType.FLOW, null);
212 * Convert and filter the statistics per container
214 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList)
215 .getFlowOnNodeList(node);
216 List<FlowOnNode> filteredList = filterFlowListPerContainer(container,
217 node, flowOnNodeList);
219 return (filteredList == null) ? null : filteredList;
224 public NodeDescription readDescription(Node node, boolean cached) {
226 if (controller == null) {
227 logger.error("Internal plugin error");
231 long sid = (Long) node.getID();
232 List<OFStatistics> ofList = (cached == true) ? statsMgr
233 .getOFDescStatistics(sid) : statsMgr.queryStatistics(sid,
234 OFStatisticsType.DESC, null);
236 return new DescStatisticsConverter(ofList).getHwDescription();
240 * Filters a list of FlowOnNode elements based on the container
247 public List<FlowOnNode> filterFlowListPerContainer(String container,
248 Node nodeId, List<FlowOnNode> list) {
253 // Create new filtered list of flows
254 List<FlowOnNode> newList = new ArrayList<FlowOnNode>();
256 for (FlowOnNode target : list) {
257 // Check whether the described flow (match + actions) belongs to this container
258 if (flowBelongToContainer(container, nodeId, target.getFlow())) {
267 * Filters a list of OFStatistics elements based on the container
274 public List<OFStatistics> filterPortListPerContainer(String container,
275 long switchId, List<OFStatistics> list) {
280 // Create new filtered list of flows
281 List<OFStatistics> newList = new ArrayList<OFStatistics>();
283 for (OFStatistics stat : list) {
284 OFPortStatisticsReply target = (OFPortStatisticsReply) stat;
285 NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(
286 target.getPortNumber(), NodeCreator.createOFNode(switchId));
287 if (containerOwnsNodeConnector(container, nc)) {
296 public List<OFStatistics> filterTableListPerContainer(
297 String container, long switchId, List<OFStatistics> list) {
302 // Create new filtered list of node tables
303 List<OFStatistics> newList = new ArrayList<OFStatistics>();
305 for (OFStatistics stat : list) {
306 OFTableStatistics target = (OFTableStatistics) stat;
307 NodeTable nt = NodeTableCreator.createOFNodeTable(
308 target.getTableId(), NodeCreator.createOFNode(switchId));
309 if (containerOwnsNodeTable(container, nt)) {
318 * Returns whether the specified flow (flow match + actions)
319 * belongs to the container
324 * @return true if it belongs
326 public boolean flowBelongToContainer(String container, Node node, Flow flow) {
327 // All flows belong to the default container
328 if (container.equals(GlobalConstants.DEFAULT.toString())) {
331 return (flowPortsBelongToContainer(container, node, flow)
332 && flowVlanBelongsToContainer(container, node, flow) && flowSpecAllowsFlow(
333 container, flow.getMatch()));
337 * Returns whether the passed NodeConnector belongs to the container
339 * @param container container name
340 * @param p node connector to test
341 * @return true if belongs false otherwise
343 public boolean containerOwnsNodeConnector(String container, NodeConnector p) {
344 // All node connectors belong to the default container
345 if (container.equals(GlobalConstants.DEFAULT.toString())) {
348 Set<NodeConnector> portSet = containerToNc.get(container);
349 return (portSet == null) ? false : portSet.contains(p);
353 * Returns whether the passed NodeConnector belongs to the container
355 * @param container container name
356 * @param table node table to test
357 * @return true if belongs false otherwise
359 public boolean containerOwnsNodeTable(String container, NodeTable table) {
360 // All node table belong to the default container
361 if (container.equals(GlobalConstants.DEFAULT.toString())) {
364 Set<NodeTable> tableSet = containerToNt.get(container);
365 return (tableSet == null) ? false : tableSet.contains(table);
369 * Returns whether the container flowspec allows the passed flow
375 private boolean flowSpecAllowsFlow(String container, Match match) {
376 return true; // Always true for now
380 * Check whether the vlan field in the flow match is the same
381 * of the static vlan configured for the container
388 private boolean flowVlanBelongsToContainer(String container, Node node, Flow flow) {
389 return true; // Always true for now
393 * Check whether the ports in the flow match and flow actions for
394 * the specified node belong to the container
401 private boolean flowPortsBelongToContainer(String container, Node node,
403 Match m = flow.getMatch();
404 if (m.isPresent(MatchType.IN_PORT)) {
405 NodeConnector inPort = (NodeConnector) m
406 .getField(MatchType.IN_PORT).getValue();
408 // If the incoming port is specified, check if it belongs to
409 if (!containerOwnsNodeConnector(container, inPort)) {
414 // If an outgoing port is specified, it must belong to this container
415 for (Action action : flow.getActions()) {
416 if (action.getType() == ActionType.OUTPUT) {
417 NodeConnector outPort = ((Output) action)
419 if (!containerOwnsNodeConnector(container, outPort)) {
428 public void containerFlowUpdated(String containerName, ContainerFlow previousFlow,
429 ContainerFlow currentFlow, UpdateType t) {
434 public void nodeConnectorUpdated(String containerName, NodeConnector p,
439 if (!containerToNc.containsKey(containerName)) {
440 containerToNc.put(containerName,
441 Collections.newSetFromMap(new ConcurrentHashMap<NodeConnector,Boolean>()));
443 containerToNc.get(containerName).add(p);
444 if (!containerToNode.containsKey(containerName)) {
445 containerToNode.put(containerName, new HashSet<Node>());
447 containerToNode.get(containerName).add(p.getNode());
450 Set<NodeConnector> ncSet = containerToNc.get(containerName);
452 //remove this nc from container map
455 //check if there are still ports of this node in this container
456 //and if not, remove its mapping
457 boolean nodeInContainer = false;
458 Node node = p.getNode();
459 for (NodeConnector nodeConnector : ncSet) {
460 if (nodeConnector.getNode().equals(node)){
461 nodeInContainer = true;
465 if (! nodeInContainer) {
466 Set<Node> nodeSet = containerToNode.get(containerName);
467 if (nodeSet != null) {
468 nodeSet.remove(node);
479 public void tagUpdated(String containerName, Node n, short oldTag, short newTag, UpdateType t) {
480 // Not interested in this event
484 public void containerModeUpdated(UpdateType t) {
485 // Not interested in this event
489 public NodeConnectorStatistics readNodeConnector(
490 String containerName, NodeConnector connector, boolean cached) {
491 if (!containerOwnsNodeConnector(containerName, connector)) {
494 Node node = connector.getNode();
495 long sid = (Long) node.getID();
496 short portId = (Short) connector.getID();
497 List<OFStatistics> ofList = (cached == true) ? statsMgr
498 .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics(
499 sid, OFStatisticsType.PORT, portId);
501 List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(
502 sid, ofList).getNodeConnectorStatsList();
503 return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics()
504 : ncStatistics.get(0);
508 public List<NodeConnectorStatistics> readAllNodeConnector(
509 String containerName, Node node, boolean cached) {
511 long sid = (Long) node.getID();
512 List<OFStatistics> ofList = (cached == true) ? statsMgr
513 .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid,
514 OFStatisticsType.FLOW, null);
516 List<OFStatistics> filteredList = filterPortListPerContainer(
517 containerName, sid, ofList);
519 return new PortStatisticsConverter(sid, filteredList)
520 .getNodeConnectorStatsList();
524 public long getTransmitRate(String containerName, NodeConnector connector) {
525 if (!containerOwnsNodeConnector(containerName, connector)) {
529 long switchId = (Long) connector.getNode().getID();
530 short port = (Short) connector.getID();
532 return statsMgr.getTransmitRate(switchId, port);
536 public NodeTableStatistics readNodeTable(String containerName,
537 NodeTable table, boolean cached) {
538 if (!containerOwnsNodeTable(containerName, table)) {
541 Node node = table.getNode();
542 long sid = (Long) node.getID();
543 Byte tableId = (Byte) table.getID();
544 List<OFStatistics> ofList = (cached == true) ? statsMgr.getOFTableStatistics(sid, tableId) :
545 statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, tableId);
547 List<NodeTableStatistics> ntStatistics =
548 new TableStatisticsConverter(sid, ofList).getNodeTableStatsList();
550 return (ntStatistics.isEmpty()) ? new NodeTableStatistics() : ntStatistics.get(0);
554 public List<NodeTableStatistics> readAllNodeTable(String containerName, Node node, boolean cached) {
555 long sid = (Long) node.getID();
556 List<OFStatistics> ofList = (cached == true) ?
557 statsMgr.getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, null);
559 List<OFStatistics> filteredList = filterTableListPerContainer(containerName, sid, ofList);
561 return new TableStatisticsConverter(sid, filteredList).getNodeTableStatsList();
565 public void descriptionStatisticsRefreshed(Long switchId, List<OFStatistics> description) {
567 Node node = NodeCreator.createOFNode(switchId);
568 NodeDescription nodeDescription = new DescStatisticsConverter(description).getHwDescription();
569 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
570 container = l.getKey();
571 if (container == GlobalConstants.DEFAULT.toString()
572 || (containerToNode.containsKey(container) && containerToNode.get(container).contains(node))) {
573 l.getValue().nodeDescriptionStatisticsUpdated(node, nodeDescription);
579 public void flowStatisticsRefreshed(Long switchId, List<OFStatistics> flows) {
581 Node node = NodeCreator.createOFNode(switchId);
582 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
583 container = l.getKey();
585 // Convert and filter the statistics per container
586 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(flows).getFlowOnNodeList(node);
587 flowOnNodeList = filterFlowListPerContainer(container, node, flowOnNodeList);
590 l.getValue().nodeFlowStatisticsUpdated(node, flowOnNodeList);
595 public void portStatisticsRefreshed(Long switchId, List<OFStatistics> ports) {
597 Node node = NodeCreator.createOFNode(switchId);
598 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
599 container = l.getKey();
601 // Convert and filter the statistics per container
602 List<OFStatistics> filteredPorts = filterPortListPerContainer(container, switchId, ports);
603 List<NodeConnectorStatistics> ncStatsList = new PortStatisticsConverter(switchId, filteredPorts)
604 .getNodeConnectorStatsList();
607 l.getValue().nodeConnectorStatisticsUpdated(node, ncStatsList);
613 public void tableStatisticsRefreshed(Long switchId, List<OFStatistics> tables) {
615 Node node = NodeCreator.createOFNode(switchId);
616 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
617 container = l.getKey();
619 // Convert and filter the statistics per container
620 List<OFStatistics> filteredList = filterTableListPerContainer(container, switchId, tables);
621 List<NodeTableStatistics> tableStatsList = new TableStatisticsConverter(switchId, filteredList)
622 .getNodeTableStatsList();
625 l.getValue().nodeTableStatisticsUpdated(node, tableStatsList);