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.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);
207 return filterFlowListPerContainer(container, node, flowOnNodeList);
211 public NodeDescription readDescription(Node node, boolean cached) {
213 if (controller == null) {
214 logger.error("Internal plugin error");
218 long sid = (Long) node.getID();
219 List<OFStatistics> ofList = (cached == true) ? statsMgr
220 .getOFDescStatistics(sid) : statsMgr.queryStatistics(sid,
221 OFStatisticsType.DESC, null);
223 return new DescStatisticsConverter(ofList).getHwDescription();
227 * Filters a list of FlowOnNode elements based on the container
234 private List<FlowOnNode> filterFlowListPerContainer(String container,
235 Node nodeId, List<FlowOnNode> list) {
237 return Collections.emptyList();
240 // Create new filtered list of flows
241 List<FlowOnNode> newList = new ArrayList<FlowOnNode>();
243 for (FlowOnNode target : list) {
244 // Check whether the described flow (match + actions) belongs to this container
245 if (flowBelongToContainer(container, nodeId, target.getFlow())) {
254 * Filters a list of OFStatistics elements based on the container
261 private List<OFStatistics> filterPortListPerContainer(String container, long switchId, List<OFStatistics> list) {
263 return Collections.emptyList();
266 // Create new filtered list of flows
267 List<OFStatistics> newList = new ArrayList<OFStatistics>();
269 for (OFStatistics stat : list) {
270 OFPortStatisticsReply target = (OFPortStatisticsReply) stat;
271 NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(
272 target.getPortNumber(), NodeCreator.createOFNode(switchId));
273 if (containerOwnsNodeConnector(container, nc)) {
282 private List<OFStatistics> filterTableListPerContainer(
283 String container, long switchId, List<OFStatistics> list) {
285 return Collections.emptyList();
288 // Create new filtered list of node tables
289 List<OFStatistics> newList = new ArrayList<OFStatistics>();
291 for (OFStatistics stat : list) {
292 OFTableStatistics target = (OFTableStatistics) stat;
293 NodeTable nt = NodeTableCreator.createOFNodeTable(target.getTableId(), NodeCreator.createOFNode(switchId));
294 if (containerOwnsNodeTable(container, nt)) {
303 * Returns whether the specified flow (flow match + actions)
304 * belongs to the container
309 * @return true if it belongs
311 public boolean flowBelongToContainer(String container, Node node, Flow flow) {
312 // All flows belong to the default container
313 if (container.equals(GlobalConstants.DEFAULT.toString())) {
316 return (flowPortsBelongToContainer(container, node, flow) &&
317 flowVlanBelongsToContainer(container, node, flow) &&
318 isFlowAllowedByContainer(container, flow));
322 * Returns whether the passed NodeConnector belongs to the container
324 * @param container container name
325 * @param p node connector to test
326 * @return true if belongs false otherwise
328 public boolean containerOwnsNodeConnector(String container, NodeConnector p) {
329 // All node connectors belong to the default container
330 if (container.equals(GlobalConstants.DEFAULT.toString())) {
333 Set<NodeConnector> portSet = containerToNc.get(container);
334 return (portSet == null) ? false : portSet.contains(p);
338 * Returns whether the passed NodeConnector belongs to the container
340 * @param container container name
341 * @param table node table to test
342 * @return true if belongs false otherwise
344 public boolean containerOwnsNodeTable(String container, NodeTable table) {
345 // All node table belong to the default container
346 if (container.equals(GlobalConstants.DEFAULT.toString())) {
349 Set<NodeTable> tableSet = containerToNt.get(container);
350 return (tableSet == null) ? false : tableSet.contains(table);
354 * Returns whether the container flows allow the passed flow
360 private boolean isFlowAllowedByContainer(String container, Flow flow) {
361 Set<ContainerFlow> cFlowSet = this.containerFlows.get(container);
362 if (cFlowSet == null || cFlowSet.isEmpty()) {
365 for (ContainerFlow cFlow : cFlowSet) {
366 if (cFlow.allowsFlow(flow)) {
374 * Check whether the vlan field in the flow match is the same
375 * of the static vlan configured for the container
382 private boolean flowVlanBelongsToContainer(String container, Node node, Flow flow) {
383 return true; // Always true for now
387 * Check whether the ports in the flow match and flow actions for
388 * the specified node belong to the container
395 private boolean flowPortsBelongToContainer(String container, Node node,
397 Match m = flow.getMatch();
398 if (m.isPresent(MatchType.IN_PORT)) {
399 NodeConnector inPort = (NodeConnector) m.getField(MatchType.IN_PORT).getValue();
400 // If the incoming port is specified, check if it belongs to
401 if (!containerOwnsNodeConnector(container, inPort)) {
406 // If an outgoing port is specified, it must belong to this container
407 for (Action action : flow.getActions()) {
408 if (action.getType() == ActionType.OUTPUT) {
409 NodeConnector outPort = ((Output) action).getPort();
410 if (!containerOwnsNodeConnector(container, outPort)) {
419 public void containerFlowUpdated(String containerName, ContainerFlow previousFlow,
420 ContainerFlow currentFlow, UpdateType t) {
421 Set<ContainerFlow> cFlowSet = containerFlows.get(containerName);
424 if (cFlowSet == null) {
425 cFlowSet = new HashSet<ContainerFlow>();
426 containerFlows.put(containerName, cFlowSet);
428 cFlowSet.add(currentFlow);
432 if (cFlowSet != null) {
433 cFlowSet.remove(currentFlow);
442 public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType type) {
446 if (!containerToNc.containsKey(containerName)) {
447 containerToNc.put(containerName,
448 Collections.newSetFromMap(new ConcurrentHashMap<NodeConnector,Boolean>()));
450 containerToNc.get(containerName).add(p);
451 if (!containerToNode.containsKey(containerName)) {
452 containerToNode.put(containerName, new HashSet<Node>());
454 containerToNode.get(containerName).add(p.getNode());
457 Set<NodeConnector> ncSet = containerToNc.get(containerName);
459 //remove this nc from container map
462 //check if there are still ports of this node in this container
463 //and if not, remove its mapping
464 boolean nodeInContainer = false;
465 Node node = p.getNode();
466 for (NodeConnector nodeConnector : ncSet) {
467 if (nodeConnector.getNode().equals(node)){
468 nodeInContainer = true;
472 if (! nodeInContainer) {
473 Set<Node> nodeSet = containerToNode.get(containerName);
474 if (nodeSet != null) {
475 nodeSet.remove(node);
486 public void tagUpdated(String containerName, Node n, short oldTag, short newTag, UpdateType t) {
487 // Not interested in this event
491 public void containerModeUpdated(UpdateType t) {
492 // Not interested in this event
496 public NodeConnectorStatistics readNodeConnector(String containerName, NodeConnector connector, boolean cached) {
497 if (!containerOwnsNodeConnector(containerName, connector)) {
500 Node node = connector.getNode();
501 long sid = (Long) node.getID();
502 short portId = (Short) connector.getID();
503 List<OFStatistics> ofList = (cached == true) ? statsMgr
504 .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics(
505 sid, OFStatisticsType.PORT, portId);
507 List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(sid, ofList)
508 .getNodeConnectorStatsList();
509 return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics() : ncStatistics.get(0);
513 public List<NodeConnectorStatistics> readAllNodeConnector(String containerName, Node node, boolean cached) {
515 long sid = (Long) node.getID();
516 List<OFStatistics> ofList = (cached == true) ? statsMgr
517 .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid,
518 OFStatisticsType.PORT, null);
520 List<OFStatistics> filteredList = filterPortListPerContainer(containerName, sid, ofList);
522 return new PortStatisticsConverter(sid, filteredList).getNodeConnectorStatsList();
526 public long getTransmitRate(String containerName, NodeConnector connector) {
527 if (!containerOwnsNodeConnector(containerName, connector)) {
531 long switchId = (Long) connector.getNode().getID();
532 short port = (Short) connector.getID();
534 return statsMgr.getTransmitRate(switchId, port);
538 public NodeTableStatistics readNodeTable(String containerName,
539 NodeTable table, boolean cached) {
540 if (!containerOwnsNodeTable(containerName, table)) {
543 Node node = table.getNode();
544 long sid = (Long) node.getID();
545 Byte tableId = (Byte) table.getID();
546 List<OFStatistics> ofList = (cached == true) ? statsMgr.getOFTableStatistics(sid, tableId) :
547 statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, tableId);
549 List<NodeTableStatistics> ntStatistics = new TableStatisticsConverter(sid, ofList).getNodeTableStatsList();
551 return (ntStatistics.isEmpty()) ? new NodeTableStatistics() : ntStatistics.get(0);
555 public List<NodeTableStatistics> readAllNodeTable(String containerName, Node node, boolean cached) {
556 long sid = (Long) node.getID();
557 List<OFStatistics> ofList = (cached == true) ?
558 statsMgr.getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, null);
560 List<OFStatistics> filteredList = filterTableListPerContainer(containerName, sid, ofList);
562 return new TableStatisticsConverter(sid, filteredList).getNodeTableStatsList();
566 public void descriptionStatisticsRefreshed(Long switchId, List<OFStatistics> description) {
568 IReadFilterInternalListener listener;
569 Node node = NodeCreator.createOFNode(switchId);
570 NodeDescription nodeDescription = new DescStatisticsConverter(description).getHwDescription();
571 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
572 container = l.getKey();
573 listener = l.getValue();
574 if (container == GlobalConstants.DEFAULT.toString()
575 || (containerToNode.containsKey(container) && containerToNode.get(container).contains(node))) {
576 listener.nodeDescriptionStatisticsUpdated(node, nodeDescription);
582 public void flowStatisticsRefreshed(Long switchId, List<OFStatistics> flows) {
584 IReadFilterInternalListener listener;
585 Node node = NodeCreator.createOFNode(switchId);
586 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
587 container = l.getKey();
588 listener = l.getValue();
590 // Convert and filter the statistics per container
591 List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(flows).getFlowOnNodeList(node);
592 flowOnNodeList = filterFlowListPerContainer(container, node, flowOnNodeList);
595 listener.nodeFlowStatisticsUpdated(node, flowOnNodeList);
600 public void portStatisticsRefreshed(Long switchId, List<OFStatistics> ports) {
602 IReadFilterInternalListener listener;
603 Node node = NodeCreator.createOFNode(switchId);
604 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
605 container = l.getKey();
606 listener = l.getValue();
608 // Convert and filter the statistics per container
609 List<OFStatistics> filteredPorts = filterPortListPerContainer(container, switchId, ports);
610 List<NodeConnectorStatistics> ncStatsList = new PortStatisticsConverter(switchId, filteredPorts)
611 .getNodeConnectorStatsList();
614 listener.nodeConnectorStatisticsUpdated(node, ncStatsList);
619 public void tableStatisticsRefreshed(Long switchId, List<OFStatistics> tables) {
621 Node node = NodeCreator.createOFNode(switchId);
622 for (Map.Entry<String, IReadFilterInternalListener> l : readFilterInternalListeners.entrySet()) {
623 container = l.getKey();
625 // Convert and filter the statistics per container
626 List<OFStatistics> filteredList = filterTableListPerContainer(container, switchId, tables);
627 List<NodeTableStatistics> tableStatsList = new TableStatisticsConverter(switchId, filteredList)
628 .getNodeTableStatsList();
631 l.getValue().nodeTableStatisticsUpdated(node, tableStatsList);
636 public void containerCreate(String containerName) {
641 public void containerDestroy(String containerName) {
642 containerToNc.remove(containerName);
643 containerToNode.remove(containerName);
644 containerToNt.remove(containerName);
645 containerFlows.remove(containerName);