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.openflowplugin.openflow.internal;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.HashSet;
15 import java.util.List;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.ConcurrentMap;
21 import org.opendaylight.controller.sal.action.Action;
22 import org.opendaylight.controller.sal.action.ActionType;
23 import org.opendaylight.controller.sal.action.Output;
24 import org.opendaylight.controller.sal.connection.IPluginOutConnectionService;
25 import org.opendaylight.controller.sal.core.ContainerFlow;
26 import org.opendaylight.controller.sal.core.IContainerListener;
27 import org.opendaylight.controller.sal.core.Node;
28 import org.opendaylight.controller.sal.core.NodeConnector;
29 import org.opendaylight.controller.sal.core.NodeTable;
30 import org.opendaylight.controller.sal.core.UpdateType;
31 import org.opendaylight.controller.sal.flowprogrammer.Flow;
32 import org.opendaylight.controller.sal.match.Match;
33 import org.opendaylight.controller.sal.match.MatchType;
34 import org.opendaylight.controller.sal.reader.FlowOnNode;
35 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
36 import org.opendaylight.controller.sal.reader.NodeDescription;
37 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
38 import org.opendaylight.controller.sal.utils.GlobalConstants;
39 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
40 import org.opendaylight.controller.sal.utils.NodeCreator;
41 import org.opendaylight.controller.sal.utils.NodeTableCreator;
42 import org.opendaylight.openflowplugin.openflow.IOFStatisticsListener;
43 import org.opendaylight.openflowplugin.openflow.IOFStatisticsManager;
44 import org.opendaylight.openflowplugin.openflow.IReadFilterInternalListener;
45 import org.opendaylight.openflowplugin.openflow.IReadServiceFilter;
46 import org.opendaylight.openflowplugin.openflow.core.IController;
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.
59 public class ReadServiceFilter implements IReadServiceFilter, IContainerListener, IOFStatisticsListener {
60 private static final Logger logger = LoggerFactory
61 .getLogger(ReadServiceFilter.class);
62 private IController controller = null;
63 private IOFStatisticsManager statsMgr = null;
64 private ConcurrentMap<String, Set<NodeConnector>> containerToNc;
65 private ConcurrentMap<String, Set<Node>> containerToNode;
66 private ConcurrentMap<String, Set<NodeTable>> containerToNt;
67 private ConcurrentMap<String, Set<ContainerFlow>> containerFlows;
68 private ConcurrentMap<String, IReadFilterInternalListener> readFilterInternalListeners;
70 public void setController(IController core) {
71 this.controller = core;
74 public void unsetController(IController core) {
75 if (this.controller == core) {
76 this.controller = null;
80 public void setReadFilterInternalListener(Map<?, ?> props, IReadFilterInternalListener s) {
82 logger.error("Failed setting Read Filter Listener, property map is null.");
85 String containerName = (String) props.get("containerName");
86 if (containerName == null) {
87 logger.error("Failed setting Read Filter Listener, container name not supplied.");
90 if ((this.readFilterInternalListeners != null) && !this.readFilterInternalListeners.containsValue(s)) {
91 this.readFilterInternalListeners.put(containerName, s);
92 logger.trace("Added Read Filter Listener for container {}", containerName);
96 public void unsetReadFilterInternalListener(Map<?, ?> props, IReadFilterInternalListener s) {
98 logger.error("Failed unsetting Read Filter Listener, property map is null.");
101 String containerName = (String) props.get("containerName");
102 if (containerName == null) {
103 logger.error("Failed unsetting Read Filter Listener, containerName not supplied");
106 if ((this.readFilterInternalListeners != null) && this.readFilterInternalListeners.get(containerName) != null
107 && this.readFilterInternalListeners.get(containerName).equals(s)) {
108 this.readFilterInternalListeners.remove(containerName);
109 logger.trace("Removed Read Filter Listener for container {}", containerName);
114 * Function called by the dependency manager when all the required
115 * dependencies are satisfied
119 containerToNc = new ConcurrentHashMap<String, Set<NodeConnector>>();
120 containerToNt = new ConcurrentHashMap<String, Set<NodeTable>>();
121 containerToNode = new ConcurrentHashMap<String, Set<Node>>();
122 containerFlows = new ConcurrentHashMap<String, Set<ContainerFlow>>();
123 readFilterInternalListeners = new ConcurrentHashMap<String, IReadFilterInternalListener>();
127 * Function called by the dependency manager when at least one
128 * dependency become unsatisfied or when the component is shutting
129 * down because for example bundle is being stopped.
136 * Function called by dependency manager after "init ()" is called
137 * and after the services provided by the class are registered in
138 * the service registry
145 * Function called by the dependency manager before the services
146 * exported by the component are unregistered, this will be
147 * followed by a "destroy ()" calls
153 public void setService(IOFStatisticsManager service) {
154 this.statsMgr = service;
157 public void unsetService(IOFStatisticsManager service) {
158 this.statsMgr = null;
161 IPluginOutConnectionService connectionPluginOutService;
162 void setIPluginOutConnectionService(IPluginOutConnectionService s) {
163 connectionPluginOutService = s;
166 void unsetIPluginOutConnectionService(IPluginOutConnectionService s) {
167 if (connectionPluginOutService == s) {
168 connectionPluginOutService = null;
173 public FlowOnNode readFlow(String container, Node node, Flow flow, boolean cached) {
175 if (controller == null) {
176 // Avoid to provide cached statistics if controller went down.
177 // They are not valid anymore anyway
178 logger.error("Internal plugin error");
182 long sid = (Long) node.getID();
183 OFMatch ofMatch = new FlowConverter(flow).getOFMatch();
184 List<OFStatistics> ofList;
186 ofList = statsMgr.getOFFlowStatistics(sid, ofMatch, flow.getPriority());
188 ofList = statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, ofMatch);
189 for (OFStatistics ofStat : ofList) {
190 if (((OFFlowStatisticsReply)ofStat).getPriority() == flow.getPriority()){
191 ofList = new ArrayList<OFStatistics>(1);
198 // Convert and filter the statistics per container
199 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList).getFlowOnNodeList(node);
200 List<FlowOnNode> filteredList = filterFlowListPerContainer(container, node, flowOnNodeList);
202 return (filteredList == null || filteredList.isEmpty()) ? null : filteredList.get(0);
206 public List<FlowOnNode> readAllFlow(String container, Node node,
209 long sid = (Long) node.getID();
210 List<OFStatistics> ofList = (cached == true) ? statsMgr
211 .getOFFlowStatistics(sid) : statsMgr.queryStatistics(sid,
212 OFStatisticsType.FLOW, null);
214 // Convert and filter the statistics per container
215 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList).getFlowOnNodeList(node);
216 List<FlowOnNode> filteredList = filterFlowListPerContainer(container, node, flowOnNodeList);
218 return (filteredList == null) ? null : filteredList;
223 public NodeDescription readDescription(Node node, boolean cached) {
225 if (controller == null) {
226 logger.error("Internal plugin error");
230 long sid = (Long) node.getID();
231 List<OFStatistics> ofList = (cached == true) ? statsMgr
232 .getOFDescStatistics(sid) : statsMgr.queryStatistics(sid,
233 OFStatisticsType.DESC, null);
235 return new DescStatisticsConverter(ofList).getHwDescription();
239 * Filters a list of FlowOnNode elements based on the container
246 public List<FlowOnNode> filterFlowListPerContainer(String container,
247 Node nodeId, List<FlowOnNode> list) {
252 // Create new filtered list of flows
253 List<FlowOnNode> newList = new ArrayList<FlowOnNode>();
255 for (FlowOnNode target : list) {
256 // Check whether the described flow (match + actions) belongs to this container
257 if (flowBelongToContainer(container, nodeId, target.getFlow())) {
266 * Filters a list of OFStatistics elements based on the container
273 public List<OFStatistics> filterPortListPerContainer(String container, long switchId, List<OFStatistics> list) {
278 // Create new filtered list of flows
279 List<OFStatistics> newList = new ArrayList<OFStatistics>();
281 for (OFStatistics stat : list) {
282 OFPortStatisticsReply target = (OFPortStatisticsReply) stat;
283 NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(
284 target.getPortNumber(), NodeCreator.createOFNode(switchId));
285 if (containerOwnsNodeConnector(container, nc)) {
294 public List<OFStatistics> filterTableListPerContainer(
295 String container, long switchId, List<OFStatistics> list) {
300 // Create new filtered list of node tables
301 List<OFStatistics> newList = new ArrayList<OFStatistics>();
303 for (OFStatistics stat : list) {
304 OFTableStatistics target = (OFTableStatistics) stat;
305 NodeTable nt = NodeTableCreator.createOFNodeTable(target.getTableId(), NodeCreator.createOFNode(switchId));
306 if (containerOwnsNodeTable(container, nt)) {
315 * Returns whether the specified flow (flow match + actions)
316 * belongs to the container
321 * @return true if it belongs
323 public boolean flowBelongToContainer(String container, Node node, Flow flow) {
324 // All flows belong to the default container
325 if (container.equals(GlobalConstants.DEFAULT.toString())) {
328 return (flowPortsBelongToContainer(container, node, flow) &&
329 flowVlanBelongsToContainer(container, node, flow) &&
330 isFlowAllowedByContainer(container, flow));
334 * Returns whether the passed NodeConnector belongs to the container
336 * @param container container name
337 * @param p node connector to test
338 * @return true if belongs false otherwise
340 public boolean containerOwnsNodeConnector(String container, NodeConnector p) {
341 // All node connectors belong to the default container
342 if (container.equals(GlobalConstants.DEFAULT.toString())) {
345 Set<NodeConnector> portSet = containerToNc.get(container);
346 return (portSet == null) ? false : portSet.contains(p);
350 * Returns whether the passed NodeConnector belongs to the container
352 * @param container container name
353 * @param table node table to test
354 * @return true if belongs false otherwise
356 public boolean containerOwnsNodeTable(String container, NodeTable table) {
357 // All node table belong to the default container
358 if (container.equals(GlobalConstants.DEFAULT.toString())) {
361 Set<NodeTable> tableSet = containerToNt.get(container);
362 return (tableSet == null) ? false : tableSet.contains(table);
366 * Returns whether the container flows allow the passed flow
372 private boolean isFlowAllowedByContainer(String container, Flow flow) {
373 Set<ContainerFlow> cFlowSet = this.containerFlows.get(container);
374 if (cFlowSet == null || cFlowSet.isEmpty()) {
377 for (ContainerFlow cFlow : cFlowSet) {
378 if (cFlow.allowsFlow(flow)) {
386 * Check whether the vlan field in the flow match is the same
387 * of the static vlan configured for the container
394 private boolean flowVlanBelongsToContainer(String container, Node node, Flow flow) {
395 return true; // Always true for now
399 * Check whether the ports in the flow match and flow actions for
400 * the specified node belong to the container
407 private boolean flowPortsBelongToContainer(String container, Node node,
409 Match m = flow.getMatch();
410 if (m.isPresent(MatchType.IN_PORT)) {
411 NodeConnector inPort = (NodeConnector) m.getField(MatchType.IN_PORT).getValue();
412 // If the incoming port is specified, check if it belongs to
413 if (!containerOwnsNodeConnector(container, inPort)) {
418 // If an outgoing port is specified, it must belong to this container
419 for (Action action : flow.getActions()) {
420 if (action.getType() == ActionType.OUTPUT) {
421 NodeConnector outPort = ((Output) action).getPort();
422 if (!containerOwnsNodeConnector(container, outPort)) {
431 public void containerFlowUpdated(String containerName, ContainerFlow previousFlow,
432 ContainerFlow currentFlow, UpdateType t) {
433 Set<ContainerFlow> cFlowSet = containerFlows.get(containerName);
436 if (cFlowSet == null) {
437 cFlowSet = new HashSet<ContainerFlow>();
438 containerFlows.put(containerName, cFlowSet);
440 cFlowSet.add(currentFlow);
444 if (cFlowSet != null) {
445 cFlowSet.remove(currentFlow);
454 public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType type) {
458 if (!containerToNc.containsKey(containerName)) {
459 containerToNc.put(containerName,
460 Collections.newSetFromMap(new ConcurrentHashMap<NodeConnector,Boolean>()));
462 containerToNc.get(containerName).add(p);
463 if (!containerToNode.containsKey(containerName)) {
464 containerToNode.put(containerName, new HashSet<Node>());
466 containerToNode.get(containerName).add(p.getNode());
469 Set<NodeConnector> ncSet = containerToNc.get(containerName);
471 //remove this nc from container map
474 //check if there are still ports of this node in this container
475 //and if not, remove its mapping
476 boolean nodeInContainer = false;
477 Node node = p.getNode();
478 for (NodeConnector nodeConnector : ncSet) {
479 if (nodeConnector.getNode().equals(node)){
480 nodeInContainer = true;
484 if (! nodeInContainer) {
485 Set<Node> nodeSet = containerToNode.get(containerName);
486 if (nodeSet != null) {
487 nodeSet.remove(node);
498 public void tagUpdated(String containerName, Node n, short oldTag, short newTag, UpdateType t) {
499 // Not interested in this event
503 public void containerModeUpdated(UpdateType t) {
504 // Not interested in this event
508 public NodeConnectorStatistics readNodeConnector(String containerName, NodeConnector connector, boolean cached) {
509 if (!containerOwnsNodeConnector(containerName, connector)) {
512 Node node = connector.getNode();
513 long sid = (Long) node.getID();
514 short portId = (Short) connector.getID();
515 List<OFStatistics> ofList = (cached == true) ? statsMgr
516 .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics(
517 sid, OFStatisticsType.PORT, portId);
519 List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(sid, ofList)
520 .getNodeConnectorStatsList();
521 return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics() : ncStatistics.get(0);
525 public List<NodeConnectorStatistics> readAllNodeConnector(String containerName, Node node, boolean cached) {
527 long sid = (Long) node.getID();
528 List<OFStatistics> ofList = (cached == true) ? statsMgr
529 .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid,
530 OFStatisticsType.FLOW, null);
532 List<OFStatistics> filteredList = filterPortListPerContainer(containerName, sid, ofList);
534 return new PortStatisticsConverter(sid, filteredList).getNodeConnectorStatsList();
538 public long getTransmitRate(String containerName, NodeConnector connector) {
539 if (!containerOwnsNodeConnector(containerName, connector)) {
543 long switchId = (Long) connector.getNode().getID();
544 short port = (Short) connector.getID();
546 return statsMgr.getTransmitRate(switchId, port);
550 public NodeTableStatistics readNodeTable(String containerName,
551 NodeTable table, boolean cached) {
552 if (!containerOwnsNodeTable(containerName, table)) {
555 Node node = table.getNode();
556 long sid = (Long) node.getID();
557 Byte tableId = (Byte) table.getID();
558 List<OFStatistics> ofList = (cached == true) ? statsMgr.getOFTableStatistics(sid, tableId) :
559 statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, tableId);
561 List<NodeTableStatistics> ntStatistics = new TableStatisticsConverter(sid, ofList).getNodeTableStatsList();
563 return (ntStatistics.isEmpty()) ? new NodeTableStatistics() : ntStatistics.get(0);
567 public List<NodeTableStatistics> readAllNodeTable(String containerName, Node node, boolean cached) {
568 long sid = (Long) node.getID();
569 List<OFStatistics> ofList = (cached == true) ?
570 statsMgr.getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, null);
572 List<OFStatistics> filteredList = filterTableListPerContainer(containerName, sid, ofList);
574 return new TableStatisticsConverter(sid, filteredList).getNodeTableStatsList();
578 public void descriptionStatisticsRefreshed(Long switchId, List<OFStatistics> description) {
580 IReadFilterInternalListener listener;
581 Node node = NodeCreator.createOFNode(switchId);
582 NodeDescription nodeDescription = new DescStatisticsConverter(description).getHwDescription();
583 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
584 container = l.getKey();
585 listener = l.getValue();
586 if (container == GlobalConstants.DEFAULT.toString()
587 || (containerToNode.containsKey(container) && containerToNode.get(container).contains(node))) {
588 listener.nodeDescriptionStatisticsUpdated(node, nodeDescription);
594 public void flowStatisticsRefreshed(Long switchId, List<OFStatistics> flows) {
596 IReadFilterInternalListener listener;
597 Node node = NodeCreator.createOFNode(switchId);
598 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
599 container = l.getKey();
600 listener = l.getValue();
602 // Convert and filter the statistics per container
603 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(flows).getFlowOnNodeList(node);
604 flowOnNodeList = filterFlowListPerContainer(container, node, flowOnNodeList);
607 listener.nodeFlowStatisticsUpdated(node, flowOnNodeList);
612 public void portStatisticsRefreshed(Long switchId, List<OFStatistics> ports) {
614 IReadFilterInternalListener listener;
615 Node node = NodeCreator.createOFNode(switchId);
616 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
617 container = l.getKey();
618 listener = l.getValue();
620 // Convert and filter the statistics per container
621 List<OFStatistics> filteredPorts = filterPortListPerContainer(container, switchId, ports);
622 List<NodeConnectorStatistics> ncStatsList = new PortStatisticsConverter(switchId, filteredPorts)
623 .getNodeConnectorStatsList();
626 listener.nodeConnectorStatisticsUpdated(node, ncStatsList);
631 public void tableStatisticsRefreshed(Long switchId, List<OFStatistics> tables) {
633 Node node = NodeCreator.createOFNode(switchId);
634 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
635 container = l.getKey();
637 // Convert and filter the statistics per container
638 List<OFStatistics> filteredList = filterTableListPerContainer(container, switchId, tables);
639 List<NodeTableStatistics> tableStatsList = new TableStatisticsConverter(switchId, filteredList)
640 .getNodeTableStatsList();
643 l.getValue().nodeTableStatisticsUpdated(node, tableStatsList);