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.HashSet;
15 import java.util.List;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.ConcurrentMap;
21 import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsListener;
22 import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
23 import org.opendaylight.controller.protocol_plugin.openflow.IReadFilterInternalListener;
24 import org.opendaylight.controller.protocol_plugin.openflow.IReadServiceFilter;
25 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
26 import org.opendaylight.controller.sal.action.Action;
27 import org.opendaylight.controller.sal.action.ActionType;
28 import org.opendaylight.controller.sal.action.Output;
29 import org.opendaylight.controller.sal.core.ContainerFlow;
30 import org.opendaylight.controller.sal.core.IContainerListener;
31 import org.opendaylight.controller.sal.core.Node;
32 import org.opendaylight.controller.sal.core.NodeConnector;
33 import org.opendaylight.controller.sal.core.NodeTable;
34 import org.opendaylight.controller.sal.core.UpdateType;
35 import org.opendaylight.controller.sal.flowprogrammer.Flow;
36 import org.opendaylight.controller.sal.match.Match;
37 import org.opendaylight.controller.sal.match.MatchType;
38 import org.opendaylight.controller.sal.reader.FlowOnNode;
39 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
40 import org.opendaylight.controller.sal.reader.NodeDescription;
41 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
42 import org.opendaylight.controller.sal.utils.GlobalConstants;
43 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
44 import org.opendaylight.controller.sal.utils.NodeCreator;
45 import org.opendaylight.controller.sal.utils.NodeTableCreator;
46 import org.openflow.protocol.OFMatch;
47 import org.openflow.protocol.statistics.OFFlowStatisticsReply;
48 import org.openflow.protocol.statistics.OFPortStatisticsReply;
49 import org.openflow.protocol.statistics.OFStatistics;
50 import org.openflow.protocol.statistics.OFStatisticsType;
51 import org.openflow.protocol.statistics.OFTableStatistics;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
55 * Read Service shim layer which is in charge of filtering the flow statistics
56 * based on container. It is a Global instance.
58 public class ReadServiceFilter implements IReadServiceFilter, IContainerListener, IOFStatisticsListener {
59 private static final Logger logger = LoggerFactory
60 .getLogger(ReadServiceFilter.class);
61 private IController controller = null;
62 private IOFStatisticsManager statsMgr = null;
63 private ConcurrentMap<String, Set<NodeConnector>> containerToNc;
64 private ConcurrentMap<String, Set<Node>> containerToNode;
65 private ConcurrentMap<String, Set<NodeTable>> containerToNt;
66 private ConcurrentMap<String, Set<ContainerFlow>> containerFlows;
67 private ConcurrentMap<String, IReadFilterInternalListener> readFilterInternalListeners =
68 new ConcurrentHashMap<String, IReadFilterInternalListener>();
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>>();
126 * Function called by the dependency manager when at least one
127 * dependency become unsatisfied or when the component is shutting
128 * down because for example bundle is being stopped.
132 readFilterInternalListeners.clear();
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;
162 public FlowOnNode readFlow(String container, Node node, Flow flow, boolean cached) {
164 if (controller == null) {
165 // Avoid to provide cached statistics if controller went down.
166 // They are not valid anymore anyway
167 logger.error("Internal plugin error");
171 long sid = (Long) node.getID();
172 OFMatch ofMatch = new FlowConverter(flow).getOFMatch();
173 List<OFStatistics> ofList;
175 ofList = statsMgr.getOFFlowStatistics(sid, ofMatch, flow.getPriority());
177 ofList = statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, ofMatch);
178 for (OFStatistics ofStat : ofList) {
179 if (((OFFlowStatisticsReply)ofStat).getPriority() == flow.getPriority()){
180 ofList = new ArrayList<OFStatistics>(1);
187 // Convert and filter the statistics per container
188 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList).getFlowOnNodeList(node);
189 List<FlowOnNode> filteredList = filterFlowListPerContainer(container, node, flowOnNodeList);
191 return (filteredList == null || filteredList.isEmpty()) ? null : filteredList.get(0);
195 public List<FlowOnNode> readAllFlow(String container, Node node,
198 long sid = (Long) node.getID();
199 List<OFStatistics> ofList = (cached == true) ? statsMgr
200 .getOFFlowStatistics(sid) : statsMgr.queryStatistics(sid,
201 OFStatisticsType.FLOW, null);
203 // Convert and filter the statistics per container
204 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList).getFlowOnNodeList(node);
205 List<FlowOnNode> filteredList = filterFlowListPerContainer(container, node, flowOnNodeList);
207 return (filteredList == null) ? null : filteredList;
212 public NodeDescription readDescription(Node node, boolean cached) {
214 if (controller == null) {
215 logger.error("Internal plugin error");
219 long sid = (Long) node.getID();
220 List<OFStatistics> ofList = (cached == true) ? statsMgr
221 .getOFDescStatistics(sid) : statsMgr.queryStatistics(sid,
222 OFStatisticsType.DESC, null);
224 return new DescStatisticsConverter(ofList).getHwDescription();
228 * Filters a list of FlowOnNode elements based on the container
235 public List<FlowOnNode> filterFlowListPerContainer(String container,
236 Node nodeId, List<FlowOnNode> list) {
241 // Create new filtered list of flows
242 List<FlowOnNode> newList = new ArrayList<FlowOnNode>();
244 for (FlowOnNode target : list) {
245 // Check whether the described flow (match + actions) belongs to this container
246 if (flowBelongToContainer(container, nodeId, target.getFlow())) {
255 * Filters a list of OFStatistics elements based on the container
262 public List<OFStatistics> filterPortListPerContainer(String container, long switchId, List<OFStatistics> list) {
267 // Create new filtered list of flows
268 List<OFStatistics> newList = new ArrayList<OFStatistics>();
270 for (OFStatistics stat : list) {
271 OFPortStatisticsReply target = (OFPortStatisticsReply) stat;
272 NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(
273 target.getPortNumber(), NodeCreator.createOFNode(switchId));
274 if (containerOwnsNodeConnector(container, nc)) {
283 public List<OFStatistics> filterTableListPerContainer(
284 String container, long switchId, List<OFStatistics> list) {
289 // Create new filtered list of node tables
290 List<OFStatistics> newList = new ArrayList<OFStatistics>();
292 for (OFStatistics stat : list) {
293 OFTableStatistics target = (OFTableStatistics) stat;
294 NodeTable nt = NodeTableCreator.createOFNodeTable(target.getTableId(), NodeCreator.createOFNode(switchId));
295 if (containerOwnsNodeTable(container, nt)) {
304 * Returns whether the specified flow (flow match + actions)
305 * belongs to the container
310 * @return true if it belongs
312 public boolean flowBelongToContainer(String container, Node node, Flow flow) {
313 // All flows belong to the default container
314 if (container.equals(GlobalConstants.DEFAULT.toString())) {
317 return (flowPortsBelongToContainer(container, node, flow) &&
318 flowVlanBelongsToContainer(container, node, flow) &&
319 isFlowAllowedByContainer(container, flow));
323 * Returns whether the passed NodeConnector belongs to the container
325 * @param container container name
326 * @param p node connector to test
327 * @return true if belongs false otherwise
329 public boolean containerOwnsNodeConnector(String container, NodeConnector p) {
330 // All node connectors belong to the default container
331 if (container.equals(GlobalConstants.DEFAULT.toString())) {
334 Set<NodeConnector> portSet = containerToNc.get(container);
335 return (portSet == null) ? false : portSet.contains(p);
339 * Returns whether the passed NodeConnector belongs to the container
341 * @param container container name
342 * @param table node table to test
343 * @return true if belongs false otherwise
345 public boolean containerOwnsNodeTable(String container, NodeTable table) {
346 // All node table belong to the default container
347 if (container.equals(GlobalConstants.DEFAULT.toString())) {
350 Set<NodeTable> tableSet = containerToNt.get(container);
351 return (tableSet == null) ? false : tableSet.contains(table);
355 * Returns whether the container flows allow the passed flow
361 private boolean isFlowAllowedByContainer(String container, Flow flow) {
362 Set<ContainerFlow> cFlowSet = this.containerFlows.get(container);
363 if (cFlowSet == null || cFlowSet.isEmpty()) {
366 for (ContainerFlow cFlow : cFlowSet) {
367 if (cFlow.allowsFlow(flow)) {
375 * Check whether the vlan field in the flow match is the same
376 * of the static vlan configured for the container
383 private boolean flowVlanBelongsToContainer(String container, Node node, Flow flow) {
384 return true; // Always true for now
388 * Check whether the ports in the flow match and flow actions for
389 * the specified node belong to the container
396 private boolean flowPortsBelongToContainer(String container, Node node,
398 Match m = flow.getMatch();
399 if (m.isPresent(MatchType.IN_PORT)) {
400 NodeConnector inPort = (NodeConnector) m.getField(MatchType.IN_PORT).getValue();
401 // If the incoming port is specified, check if it belongs to
402 if (!containerOwnsNodeConnector(container, inPort)) {
407 // If an outgoing port is specified, it must belong to this container
408 for (Action action : flow.getActions()) {
409 if (action.getType() == ActionType.OUTPUT) {
410 NodeConnector outPort = ((Output) action).getPort();
411 if (!containerOwnsNodeConnector(container, outPort)) {
420 public void containerFlowUpdated(String containerName, ContainerFlow previousFlow,
421 ContainerFlow currentFlow, UpdateType t) {
422 Set<ContainerFlow> cFlowSet = containerFlows.get(containerName);
425 if (cFlowSet == null) {
426 cFlowSet = new HashSet<ContainerFlow>();
427 containerFlows.put(containerName, cFlowSet);
429 cFlowSet.add(currentFlow);
433 if (cFlowSet != null) {
434 cFlowSet.remove(currentFlow);
443 public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType type) {
447 if (!containerToNc.containsKey(containerName)) {
448 containerToNc.put(containerName,
449 Collections.newSetFromMap(new ConcurrentHashMap<NodeConnector,Boolean>()));
451 containerToNc.get(containerName).add(p);
452 if (!containerToNode.containsKey(containerName)) {
453 containerToNode.put(containerName, new HashSet<Node>());
455 containerToNode.get(containerName).add(p.getNode());
458 Set<NodeConnector> ncSet = containerToNc.get(containerName);
460 //remove this nc from container map
463 //check if there are still ports of this node in this container
464 //and if not, remove its mapping
465 boolean nodeInContainer = false;
466 Node node = p.getNode();
467 for (NodeConnector nodeConnector : ncSet) {
468 if (nodeConnector.getNode().equals(node)){
469 nodeInContainer = true;
473 if (! nodeInContainer) {
474 Set<Node> nodeSet = containerToNode.get(containerName);
475 if (nodeSet != null) {
476 nodeSet.remove(node);
487 public void tagUpdated(String containerName, Node n, short oldTag, short newTag, UpdateType t) {
488 // Not interested in this event
492 public void containerModeUpdated(UpdateType t) {
493 // Not interested in this event
497 public NodeConnectorStatistics readNodeConnector(String containerName, NodeConnector connector, boolean cached) {
498 if (!containerOwnsNodeConnector(containerName, connector)) {
501 Node node = connector.getNode();
502 long sid = (Long) node.getID();
503 short portId = (Short) connector.getID();
504 List<OFStatistics> ofList = (cached == true) ? statsMgr
505 .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics(
506 sid, OFStatisticsType.PORT, portId);
508 List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(sid, ofList)
509 .getNodeConnectorStatsList();
510 return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics() : ncStatistics.get(0);
514 public List<NodeConnectorStatistics> readAllNodeConnector(String containerName, Node node, boolean cached) {
516 long sid = (Long) node.getID();
517 List<OFStatistics> ofList = (cached == true) ? statsMgr
518 .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid,
519 OFStatisticsType.FLOW, null);
521 List<OFStatistics> filteredList = filterPortListPerContainer(containerName, sid, ofList);
523 return new PortStatisticsConverter(sid, filteredList).getNodeConnectorStatsList();
527 public long getTransmitRate(String containerName, NodeConnector connector) {
528 if (!containerOwnsNodeConnector(containerName, connector)) {
532 long switchId = (Long) connector.getNode().getID();
533 short port = (Short) connector.getID();
535 return statsMgr.getTransmitRate(switchId, port);
539 public NodeTableStatistics readNodeTable(String containerName,
540 NodeTable table, boolean cached) {
541 if (!containerOwnsNodeTable(containerName, table)) {
544 Node node = table.getNode();
545 long sid = (Long) node.getID();
546 Byte tableId = (Byte) table.getID();
547 List<OFStatistics> ofList = (cached == true) ? statsMgr.getOFTableStatistics(sid, tableId) :
548 statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, tableId);
550 List<NodeTableStatistics> ntStatistics = new TableStatisticsConverter(sid, ofList).getNodeTableStatsList();
552 return (ntStatistics.isEmpty()) ? new NodeTableStatistics() : ntStatistics.get(0);
556 public List<NodeTableStatistics> readAllNodeTable(String containerName, Node node, boolean cached) {
557 long sid = (Long) node.getID();
558 List<OFStatistics> ofList = (cached == true) ?
559 statsMgr.getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, null);
561 List<OFStatistics> filteredList = filterTableListPerContainer(containerName, sid, ofList);
563 return new TableStatisticsConverter(sid, filteredList).getNodeTableStatsList();
567 public void descriptionStatisticsRefreshed(Long switchId, List<OFStatistics> description) {
569 IReadFilterInternalListener listener;
570 Node node = NodeCreator.createOFNode(switchId);
571 NodeDescription nodeDescription = new DescStatisticsConverter(description).getHwDescription();
572 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
573 container = l.getKey();
574 listener = l.getValue();
575 if (container == GlobalConstants.DEFAULT.toString()
576 || (containerToNode.containsKey(container) && containerToNode.get(container).contains(node))) {
577 listener.nodeDescriptionStatisticsUpdated(node, nodeDescription);
583 public void flowStatisticsRefreshed(Long switchId, List<OFStatistics> flows) {
585 IReadFilterInternalListener listener;
586 Node node = NodeCreator.createOFNode(switchId);
587 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
588 container = l.getKey();
589 listener = l.getValue();
591 // Convert and filter the statistics per container
592 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(flows).getFlowOnNodeList(node);
593 flowOnNodeList = filterFlowListPerContainer(container, node, flowOnNodeList);
596 listener.nodeFlowStatisticsUpdated(node, flowOnNodeList);
601 public void portStatisticsRefreshed(Long switchId, List<OFStatistics> ports) {
603 IReadFilterInternalListener listener;
604 Node node = NodeCreator.createOFNode(switchId);
605 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
606 container = l.getKey();
607 listener = l.getValue();
609 // Convert and filter the statistics per container
610 List<OFStatistics> filteredPorts = filterPortListPerContainer(container, switchId, ports);
611 List<NodeConnectorStatistics> ncStatsList = new PortStatisticsConverter(switchId, filteredPorts)
612 .getNodeConnectorStatsList();
615 listener.nodeConnectorStatisticsUpdated(node, ncStatsList);
620 public void tableStatisticsRefreshed(Long switchId, List<OFStatistics> tables) {
622 Node node = NodeCreator.createOFNode(switchId);
623 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
624 container = l.getKey();
626 // Convert and filter the statistics per container
627 List<OFStatistics> filteredList = filterTableListPerContainer(container, switchId, tables);
628 List<NodeTableStatistics> tableStatsList = new TableStatisticsConverter(switchId, filteredList)
629 .getNodeTableStatsList();
632 l.getValue().nodeTableStatisticsUpdated(node, tableStatsList);