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 new ConcurrentHashMap<String, IPluginInReadService>();
64 private Set<IReadServiceListener> readerListeners =
65 new CopyOnWriteArraySet<IReadServiceListener>();
68 * Function called by the dependency manager when all the required
69 * dependencies are satisfied
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();
85 this.readerListeners.clear();
89 * Function called by dependency manager after "init ()" is called
90 * and after the services provided by the class are registered in
91 * the service registry
95 registerWithOSGIConsole();
99 * Function called by the dependency manager before the services
100 * exported by the component are unregistered, this will be
101 * followed by a "destroy ()" calls
107 // Set the reference to the plugin flow Reader service
108 public void setService(Map<?, ?> props, IPluginInReadService s) {
109 if (this.pluginReader == null) {
110 logger.error("pluginReader store null");
114 logger.trace("Got a service set request {}", s);
116 for (Object e : props.entrySet()) {
117 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
118 logger.trace("Prop key:({}) value:({})", entry.getKey(),
122 Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
123 if (value instanceof String) {
124 type = (String) value;
127 logger.error("Received a pluginReader without any "
128 + "protocolPluginType provided");
130 this.pluginReader.put(type, s);
131 logger.debug("Stored the pluginReader for type: {}", type);
135 public void unsetService(Map<?, ?> props, IPluginInReadService s) {
136 if (this.pluginReader == null) {
137 logger.error("pluginReader store null");
142 logger.debug("Received unsetpluginReader request");
143 for (Object e : props.entrySet()) {
144 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
145 logger.trace("Prop key:({}) value:({})", entry.getKey(),
149 Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
150 if (value instanceof String) {
151 type = (String) value;
154 logger.error("Received a pluginReader without any "
155 + "protocolPluginType provided");
156 } else if (this.pluginReader.get(type).equals(s)) {
157 this.pluginReader.remove(type);
158 logger.debug("Removed the pluginReader for type: {}", type);
161 public void setReaderListener(IReadServiceListener service) {
162 logger.trace("Got a listener set request {}", service);
163 this.readerListeners.add(service);
166 public void unsetReaderListener(IReadServiceListener service) {
167 logger.trace("Got a listener Unset request");
168 this.readerListeners.remove(service);
172 public FlowOnNode readFlow(Node node, Flow flow) {
173 if (pluginReader != null) {
174 if (this.pluginReader.get(node.getType()) != null) {
175 return this.pluginReader.get(node.getType())
176 .readFlow(node, flow, true);
179 logger.warn("Plugin {} unavailable", node.getType());
184 public FlowOnNode nonCachedReadFlow(Node node, Flow flow) {
185 if (pluginReader != null) {
186 if (this.pluginReader.get(node.getType()) != null) {
187 return this.pluginReader.get(node.getType())
188 .readFlow(node, flow, false);
191 logger.warn("Plugin {} unavailable", node.getType());
196 public List<FlowOnNode> readAllFlows(Node node) {
197 if (pluginReader != null) {
198 if (this.pluginReader.get(node.getType()) != null) {
199 return this.pluginReader.get(node.getType())
200 .readAllFlow(node, true);
203 logger.warn("Plugin {} unavailable", node.getType());
208 public List<FlowOnNode> nonCachedReadAllFlows(Node node) {
209 if (pluginReader != null) {
210 if (this.pluginReader.get(node.getType()) != null) {
211 return this.pluginReader.get(node.getType())
212 .readAllFlow(node, false);
215 logger.warn("Plugin {} unavailable", node.getType());
220 public NodeDescription readDescription(Node node) {
221 if (pluginReader != null) {
222 if (this.pluginReader.get(node.getType()) != null) {
223 return this.pluginReader.get(node.getType())
224 .readDescription(node, true);
227 logger.warn("Plugin {} unavailable", node.getType());
232 public NodeDescription nonCachedReadDescription(Node node) {
233 if (pluginReader != null) {
234 if (this.pluginReader.get(node.getType()) != null) {
235 return this.pluginReader.get(node.getType())
236 .readDescription(node, false);
239 logger.warn("Plugin {} unavailable", node.getType());
244 public NodeConnectorStatistics readNodeConnector(NodeConnector connector) {
245 Node node = connector.getNode();
246 if (pluginReader != null && node != null) {
247 if (this.pluginReader.get(node.getType()) != null) {
248 return this.pluginReader.get(node.getType())
249 .readNodeConnector(connector, true);
252 logger.warn("Plugin {} unavailable", node.getType());
257 public NodeConnectorStatistics nonCachedReadNodeConnector(
258 NodeConnector connector) {
259 Node node = connector.getNode();
260 if (pluginReader != null && node != null) {
261 if (this.pluginReader.get(node.getType()) != null) {
262 return this.pluginReader.get(node.getType())
263 .readNodeConnector(connector, false);
266 logger.warn("Plugin {} unavailable", node.getType());
271 public List<NodeConnectorStatistics> readNodeConnectors(Node node) {
272 if (pluginReader != null) {
273 if (this.pluginReader.get(node.getType()) != null) {
274 return this.pluginReader.get(node.getType())
275 .readAllNodeConnector(node, true);
278 logger.warn("Plugin {} unavailable", node.getType());
283 public List<NodeTableStatistics> readNodeTable(Node node) {
284 if (pluginReader != null) {
285 if (this.pluginReader.get(node.getType()) != null) {
286 return this.pluginReader.get(node.getType())
287 .readAllNodeTable(node, true);
290 logger.warn("Plugin {} unavailable", node.getType());
296 public NodeTableStatistics nonCachedReadNodeTable(NodeTable table) {
297 Node node = table.getNode();
298 if (pluginReader != null && node != null) {
299 if (this.pluginReader.get(node.getType()) != null) {
300 return this.pluginReader.get(node.getType())
301 .readNodeTable(table, false);
304 logger.warn("Plugin {} unavailable", node.getType());
309 public NodeTableStatistics readNodeTable(NodeTable table) {
310 Node node = table.getNode();
311 if (pluginReader != null && node != null) {
312 if (this.pluginReader.get(node.getType()) != null) {
313 return this.pluginReader.get(node.getType())
314 .readNodeTable(table, true);
317 logger.warn("Plugin {} unavailable", node.getType());
322 public List<NodeConnectorStatistics> nonCachedReadNodeConnectors(Node node) {
323 if (pluginReader != null) {
324 if (this.pluginReader.get(node.getType()) != null) {
325 return this.pluginReader.get(node.getType())
326 .readAllNodeConnector(node, false);
329 logger.warn("Plugin {} unavailable", node.getType());
334 public long getTransmitRate(NodeConnector connector) {
335 Node node = connector.getNode();
336 if (pluginReader != null && node != null) {
337 if (this.pluginReader.get(node.getType()) != null) {
338 return this.pluginReader.get(node.getType())
339 .getTransmitRate(connector);
342 logger.warn("Plugin {} unavailable", node.getType());
347 public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
348 for (IReadServiceListener l : readerListeners){
349 l.nodeFlowStatisticsUpdated(node, flowStatsList);
354 public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
355 for (IReadServiceListener l : readerListeners){
356 l.nodeConnectorStatisticsUpdated(node, ncStatsList);
361 public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
362 for (IReadServiceListener l : readerListeners){
363 l.nodeTableStatisticsUpdated(node, tableStatsList);
368 public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
369 for (IReadServiceListener l : readerListeners){
370 l.descriptionStatisticsUpdated(node, nodeDescription);
374 // ---------------- OSGI TEST CODE ------------------------------//
376 private void registerWithOSGIConsole() {
377 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
379 bundleContext.registerService(CommandProvider.class.getName(), this,
384 public String getHelp() {
385 StringBuffer help = new StringBuffer();
386 help.append("---SAL Reader testing commands---\n");
387 help.append("\t readflows <sid> <cached> - Read all the (cached) flows from the openflow switch <sid>\n");
388 help.append("\t readflow <sid> <cached> - Read the (cached) sample flow from the openflow switch <sid>\n");
389 help.append("\t readdescr <sid> <cached> - Read the (cached) description from openflow switch <sid>\n");
390 help.append("\t\t cached = (true|false). If false or not specified, the plugin cached info\n");
391 help.append("\t\t is returned. If true, the info is directly retrieved from the switch\n");
392 help.append("\t readport <sid> <port> - Read port statistics for the specified port\n");
393 help.append("\t readports <sid> - Read port statistics for all ports of specified switch\n");
394 help.append("\t readtable <sid> <tableid>- Read specified table statistics\n");
396 return help.toString();
399 public void _readflows(CommandInterpreter ci) {
400 String nodeId = ci.nextArgument();
401 String cacheReq = ci.nextArgument();
403 if (nodeId == null) {
404 ci.print("Node id not specified");
407 cached = (cacheReq == null) ? true : cacheReq.equals("true");
410 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
411 } catch (NumberFormatException e) {
413 } catch (ConstructionException e) {
416 List<FlowOnNode> list = (cached) ? this.readAllFlows(node) : this
417 .nonCachedReadAllFlows(node);
419 ci.println(list.toString());
425 // Requests the hw view for the specific sample flow
426 public void _readflow(CommandInterpreter ci) throws UnknownHostException {
427 String nodeId = ci.nextArgument();
428 String cacheReq = ci.nextArgument();
430 if (nodeId == null) {
431 ci.print("Node id not specified");
434 cached = (cacheReq == null) ? true : cacheReq.equals("true");
437 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
438 } catch (NumberFormatException e) {
440 } catch (ConstructionException e) {
443 Flow flow = getSampleFlow(node);
444 FlowOnNode flowOnNode = (cached) ? this.readFlow(node, flow) : this
445 .nonCachedReadFlow(node, flow);
446 if (flowOnNode != null) {
447 ci.println(flowOnNode.toString());
453 public void _readports(CommandInterpreter ci) {
454 String nodeId = ci.nextArgument();
455 String cacheReq = ci.nextArgument();
457 if (nodeId == null) {
458 ci.print("Node id not specified");
461 cached = (cacheReq == null) ? true : cacheReq.equals("true");
464 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
465 } catch (NumberFormatException e) {
467 } catch (ConstructionException e) {
470 List<NodeConnectorStatistics> list = (cached) ? this
471 .readNodeConnectors(node) : this
472 .nonCachedReadNodeConnectors(node);
474 ci.println(list.toString());
480 public void _readport(CommandInterpreter ci) {
481 String nodeId = ci.nextArgument();
482 String portId = ci.nextArgument();
483 String cacheReq = ci.nextArgument();
485 if (nodeId == null) {
486 ci.print("Node id not specified");
489 if (portId == null) {
490 ci.print("Port id not specified");
493 cached = (cacheReq == null) ? true : cacheReq.equals("true");
494 NodeConnector nodeConnector = null;
495 Node node = NodeCreator.createOFNode(Long.parseLong(nodeId));
496 nodeConnector = NodeConnectorCreator.createNodeConnector(Short
497 .valueOf(portId), node);
498 NodeConnectorStatistics stats = (cached) ? this
499 .readNodeConnector(nodeConnector) : this
500 .nonCachedReadNodeConnector(nodeConnector);
502 ci.println(stats.toString());
508 public void _readtable(CommandInterpreter ci) {
509 String nodeId = ci.nextArgument();
510 String tableId = ci.nextArgument();
511 String cacheReq = ci.nextArgument();
513 if (nodeId == null) {
514 ci.print("Node id not specified");
517 if (tableId == null) {
518 ci.print("Table id not specified");
521 cached = (cacheReq == null) ? true : cacheReq.equals("true");
522 NodeTable nodeTable = null;
523 Node node = NodeCreator.createOFNode(Long.parseLong(nodeId));
524 nodeTable = NodeTableCreator.createNodeTable(Byte
525 .valueOf(tableId), node);
526 NodeTableStatistics stats = (cached) ? this
527 .readNodeTable(nodeTable) : this
528 .nonCachedReadNodeTable(nodeTable);
530 ci.println(stats.toString());
536 public void _readdescr(CommandInterpreter ci) {
537 String nodeId = ci.nextArgument();
538 String cacheReq = ci.nextArgument();
540 if (nodeId == null) {
541 ci.print("Node id not specified");
544 cached = (cacheReq == null) ? true : cacheReq.equals("true");
548 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
549 } catch (NumberFormatException e) {
551 } catch (ConstructionException e) {
554 NodeDescription desc = (cached) ? this.readDescription(node) : this
555 .nonCachedReadDescription(node);
557 ci.println(desc.toString());
563 private Flow getSampleFlow(Node node) throws UnknownHostException {
564 NodeConnector port = NodeConnectorCreator.createOFNodeConnector(
566 NodeConnector oport = NodeConnectorCreator.createOFNodeConnector(
568 byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78,
569 (byte) 0x9a, (byte) 0xbc };
570 byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d,
571 (byte) 0x5e, (byte) 0x6f };
572 InetAddress srcIP = InetAddress.getByName("172.28.30.50");
573 InetAddress dstIP = InetAddress.getByName("171.71.9.52");
574 InetAddress ipMask = InetAddress.getByName("255.255.255.0");
575 InetAddress ipMask2 = InetAddress.getByName("255.0.0.0");
576 short ethertype = EtherTypes.IPv4.shortValue();
577 short vlan = (short) 27;
580 byte proto = IPProtocols.TCP.byteValue();
581 short src = (short) 55000;
585 * Create a SAL Flow aFlow
587 Match match = new Match();
588 match.setField(MatchType.IN_PORT, port);
589 match.setField(MatchType.DL_SRC, srcMac);
590 match.setField(MatchType.DL_DST, dstMac);
591 match.setField(MatchType.DL_TYPE, ethertype);
592 match.setField(MatchType.DL_VLAN, vlan);
593 match.setField(MatchType.DL_VLAN_PR, vlanPr);
594 match.setField(MatchType.NW_SRC, srcIP, ipMask);
595 match.setField(MatchType.NW_DST, dstIP, ipMask2);
596 match.setField(MatchType.NW_TOS, tos);
597 match.setField(MatchType.NW_PROTO, proto);
598 match.setField(MatchType.TP_SRC, src);
599 match.setField(MatchType.TP_DST, dst);
601 List<Action> actions = new ArrayList<Action>();
602 actions.add(new Output(oport));
603 actions.add(new PopVlan());
604 actions.add(new Flood());
605 actions.add(new Controller());
606 return new Flow(match, actions);