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.Collections;
16 import java.util.List;
19 import java.util.concurrent.ConcurrentHashMap;
20 import java.util.concurrent.CopyOnWriteArraySet;
22 import org.eclipse.osgi.framework.console.CommandInterpreter;
23 import org.eclipse.osgi.framework.console.CommandProvider;
24 import org.opendaylight.controller.sal.action.Action;
25 import org.opendaylight.controller.sal.action.Controller;
26 import org.opendaylight.controller.sal.action.Flood;
27 import org.opendaylight.controller.sal.action.Output;
28 import org.opendaylight.controller.sal.action.PopVlan;
29 import org.opendaylight.controller.sal.core.ConstructionException;
30 import org.opendaylight.controller.sal.core.Node;
31 import org.opendaylight.controller.sal.core.Node.NodeIDType;
32 import org.opendaylight.controller.sal.core.NodeConnector;
33 import org.opendaylight.controller.sal.core.NodeTable;
34 import org.opendaylight.controller.sal.flowprogrammer.Flow;
35 import org.opendaylight.controller.sal.match.Match;
36 import org.opendaylight.controller.sal.match.MatchType;
37 import org.opendaylight.controller.sal.reader.FlowOnNode;
38 import org.opendaylight.controller.sal.reader.IPluginInReadService;
39 import org.opendaylight.controller.sal.reader.IPluginOutReadService;
40 import org.opendaylight.controller.sal.reader.IReadService;
41 import org.opendaylight.controller.sal.reader.IReadServiceListener;
42 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
43 import org.opendaylight.controller.sal.reader.NodeDescription;
44 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
45 import org.opendaylight.controller.sal.utils.EtherTypes;
46 import org.opendaylight.controller.sal.utils.GlobalConstants;
47 import org.opendaylight.controller.sal.utils.IPProtocols;
48 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
49 import org.opendaylight.controller.sal.utils.NodeCreator;
50 import org.opendaylight.controller.sal.utils.NodeTableCreator;
51 import org.osgi.framework.BundleContext;
52 import org.osgi.framework.FrameworkUtil;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
57 * The SAL Read Service. Dispatches read requests to the proper SDN protocol
58 * plugin, and notifies any listeners on updates from any plugin readers
60 public class ReadService implements IReadService, CommandProvider, IPluginOutReadService {
62 protected static final Logger logger = LoggerFactory.getLogger(ReadService.class);
63 private ConcurrentHashMap<String, IPluginInReadService> pluginReader =
64 new ConcurrentHashMap<String, IPluginInReadService>();
65 private Set<IReadServiceListener> readerListeners =
66 new CopyOnWriteArraySet<IReadServiceListener>();
69 * Function called by the dependency manager when all the required
70 * dependencies are satisfied
77 * Function called by the dependency manager when at least one
78 * dependency become unsatisfied or when the component is shutting
79 * down because for example bundle is being stopped.
83 // In case of plugin disactivating make sure we clear the
85 this.pluginReader.clear();
86 this.readerListeners.clear();
90 * Function called by dependency manager after "init ()" is called
91 * and after the services provided by the class are registered in
92 * the service registry
96 registerWithOSGIConsole();
100 * Function called by the dependency manager before the services
101 * exported by the component are unregistered, this will be
102 * followed by a "destroy ()" calls
108 // Set the reference to the plugin flow Reader service
109 public void setService(Map<?, ?> props, IPluginInReadService s) {
110 if (this.pluginReader == null) {
111 logger.error("pluginReader store null");
115 logger.trace("Got a service set request {}", s);
117 for (Object e : props.entrySet()) {
118 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
119 logger.trace("Prop key:({}) value:({})", entry.getKey(),
123 Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
124 if (value instanceof String) {
125 type = (String) value;
128 logger.error("Received a pluginReader without any "
129 + "protocolPluginType provided");
131 this.pluginReader.put(type, s);
132 logger.debug("Stored the pluginReader for type: {}", type);
136 public void unsetService(Map<?, ?> props, IPluginInReadService s) {
137 if (this.pluginReader == null) {
138 logger.error("pluginReader store null");
143 logger.debug("Received unsetpluginReader request");
144 for (Object e : props.entrySet()) {
145 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
146 logger.trace("Prop key:({}) value:({})", entry.getKey(),
150 Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
151 if (value instanceof String) {
152 type = (String) value;
155 logger.error("Received a pluginReader without any "
156 + "protocolPluginType provided");
157 } else if (this.pluginReader.get(type).equals(s)) {
158 this.pluginReader.remove(type);
159 logger.debug("Removed the pluginReader for type: {}", type);
162 public void setReaderListener(IReadServiceListener service) {
163 logger.trace("Got a listener set request {}", service);
164 this.readerListeners.add(service);
167 public void unsetReaderListener(IReadServiceListener service) {
168 logger.trace("Got a listener Unset request");
169 this.readerListeners.remove(service);
173 public FlowOnNode readFlow(Node node, Flow flow) {
174 if (pluginReader != null) {
175 if (this.pluginReader.get(node.getType()) != null) {
176 return this.pluginReader.get(node.getType())
177 .readFlow(node, flow, true);
180 logger.warn("Plugin {} unavailable", node.getType());
185 public FlowOnNode nonCachedReadFlow(Node node, Flow flow) {
186 if (pluginReader != null) {
187 if (this.pluginReader.get(node.getType()) != null) {
188 return this.pluginReader.get(node.getType())
189 .readFlow(node, flow, false);
192 logger.warn("Plugin {} unavailable", node.getType());
197 public List<FlowOnNode> readAllFlows(Node node) {
198 if (pluginReader != null) {
199 if (this.pluginReader.get(node.getType()) != null) {
200 return this.pluginReader.get(node.getType())
201 .readAllFlow(node, true);
204 logger.warn("Plugin {} unavailable", node.getType());
205 return Collections.emptyList();
209 public List<FlowOnNode> nonCachedReadAllFlows(Node node) {
210 if (pluginReader != null) {
211 if (this.pluginReader.get(node.getType()) != null) {
212 return this.pluginReader.get(node.getType())
213 .readAllFlow(node, false);
216 logger.warn("Plugin {} unavailable", node.getType());
217 return Collections.emptyList();
221 public NodeDescription readDescription(Node node) {
222 if (pluginReader != null) {
223 if (this.pluginReader.get(node.getType()) != null) {
224 return this.pluginReader.get(node.getType())
225 .readDescription(node, true);
228 logger.warn("Plugin {} unavailable", node.getType());
233 public NodeDescription nonCachedReadDescription(Node node) {
234 if (pluginReader != null) {
235 if (this.pluginReader.get(node.getType()) != null) {
236 return this.pluginReader.get(node.getType())
237 .readDescription(node, false);
240 logger.warn("Plugin {} unavailable", node.getType());
245 public NodeConnectorStatistics readNodeConnector(NodeConnector connector) {
246 Node node = connector.getNode();
247 if (pluginReader != null && node != null) {
248 if (this.pluginReader.get(node.getType()) != null) {
249 return this.pluginReader.get(node.getType())
250 .readNodeConnector(connector, true);
253 logger.warn("Plugin {} unavailable", node.getType());
258 public NodeConnectorStatistics nonCachedReadNodeConnector(
259 NodeConnector connector) {
260 Node node = connector.getNode();
261 if (pluginReader != null && node != null) {
262 if (this.pluginReader.get(node.getType()) != null) {
263 return this.pluginReader.get(node.getType())
264 .readNodeConnector(connector, false);
267 logger.warn("Plugin {} unavailable", node.getType());
272 public List<NodeConnectorStatistics> readNodeConnectors(Node node) {
273 if (pluginReader != null) {
274 if (this.pluginReader.get(node.getType()) != null) {
275 return this.pluginReader.get(node.getType())
276 .readAllNodeConnector(node, true);
279 logger.warn("Plugin {} unavailable", node.getType());
280 return Collections.emptyList();
284 public List<NodeTableStatistics> readNodeTable(Node node) {
285 if (pluginReader != null) {
286 if (this.pluginReader.get(node.getType()) != null) {
287 return this.pluginReader.get(node.getType())
288 .readAllNodeTable(node, true);
291 logger.warn("Plugin {} unavailable", node.getType());
292 return Collections.emptyList();
297 public NodeTableStatistics nonCachedReadNodeTable(NodeTable table) {
298 Node node = table.getNode();
299 if (pluginReader != null && node != null) {
300 if (this.pluginReader.get(node.getType()) != null) {
301 return this.pluginReader.get(node.getType())
302 .readNodeTable(table, false);
305 logger.warn("Plugin {} unavailable", node.getType());
310 public NodeTableStatistics readNodeTable(NodeTable table) {
311 Node node = table.getNode();
312 if (pluginReader != null && node != null) {
313 if (this.pluginReader.get(node.getType()) != null) {
314 return this.pluginReader.get(node.getType())
315 .readNodeTable(table, true);
318 logger.warn("Plugin {} unavailable", node.getType());
323 public List<NodeConnectorStatistics> nonCachedReadNodeConnectors(Node node) {
324 if (pluginReader != null) {
325 if (this.pluginReader.get(node.getType()) != null) {
326 return this.pluginReader.get(node.getType())
327 .readAllNodeConnector(node, false);
330 logger.warn("Plugin {} unavailable", node.getType());
331 return Collections.emptyList();
335 public long getTransmitRate(NodeConnector connector) {
336 Node node = connector.getNode();
337 if (pluginReader != null && node != null) {
338 if (this.pluginReader.get(node.getType()) != null) {
339 return this.pluginReader.get(node.getType())
340 .getTransmitRate(connector);
343 logger.warn("Plugin {} unavailable", node.getType());
348 public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
349 for (IReadServiceListener l : readerListeners){
350 l.nodeFlowStatisticsUpdated(node, flowStatsList);
355 public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
356 for (IReadServiceListener l : readerListeners){
357 l.nodeConnectorStatisticsUpdated(node, ncStatsList);
362 public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
363 for (IReadServiceListener l : readerListeners){
364 l.nodeTableStatisticsUpdated(node, tableStatsList);
369 public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
370 for (IReadServiceListener l : readerListeners){
371 l.descriptionStatisticsUpdated(node, nodeDescription);
375 // ---------------- OSGI TEST CODE ------------------------------//
377 private void registerWithOSGIConsole() {
378 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
380 bundleContext.registerService(CommandProvider.class.getName(), this,
385 public String getHelp() {
386 StringBuffer help = new StringBuffer();
387 help.append("---SAL Reader testing commands---\n");
388 help.append("\t readflows <sid> <cached> - Read all the (cached) flows from the openflow switch <sid>\n");
389 help.append("\t readflow <sid> <cached> - Read the (cached) sample flow from the openflow switch <sid>\n");
390 help.append("\t readdescr <sid> <cached> - Read the (cached) description from openflow switch <sid>\n");
391 help.append("\t\t cached = (true|false). If false or not specified, the plugin cached info\n");
392 help.append("\t\t is returned. If true, the info is directly retrieved from the switch\n");
393 help.append("\t readport <sid> <port> - Read port statistics for the specified port\n");
394 help.append("\t readports <sid> - Read port statistics for all ports of specified switch\n");
395 help.append("\t readtable <sid> <tableid>- Read specified table statistics\n");
397 return help.toString();
400 public void _readflows(CommandInterpreter ci) {
401 String nodeId = ci.nextArgument();
402 String cacheReq = ci.nextArgument();
404 if (nodeId == null) {
405 ci.print("Node id not specified");
408 cached = (cacheReq == null) ? true : cacheReq.equals("true");
411 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
412 } catch (NumberFormatException e) {
414 } catch (ConstructionException e) {
417 List<FlowOnNode> list = (cached) ? this.readAllFlows(node) : this
418 .nonCachedReadAllFlows(node);
420 ci.println(list.toString());
426 // Requests the hw view for the specific sample flow
427 public void _readflow(CommandInterpreter ci) throws UnknownHostException {
428 String nodeId = ci.nextArgument();
429 String cacheReq = ci.nextArgument();
431 if (nodeId == null) {
432 ci.print("Node id not specified");
435 cached = (cacheReq == null) ? true : cacheReq.equals("true");
438 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
439 } catch (NumberFormatException e) {
441 } catch (ConstructionException e) {
444 Flow flow = getSampleFlow(node);
445 FlowOnNode flowOnNode = (cached) ? this.readFlow(node, flow) : this
446 .nonCachedReadFlow(node, flow);
447 if (flowOnNode != null) {
448 ci.println(flowOnNode.toString());
454 public void _readports(CommandInterpreter ci) {
455 String nodeId = ci.nextArgument();
456 String cacheReq = ci.nextArgument();
458 if (nodeId == null) {
459 ci.print("Node id not specified");
462 cached = (cacheReq == null) ? true : cacheReq.equals("true");
465 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
466 } catch (NumberFormatException e) {
468 } catch (ConstructionException e) {
471 List<NodeConnectorStatistics> list = (cached) ? this
472 .readNodeConnectors(node) : this
473 .nonCachedReadNodeConnectors(node);
475 ci.println(list.toString());
481 public void _readport(CommandInterpreter ci) {
482 String nodeId = ci.nextArgument();
483 String portId = ci.nextArgument();
484 String cacheReq = ci.nextArgument();
486 if (nodeId == null) {
487 ci.print("Node id not specified");
490 if (portId == null) {
491 ci.print("Port id not specified");
494 cached = (cacheReq == null) ? true : cacheReq.equals("true");
495 NodeConnector nodeConnector = null;
496 Node node = NodeCreator.createOFNode(Long.parseLong(nodeId));
497 nodeConnector = NodeConnectorCreator.createNodeConnector(Short
498 .valueOf(portId), node);
499 NodeConnectorStatistics stats = (cached) ? this
500 .readNodeConnector(nodeConnector) : this
501 .nonCachedReadNodeConnector(nodeConnector);
503 ci.println(stats.toString());
509 public void _readtable(CommandInterpreter ci) {
510 String nodeId = ci.nextArgument();
511 String tableId = ci.nextArgument();
512 String cacheReq = ci.nextArgument();
514 if (nodeId == null) {
515 ci.print("Node id not specified");
518 if (tableId == null) {
519 ci.print("Table id not specified");
522 cached = (cacheReq == null) ? true : cacheReq.equals("true");
523 NodeTable nodeTable = null;
524 Node node = NodeCreator.createOFNode(Long.parseLong(nodeId));
525 nodeTable = NodeTableCreator.createNodeTable(Byte
526 .valueOf(tableId), node);
527 NodeTableStatistics stats = (cached) ? this
528 .readNodeTable(nodeTable) : this
529 .nonCachedReadNodeTable(nodeTable);
531 ci.println(stats.toString());
537 public void _readdescr(CommandInterpreter ci) {
538 String nodeId = ci.nextArgument();
539 String cacheReq = ci.nextArgument();
541 if (nodeId == null) {
542 ci.print("Node id not specified");
545 cached = (cacheReq == null) ? true : cacheReq.equals("true");
549 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
550 } catch (NumberFormatException e) {
552 } catch (ConstructionException e) {
555 NodeDescription desc = (cached) ? this.readDescription(node) : this
556 .nonCachedReadDescription(node);
558 ci.println(desc.toString());
564 private Flow getSampleFlow(Node node) throws UnknownHostException {
565 NodeConnector port = NodeConnectorCreator.createOFNodeConnector(
567 NodeConnector oport = NodeConnectorCreator.createOFNodeConnector(
569 byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78,
570 (byte) 0x9a, (byte) 0xbc };
571 byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d,
572 (byte) 0x5e, (byte) 0x6f };
573 InetAddress srcIP = InetAddress.getByName("172.28.30.50");
574 InetAddress dstIP = InetAddress.getByName("171.71.9.52");
575 InetAddress ipMask = InetAddress.getByName("255.255.255.0");
576 InetAddress ipMask2 = InetAddress.getByName("255.0.0.0");
577 short ethertype = EtherTypes.IPv4.shortValue();
578 short vlan = (short) 27;
581 byte proto = IPProtocols.TCP.byteValue();
582 short src = (short) 55000;
586 * Create a SAL Flow aFlow
588 Match match = new Match();
589 match.setField(MatchType.IN_PORT, port);
590 match.setField(MatchType.DL_SRC, srcMac);
591 match.setField(MatchType.DL_DST, dstMac);
592 match.setField(MatchType.DL_TYPE, ethertype);
593 match.setField(MatchType.DL_VLAN, vlan);
594 match.setField(MatchType.DL_VLAN_PR, vlanPr);
595 match.setField(MatchType.NW_SRC, srcIP, ipMask);
596 match.setField(MatchType.NW_DST, dstIP, ipMask2);
597 match.setField(MatchType.NW_TOS, tos);
598 match.setField(MatchType.NW_PROTO, proto);
599 match.setField(MatchType.TP_SRC, src);
600 match.setField(MatchType.TP_DST, dst);
602 List<Action> actions = new ArrayList<Action>();
603 actions.add(new Output(oport));
604 actions.add(new PopVlan());
605 actions.add(new Flood());
606 actions.add(new Controller());
607 return new Flow(match, actions);