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.sal.implementation.internal;
12 import java.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.ArrayList;
15 import java.util.List;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.CopyOnWriteArraySet;
21 import org.eclipse.osgi.framework.console.CommandInterpreter;
22 import org.eclipse.osgi.framework.console.CommandProvider;
23 import org.opendaylight.controller.sal.action.Action;
24 import org.opendaylight.controller.sal.action.Controller;
25 import org.opendaylight.controller.sal.action.Flood;
26 import org.opendaylight.controller.sal.action.Output;
27 import org.opendaylight.controller.sal.action.PopVlan;
28 import org.opendaylight.controller.sal.core.ConstructionException;
29 import org.opendaylight.controller.sal.core.Node;
30 import org.opendaylight.controller.sal.core.Node.NodeIDType;
31 import org.opendaylight.controller.sal.core.NodeConnector;
32 import org.opendaylight.controller.sal.core.NodeTable;
33 import org.opendaylight.controller.sal.flowprogrammer.Flow;
34 import org.opendaylight.controller.sal.match.Match;
35 import org.opendaylight.controller.sal.match.MatchType;
36 import org.opendaylight.controller.sal.reader.FlowOnNode;
37 import org.opendaylight.controller.sal.reader.IPluginInReadService;
38 import org.opendaylight.controller.sal.reader.IPluginOutReadService;
39 import org.opendaylight.controller.sal.reader.IReadService;
40 import org.opendaylight.controller.sal.reader.IReadServiceListener;
41 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
42 import org.opendaylight.controller.sal.reader.NodeDescription;
43 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
44 import org.opendaylight.controller.sal.utils.EtherTypes;
45 import org.opendaylight.controller.sal.utils.GlobalConstants;
46 import org.opendaylight.controller.sal.utils.IPProtocols;
47 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
48 import org.opendaylight.controller.sal.utils.NodeCreator;
49 import org.opendaylight.controller.sal.utils.NodeTableCreator;
50 import org.osgi.framework.BundleContext;
51 import org.osgi.framework.FrameworkUtil;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
56 * The SAL Read Service. Dispatches read requests to the proper SDN protocol
57 * plugin, and notifies any listeners on updates from any plugin readers
59 public class ReadService implements IReadService, CommandProvider, IPluginOutReadService {
61 protected static final Logger logger = LoggerFactory.getLogger(ReadService.class);
62 private ConcurrentHashMap<String, IPluginInReadService> pluginReader;
63 private Set<IReadServiceListener> readerListeners;
66 * Function called by the dependency manager when all the required
67 * dependencies are satisfied
71 pluginReader = new ConcurrentHashMap<String, IPluginInReadService>();
72 readerListeners = new CopyOnWriteArraySet<IReadServiceListener>();
76 * Function called by the dependency manager when at least one
77 * dependency become unsatisfied or when the component is shutting
78 * down because for example bundle is being stopped.
82 // In case of plugin disactivating make sure we clear the
84 this.pluginReader.clear();
88 * Function called by dependency manager after "init ()" is called
89 * and after the services provided by the class are registered in
90 * the service registry
94 registerWithOSGIConsole();
98 * Function called by the dependency manager before the services
99 * exported by the component are unregistered, this will be
100 * followed by a "destroy ()" calls
106 // Set the reference to the plugin flow Reader service
107 public void setService(Map<?, ?> props, IPluginInReadService s) {
108 if (this.pluginReader == null) {
109 logger.error("pluginReader store null");
113 logger.trace("Got a service set request {}", s);
115 for (Object e : props.entrySet()) {
116 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
117 logger.trace("Prop key:({}) value:({})", entry.getKey(),
121 Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
122 if (value instanceof String) {
123 type = (String) value;
126 logger.error("Received a pluginReader without any "
127 + "protocolPluginType provided");
129 this.pluginReader.put(type, s);
130 logger.debug("Stored the pluginReader for type: {}", type);
134 public void unsetService(Map<?, ?> props, IPluginInReadService s) {
135 if (this.pluginReader == null) {
136 logger.error("pluginReader store null");
141 logger.debug("Received unsetpluginReader request");
142 for (Object e : props.entrySet()) {
143 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
144 logger.trace("Prop key:({}) value:({})", entry.getKey(),
148 Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
149 if (value instanceof String) {
150 type = (String) value;
153 logger.error("Received a pluginReader without any "
154 + "protocolPluginType provided");
155 } else if (this.pluginReader.get(type).equals(s)) {
156 this.pluginReader.remove(type);
157 logger.debug("Removed the pluginReader for type: {}", type);
160 public void setReaderListener(IReadServiceListener service) {
161 logger.trace("Got a listener set request {}", service);
162 this.readerListeners.add(service);
165 public void unsetReaderListener(IReadServiceListener service) {
166 logger.trace("Got a listener Unset request");
167 this.readerListeners.remove(service);
171 public FlowOnNode readFlow(Node node, Flow flow) {
172 if (pluginReader != null) {
173 if (this.pluginReader.get(node.getType()) != null) {
174 return this.pluginReader.get(node.getType())
175 .readFlow(node, flow, true);
178 logger.warn("Plugin {} unavailable", node.getType());
183 public FlowOnNode nonCachedReadFlow(Node node, Flow flow) {
184 if (pluginReader != null) {
185 if (this.pluginReader.get(node.getType()) != null) {
186 return this.pluginReader.get(node.getType())
187 .readFlow(node, flow, false);
190 logger.warn("Plugin {} unavailable", node.getType());
195 public List<FlowOnNode> readAllFlows(Node node) {
196 if (pluginReader != null) {
197 if (this.pluginReader.get(node.getType()) != null) {
198 return this.pluginReader.get(node.getType())
199 .readAllFlow(node, true);
202 logger.warn("Plugin {} unavailable", node.getType());
207 public List<FlowOnNode> nonCachedReadAllFlows(Node node) {
208 if (pluginReader != null) {
209 if (this.pluginReader.get(node.getType()) != null) {
210 return this.pluginReader.get(node.getType())
211 .readAllFlow(node, false);
214 logger.warn("Plugin {} unavailable", node.getType());
219 public NodeDescription readDescription(Node node) {
220 if (pluginReader != null) {
221 if (this.pluginReader.get(node.getType()) != null) {
222 return this.pluginReader.get(node.getType())
223 .readDescription(node, true);
226 logger.warn("Plugin {} unavailable", node.getType());
231 public NodeDescription nonCachedReadDescription(Node node) {
232 if (pluginReader != null) {
233 if (this.pluginReader.get(node.getType()) != null) {
234 return this.pluginReader.get(node.getType())
235 .readDescription(node, false);
238 logger.warn("Plugin {} unavailable", node.getType());
243 public NodeConnectorStatistics readNodeConnector(NodeConnector connector) {
244 Node node = connector.getNode();
245 if (pluginReader != null && node != null) {
246 if (this.pluginReader.get(node.getType()) != null) {
247 return this.pluginReader.get(node.getType())
248 .readNodeConnector(connector, true);
251 logger.warn("Plugin {} unavailable", node.getType());
256 public NodeConnectorStatistics nonCachedReadNodeConnector(
257 NodeConnector connector) {
258 Node node = connector.getNode();
259 if (pluginReader != null && node != null) {
260 if (this.pluginReader.get(node.getType()) != null) {
261 return this.pluginReader.get(node.getType())
262 .readNodeConnector(connector, false);
265 logger.warn("Plugin {} unavailable", node.getType());
270 public List<NodeConnectorStatistics> readNodeConnectors(Node node) {
271 if (pluginReader != null) {
272 if (this.pluginReader.get(node.getType()) != null) {
273 return this.pluginReader.get(node.getType())
274 .readAllNodeConnector(node, true);
277 logger.warn("Plugin {} unavailable", node.getType());
282 public List<NodeTableStatistics> readNodeTable(Node node) {
283 if (pluginReader != null) {
284 if (this.pluginReader.get(node.getType()) != null) {
285 return this.pluginReader.get(node.getType())
286 .readAllNodeTable(node, true);
289 logger.warn("Plugin {} unavailable", node.getType());
295 public NodeTableStatistics nonCachedReadNodeTable(NodeTable table) {
296 Node node = table.getNode();
297 if (pluginReader != null && node != null) {
298 if (this.pluginReader.get(node.getType()) != null) {
299 return this.pluginReader.get(node.getType())
300 .readNodeTable(table, false);
303 logger.warn("Plugin {} unavailable", node.getType());
308 public NodeTableStatistics readNodeTable(NodeTable table) {
309 Node node = table.getNode();
310 if (pluginReader != null && node != null) {
311 if (this.pluginReader.get(node.getType()) != null) {
312 return this.pluginReader.get(node.getType())
313 .readNodeTable(table, true);
316 logger.warn("Plugin {} unavailable", node.getType());
321 public List<NodeConnectorStatistics> nonCachedReadNodeConnectors(Node node) {
322 if (pluginReader != null) {
323 if (this.pluginReader.get(node.getType()) != null) {
324 return this.pluginReader.get(node.getType())
325 .readAllNodeConnector(node, false);
328 logger.warn("Plugin {} unavailable", node.getType());
333 public long getTransmitRate(NodeConnector connector) {
334 Node node = connector.getNode();
335 if (pluginReader != null && node != null) {
336 if (this.pluginReader.get(node.getType()) != null) {
337 return this.pluginReader.get(node.getType())
338 .getTransmitRate(connector);
341 logger.warn("Plugin {} unavailable", node.getType());
346 public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
347 for (IReadServiceListener l : readerListeners){
348 l.nodeFlowStatisticsUpdated(node, flowStatsList);
353 public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
354 for (IReadServiceListener l : readerListeners){
355 l.nodeConnectorStatisticsUpdated(node, ncStatsList);
360 public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
361 for (IReadServiceListener l : readerListeners){
362 l.nodeTableStatisticsUpdated(node, tableStatsList);
367 public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
368 for (IReadServiceListener l : readerListeners){
369 l.descriptionStatisticsUpdated(node, nodeDescription);
373 // ---------------- OSGI TEST CODE ------------------------------//
375 private void registerWithOSGIConsole() {
376 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
378 bundleContext.registerService(CommandProvider.class.getName(), this,
383 public String getHelp() {
384 StringBuffer help = new StringBuffer();
385 help.append("---SAL Reader testing commands---\n");
386 help.append("\t readflows <sid> <cached> - Read all the (cached) flows from the openflow switch <sid>\n");
387 help.append("\t readflow <sid> <cached> - Read the (cached) sample flow from the openflow switch <sid>\n");
388 help.append("\t readdescr <sid> <cached> - Read the (cached) description from openflow switch <sid>\n");
389 help.append("\t\t cached = (true|false). If false or not specified, the plugin cached info\n");
390 help.append("\t\t is returned. If true, the info is directly retrieved from the switch\n");
391 help.append("\t readport <sid> <port> - Read port statistics for the specified port\n");
392 help.append("\t readports <sid> - Read port statistics for all ports of specified switch\n");
393 help.append("\t readtable <sid> <tableid>- Read specified table statistics\n");
395 return help.toString();
398 public void _readflows(CommandInterpreter ci) {
399 String nodeId = ci.nextArgument();
400 String cacheReq = ci.nextArgument();
402 if (nodeId == null) {
403 ci.print("Node id not specified");
406 cached = (cacheReq == null) ? true : cacheReq.equals("true");
409 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
410 } catch (NumberFormatException e) {
412 } catch (ConstructionException e) {
415 List<FlowOnNode> list = (cached) ? this.readAllFlows(node) : this
416 .nonCachedReadAllFlows(node);
418 ci.println(list.toString());
424 // Requests the hw view for the specific sample flow
425 public void _readflow(CommandInterpreter ci) throws UnknownHostException {
426 String nodeId = ci.nextArgument();
427 String cacheReq = ci.nextArgument();
429 if (nodeId == null) {
430 ci.print("Node id not specified");
433 cached = (cacheReq == null) ? true : cacheReq.equals("true");
436 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
437 } catch (NumberFormatException e) {
439 } catch (ConstructionException e) {
442 Flow flow = getSampleFlow(node);
443 FlowOnNode flowOnNode = (cached) ? this.readFlow(node, flow) : this
444 .nonCachedReadFlow(node, flow);
445 if (flowOnNode != null) {
446 ci.println(flowOnNode.toString());
452 public void _readports(CommandInterpreter ci) {
453 String nodeId = ci.nextArgument();
454 String cacheReq = ci.nextArgument();
456 if (nodeId == null) {
457 ci.print("Node id not specified");
460 cached = (cacheReq == null) ? true : cacheReq.equals("true");
463 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
464 } catch (NumberFormatException e) {
466 } catch (ConstructionException e) {
469 List<NodeConnectorStatistics> list = (cached) ? this
470 .readNodeConnectors(node) : this
471 .nonCachedReadNodeConnectors(node);
473 ci.println(list.toString());
479 public void _readport(CommandInterpreter ci) {
480 String nodeId = ci.nextArgument();
481 String portId = ci.nextArgument();
482 String cacheReq = ci.nextArgument();
484 if (nodeId == null) {
485 ci.print("Node id not specified");
488 if (portId == null) {
489 ci.print("Port id not specified");
492 cached = (cacheReq == null) ? true : cacheReq.equals("true");
493 NodeConnector nodeConnector = null;
494 Node node = NodeCreator.createOFNode(Long.parseLong(nodeId));
495 nodeConnector = NodeConnectorCreator.createNodeConnector(Short
496 .valueOf(portId), node);
497 NodeConnectorStatistics stats = (cached) ? this
498 .readNodeConnector(nodeConnector) : this
499 .nonCachedReadNodeConnector(nodeConnector);
501 ci.println(stats.toString());
507 public void _readtable(CommandInterpreter ci) {
508 String nodeId = ci.nextArgument();
509 String tableId = ci.nextArgument();
510 String cacheReq = ci.nextArgument();
512 if (nodeId == null) {
513 ci.print("Node id not specified");
516 if (tableId == null) {
517 ci.print("Table id not specified");
520 cached = (cacheReq == null) ? true : cacheReq.equals("true");
521 NodeTable nodeTable = null;
522 Node node = NodeCreator.createOFNode(Long.parseLong(nodeId));
523 nodeTable = NodeTableCreator.createNodeTable(Byte
524 .valueOf(tableId), node);
525 NodeTableStatistics stats = (cached) ? this
526 .readNodeTable(nodeTable) : this
527 .nonCachedReadNodeTable(nodeTable);
529 ci.println(stats.toString());
535 public void _readdescr(CommandInterpreter ci) {
536 String nodeId = ci.nextArgument();
537 String cacheReq = ci.nextArgument();
539 if (nodeId == null) {
540 ci.print("Node id not specified");
543 cached = (cacheReq == null) ? true : cacheReq.equals("true");
547 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
548 } catch (NumberFormatException e) {
550 } catch (ConstructionException e) {
553 NodeDescription desc = (cached) ? this.readDescription(node) : this
554 .nonCachedReadDescription(node);
556 ci.println(desc.toString());
562 private Flow getSampleFlow(Node node) throws UnknownHostException {
563 NodeConnector port = NodeConnectorCreator.createOFNodeConnector(
565 NodeConnector oport = NodeConnectorCreator.createOFNodeConnector(
567 byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78,
568 (byte) 0x9a, (byte) 0xbc };
569 byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d,
570 (byte) 0x5e, (byte) 0x6f };
571 InetAddress srcIP = InetAddress.getByName("172.28.30.50");
572 InetAddress dstIP = InetAddress.getByName("171.71.9.52");
573 InetAddress ipMask = InetAddress.getByName("255.255.255.0");
574 InetAddress ipMask2 = InetAddress.getByName("255.0.0.0");
575 short ethertype = EtherTypes.IPv4.shortValue();
576 short vlan = (short) 27;
579 byte proto = IPProtocols.TCP.byteValue();
580 short src = (short) 55000;
584 * Create a SAL Flow aFlow
586 Match match = new Match();
587 match.setField(MatchType.IN_PORT, port);
588 match.setField(MatchType.DL_SRC, srcMac);
589 match.setField(MatchType.DL_DST, dstMac);
590 match.setField(MatchType.DL_TYPE, ethertype);
591 match.setField(MatchType.DL_VLAN, vlan);
592 match.setField(MatchType.DL_VLAN_PR, vlanPr);
593 match.setField(MatchType.NW_SRC, srcIP, ipMask);
594 match.setField(MatchType.NW_DST, dstIP, ipMask2);
595 match.setField(MatchType.NW_TOS, tos);
596 match.setField(MatchType.NW_PROTO, proto);
597 match.setField(MatchType.TP_SRC, src);
598 match.setField(MatchType.TP_DST, dst);
600 List<Action> actions = new ArrayList<Action>();
601 actions.add(new Output(oport));
602 actions.add(new PopVlan());
603 actions.add(new Flood());
604 actions.add(new Controller());
605 return new Flow(match, actions);