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.IContainerAware;
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.
59 public class ReadServiceFilter implements IReadServiceFilter, IContainerListener, IOFStatisticsListener, IContainerAware {
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 =
69 new ConcurrentHashMap<String, IReadFilterInternalListener>();
71 public void setController(IController core) {
72 this.controller = core;
75 public void unsetController(IController core) {
76 if (this.controller == core) {
77 this.controller = null;
81 public void setReadFilterInternalListener(Map<?, ?> props, IReadFilterInternalListener s) {
83 logger.error("Failed setting Read Filter Listener, property map is null.");
86 String containerName = (String) props.get("containerName");
87 if (containerName == null) {
88 logger.error("Failed setting Read Filter Listener, container name not supplied.");
91 if ((this.readFilterInternalListeners != null) && !this.readFilterInternalListeners.containsValue(s)) {
92 this.readFilterInternalListeners.put(containerName, s);
93 logger.trace("Added Read Filter Listener for container {}", containerName);
97 public void unsetReadFilterInternalListener(Map<?, ?> props, IReadFilterInternalListener s) {
99 logger.error("Failed unsetting Read Filter Listener, property map is null.");
102 String containerName = (String) props.get("containerName");
103 if (containerName == null) {
104 logger.error("Failed unsetting Read Filter Listener, containerName not supplied");
107 if ((this.readFilterInternalListeners != null) && this.readFilterInternalListeners.get(containerName) != null
108 && this.readFilterInternalListeners.get(containerName).equals(s)) {
109 this.readFilterInternalListeners.remove(containerName);
110 logger.trace("Removed Read Filter Listener for container {}", containerName);
115 * Function called by the dependency manager when all the required
116 * dependencies are satisfied
120 containerToNc = new ConcurrentHashMap<String, Set<NodeConnector>>();
121 containerToNt = new ConcurrentHashMap<String, Set<NodeTable>>();
122 containerToNode = new ConcurrentHashMap<String, Set<Node>>();
123 containerFlows = new ConcurrentHashMap<String, Set<ContainerFlow>>();
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.
133 readFilterInternalListeners.clear();
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, boolean cached) {
165 if (controller == null) {
166 // Avoid to provide cached statistics if controller went down.
167 // They are not valid anymore anyway
168 logger.error("Internal plugin error");
172 long sid = (Long) node.getID();
173 OFMatch ofMatch = new FlowConverter(flow).getOFMatch();
174 List<OFStatistics> ofList;
176 ofList = statsMgr.getOFFlowStatistics(sid, ofMatch, flow.getPriority());
178 ofList = statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, ofMatch);
179 for (OFStatistics ofStat : ofList) {
180 if (((OFFlowStatisticsReply)ofStat).getPriority() == flow.getPriority()){
181 ofList = new ArrayList<OFStatistics>(1);
188 // Convert and filter the statistics per container
189 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList).getFlowOnNodeList(node);
190 List<FlowOnNode> filteredList = filterFlowListPerContainer(container, node, flowOnNodeList);
192 return (filteredList == null || filteredList.isEmpty()) ? null : filteredList.get(0);
196 public List<FlowOnNode> readAllFlow(String container, Node node,
199 long sid = (Long) node.getID();
200 List<OFStatistics> ofList = (cached == true) ? statsMgr
201 .getOFFlowStatistics(sid) : statsMgr.queryStatistics(sid,
202 OFStatisticsType.FLOW, null);
204 // Convert and filter the statistics per container
205 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList).getFlowOnNodeList(node);
206 List<FlowOnNode> filteredList = filterFlowListPerContainer(container, node, flowOnNodeList);
208 return (filteredList == null) ? null : filteredList;
213 public NodeDescription readDescription(Node node, boolean cached) {
215 if (controller == null) {
216 logger.error("Internal plugin error");
220 long sid = (Long) node.getID();
221 List<OFStatistics> ofList = (cached == true) ? statsMgr
222 .getOFDescStatistics(sid) : statsMgr.queryStatistics(sid,
223 OFStatisticsType.DESC, null);
225 return new DescStatisticsConverter(ofList).getHwDescription();
229 * Filters a list of FlowOnNode elements based on the container
236 public List<FlowOnNode> filterFlowListPerContainer(String container,
237 Node nodeId, List<FlowOnNode> list) {
242 // Create new filtered list of flows
243 List<FlowOnNode> newList = new ArrayList<FlowOnNode>();
245 for (FlowOnNode target : list) {
246 // Check whether the described flow (match + actions) belongs to this container
247 if (flowBelongToContainer(container, nodeId, target.getFlow())) {
256 * Filters a list of OFStatistics elements based on the container
263 public List<OFStatistics> filterPortListPerContainer(String container, long switchId, List<OFStatistics> list) {
268 // Create new filtered list of flows
269 List<OFStatistics> newList = new ArrayList<OFStatistics>();
271 for (OFStatistics stat : list) {
272 OFPortStatisticsReply target = (OFPortStatisticsReply) stat;
273 NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(
274 target.getPortNumber(), NodeCreator.createOFNode(switchId));
275 if (containerOwnsNodeConnector(container, nc)) {
284 public List<OFStatistics> filterTableListPerContainer(
285 String container, long switchId, List<OFStatistics> list) {
290 // Create new filtered list of node tables
291 List<OFStatistics> newList = new ArrayList<OFStatistics>();
293 for (OFStatistics stat : list) {
294 OFTableStatistics target = (OFTableStatistics) stat;
295 NodeTable nt = NodeTableCreator.createOFNodeTable(target.getTableId(), NodeCreator.createOFNode(switchId));
296 if (containerOwnsNodeTable(container, nt)) {
305 * Returns whether the specified flow (flow match + actions)
306 * belongs to the container
311 * @return true if it belongs
313 public boolean flowBelongToContainer(String container, Node node, Flow flow) {
314 // All flows belong to the default container
315 if (container.equals(GlobalConstants.DEFAULT.toString())) {
318 return (flowPortsBelongToContainer(container, node, flow) &&
319 flowVlanBelongsToContainer(container, node, flow) &&
320 isFlowAllowedByContainer(container, flow));
324 * Returns whether the passed NodeConnector belongs to the container
326 * @param container container name
327 * @param p node connector to test
328 * @return true if belongs false otherwise
330 public boolean containerOwnsNodeConnector(String container, NodeConnector p) {
331 // All node connectors belong to the default container
332 if (container.equals(GlobalConstants.DEFAULT.toString())) {
335 Set<NodeConnector> portSet = containerToNc.get(container);
336 return (portSet == null) ? false : portSet.contains(p);
340 * Returns whether the passed NodeConnector belongs to the container
342 * @param container container name
343 * @param table node table to test
344 * @return true if belongs false otherwise
346 public boolean containerOwnsNodeTable(String container, NodeTable table) {
347 // All node table belong to the default container
348 if (container.equals(GlobalConstants.DEFAULT.toString())) {
351 Set<NodeTable> tableSet = containerToNt.get(container);
352 return (tableSet == null) ? false : tableSet.contains(table);
356 * Returns whether the container flows allow the passed flow
362 private boolean isFlowAllowedByContainer(String container, Flow flow) {
363 Set<ContainerFlow> cFlowSet = this.containerFlows.get(container);
364 if (cFlowSet == null || cFlowSet.isEmpty()) {
367 for (ContainerFlow cFlow : cFlowSet) {
368 if (cFlow.allowsFlow(flow)) {
376 * Check whether the vlan field in the flow match is the same
377 * of the static vlan configured for the container
384 private boolean flowVlanBelongsToContainer(String container, Node node, Flow flow) {
385 return true; // Always true for now
389 * Check whether the ports in the flow match and flow actions for
390 * the specified node belong to the container
397 private boolean flowPortsBelongToContainer(String container, Node node,
399 Match m = flow.getMatch();
400 if (m.isPresent(MatchType.IN_PORT)) {
401 NodeConnector inPort = (NodeConnector) m.getField(MatchType.IN_PORT).getValue();
402 // If the incoming port is specified, check if it belongs to
403 if (!containerOwnsNodeConnector(container, inPort)) {
408 // If an outgoing port is specified, it must belong to this container
409 for (Action action : flow.getActions()) {
410 if (action.getType() == ActionType.OUTPUT) {
411 NodeConnector outPort = ((Output) action).getPort();
412 if (!containerOwnsNodeConnector(container, outPort)) {
421 public void containerFlowUpdated(String containerName, ContainerFlow previousFlow,
422 ContainerFlow currentFlow, UpdateType t) {
423 Set<ContainerFlow> cFlowSet = containerFlows.get(containerName);
426 if (cFlowSet == null) {
427 cFlowSet = new HashSet<ContainerFlow>();
428 containerFlows.put(containerName, cFlowSet);
430 cFlowSet.add(currentFlow);
434 if (cFlowSet != null) {
435 cFlowSet.remove(currentFlow);
444 public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType type) {
448 if (!containerToNc.containsKey(containerName)) {
449 containerToNc.put(containerName,
450 Collections.newSetFromMap(new ConcurrentHashMap<NodeConnector,Boolean>()));
452 containerToNc.get(containerName).add(p);
453 if (!containerToNode.containsKey(containerName)) {
454 containerToNode.put(containerName, new HashSet<Node>());
456 containerToNode.get(containerName).add(p.getNode());
459 Set<NodeConnector> ncSet = containerToNc.get(containerName);
461 //remove this nc from container map
464 //check if there are still ports of this node in this container
465 //and if not, remove its mapping
466 boolean nodeInContainer = false;
467 Node node = p.getNode();
468 for (NodeConnector nodeConnector : ncSet) {
469 if (nodeConnector.getNode().equals(node)){
470 nodeInContainer = true;
474 if (! nodeInContainer) {
475 Set<Node> nodeSet = containerToNode.get(containerName);
476 if (nodeSet != null) {
477 nodeSet.remove(node);
488 public void tagUpdated(String containerName, Node n, short oldTag, short newTag, UpdateType t) {
489 // Not interested in this event
493 public void containerModeUpdated(UpdateType t) {
494 // Not interested in this event
498 public NodeConnectorStatistics readNodeConnector(String containerName, NodeConnector connector, boolean cached) {
499 if (!containerOwnsNodeConnector(containerName, connector)) {
502 Node node = connector.getNode();
503 long sid = (Long) node.getID();
504 short portId = (Short) connector.getID();
505 List<OFStatistics> ofList = (cached == true) ? statsMgr
506 .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics(
507 sid, OFStatisticsType.PORT, portId);
509 List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(sid, ofList)
510 .getNodeConnectorStatsList();
511 return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics() : ncStatistics.get(0);
515 public List<NodeConnectorStatistics> readAllNodeConnector(String containerName, Node node, boolean cached) {
517 long sid = (Long) node.getID();
518 List<OFStatistics> ofList = (cached == true) ? statsMgr
519 .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid,
520 OFStatisticsType.FLOW, null);
522 List<OFStatistics> filteredList = filterPortListPerContainer(containerName, sid, ofList);
524 return new PortStatisticsConverter(sid, filteredList).getNodeConnectorStatsList();
528 public long getTransmitRate(String containerName, NodeConnector connector) {
529 if (!containerOwnsNodeConnector(containerName, connector)) {
533 long switchId = (Long) connector.getNode().getID();
534 short port = (Short) connector.getID();
536 return statsMgr.getTransmitRate(switchId, port);
540 public NodeTableStatistics readNodeTable(String containerName,
541 NodeTable table, boolean cached) {
542 if (!containerOwnsNodeTable(containerName, table)) {
545 Node node = table.getNode();
546 long sid = (Long) node.getID();
547 Byte tableId = (Byte) table.getID();
548 List<OFStatistics> ofList = (cached == true) ? statsMgr.getOFTableStatistics(sid, tableId) :
549 statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, tableId);
551 List<NodeTableStatistics> ntStatistics = new TableStatisticsConverter(sid, ofList).getNodeTableStatsList();
553 return (ntStatistics.isEmpty()) ? new NodeTableStatistics() : ntStatistics.get(0);
557 public List<NodeTableStatistics> readAllNodeTable(String containerName, Node node, boolean cached) {
558 long sid = (Long) node.getID();
559 List<OFStatistics> ofList = (cached == true) ?
560 statsMgr.getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, null);
562 List<OFStatistics> filteredList = filterTableListPerContainer(containerName, sid, ofList);
564 return new TableStatisticsConverter(sid, filteredList).getNodeTableStatsList();
568 public void descriptionStatisticsRefreshed(Long switchId, List<OFStatistics> description) {
570 IReadFilterInternalListener listener;
571 Node node = NodeCreator.createOFNode(switchId);
572 NodeDescription nodeDescription = new DescStatisticsConverter(description).getHwDescription();
573 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
574 container = l.getKey();
575 listener = l.getValue();
576 if (container == GlobalConstants.DEFAULT.toString()
577 || (containerToNode.containsKey(container) && containerToNode.get(container).contains(node))) {
578 listener.nodeDescriptionStatisticsUpdated(node, nodeDescription);
584 public void flowStatisticsRefreshed(Long switchId, List<OFStatistics> flows) {
586 IReadFilterInternalListener listener;
587 Node node = NodeCreator.createOFNode(switchId);
588 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
589 container = l.getKey();
590 listener = l.getValue();
592 // Convert and filter the statistics per container
593 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(flows).getFlowOnNodeList(node);
594 flowOnNodeList = filterFlowListPerContainer(container, node, flowOnNodeList);
597 listener.nodeFlowStatisticsUpdated(node, flowOnNodeList);
602 public void portStatisticsRefreshed(Long switchId, List<OFStatistics> ports) {
604 IReadFilterInternalListener listener;
605 Node node = NodeCreator.createOFNode(switchId);
606 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
607 container = l.getKey();
608 listener = l.getValue();
610 // Convert and filter the statistics per container
611 List<OFStatistics> filteredPorts = filterPortListPerContainer(container, switchId, ports);
612 List<NodeConnectorStatistics> ncStatsList = new PortStatisticsConverter(switchId, filteredPorts)
613 .getNodeConnectorStatsList();
616 listener.nodeConnectorStatisticsUpdated(node, ncStatsList);
621 public void tableStatisticsRefreshed(Long switchId, List<OFStatistics> tables) {
623 Node node = NodeCreator.createOFNode(switchId);
624 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
625 container = l.getKey();
627 // Convert and filter the statistics per container
628 List<OFStatistics> filteredList = filterTableListPerContainer(container, switchId, tables);
629 List<NodeTableStatistics> tableStatsList = new TableStatisticsConverter(switchId, filteredList)
630 .getNodeTableStatsList();
633 l.getValue().nodeTableStatisticsUpdated(node, tableStatsList);
638 public void containerCreate(String containerName) {
643 public void containerDestroy(String containerName) {
644 containerToNc.remove(containerName);
645 containerToNode.remove(containerName);
646 containerToNt.remove(containerName);
647 containerFlows.remove(containerName);