/* * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.sal.implementation.internal; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import org.eclipse.osgi.framework.console.CommandInterpreter; import org.eclipse.osgi.framework.console.CommandProvider; import org.opendaylight.controller.sal.action.Action; import org.opendaylight.controller.sal.action.Controller; import org.opendaylight.controller.sal.action.Flood; import org.opendaylight.controller.sal.action.Output; import org.opendaylight.controller.sal.action.PopVlan; import org.opendaylight.controller.sal.core.ConstructionException; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.Node.NodeIDType; import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.core.NodeTable; import org.opendaylight.controller.sal.flowprogrammer.Flow; import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.controller.sal.reader.FlowOnNode; import org.opendaylight.controller.sal.reader.IPluginInReadService; import org.opendaylight.controller.sal.reader.IPluginOutReadService; import org.opendaylight.controller.sal.reader.IReadService; import org.opendaylight.controller.sal.reader.IReadServiceListener; import org.opendaylight.controller.sal.reader.NodeConnectorStatistics; import org.opendaylight.controller.sal.reader.NodeDescription; import org.opendaylight.controller.sal.reader.NodeTableStatistics; import org.opendaylight.controller.sal.utils.EtherTypes; import org.opendaylight.controller.sal.utils.IPProtocols; import org.opendaylight.controller.sal.utils.NodeConnectorCreator; import org.opendaylight.controller.sal.utils.NodeCreator; import org.opendaylight.controller.sal.utils.NodeTableCreator; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The SAL Read Service. Dispatches read requests to the proper SDN protocol * plugin, and notifies any listeners on updates from any plugin readers */ public class ReadService implements IReadService, CommandProvider, IPluginOutReadService { protected static final Logger logger = LoggerFactory.getLogger(ReadService.class); private ConcurrentHashMap> pluginReader = new ConcurrentHashMap>(); private Set readerListeners = new CopyOnWriteArraySet(); /** * Function called by the dependency manager when all the required * dependencies are satisfied * */ void init() { } /** * Function called by the dependency manager when at least one * dependency become unsatisfied or when the component is shutting * down because for example bundle is being stopped. * */ void destroy() { // In case of plugin disactivating make sure we clear the // dependencies this.pluginReader.clear(); this.readerListeners.clear(); } /** * Function called by dependency manager after "init ()" is called * and after the services provided by the class are registered in * the service registry * */ void start() { registerWithOSGIConsole(); } /** * Function called by the dependency manager before the services * exported by the component are unregistered, this will be * followed by a "destroy ()" calls * */ void stop() { } // Set the reference to the plugin flow Reader service public void setService(Map props, IPluginInReadService s) { ProtocolService.set(this.pluginReader, props, s, logger); } public void unsetService(Map props, IPluginInReadService s) { ProtocolService.unset(this.pluginReader, props, s, logger); } public void setReaderListener(IReadServiceListener service) { logger.trace("Got a listener set request {}", service); this.readerListeners.add(service); } public void unsetReaderListener(IReadServiceListener service) { logger.trace("Got a listener Unset request"); this.readerListeners.remove(service); } @Override public FlowOnNode readFlow(Node node, Flow flow) { if (pluginReader != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readFlow(node, flow, true); } } logger.warn("Plugin {} unavailable", node.getType()); return null; } @Override public FlowOnNode nonCachedReadFlow(Node node, Flow flow) { if (pluginReader != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readFlow(node, flow, false); } } logger.warn("Plugin {} unavailable", node.getType()); return null; } @Override public List readAllFlows(Node node) { if (pluginReader != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readAllFlow(node, true); } } logger.warn("Plugin {} unavailable", node.getType()); return Collections.emptyList(); } @Override public List nonCachedReadAllFlows(Node node) { if (pluginReader != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readAllFlow(node, false); } } logger.warn("Plugin {} unavailable", node.getType()); return Collections.emptyList(); } @Override public NodeDescription readDescription(Node node) { if (pluginReader != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readDescription(node, true); } } logger.warn("Plugin {} unavailable", node.getType()); return null; } @Override public NodeDescription nonCachedReadDescription(Node node) { if (pluginReader != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readDescription(node, false); } } logger.warn("Plugin {} unavailable", node.getType()); return null; } @Override public NodeConnectorStatistics readNodeConnector(NodeConnector connector) { Node node = connector.getNode(); if (pluginReader != null && node != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readNodeConnector(connector, true); } } logger.warn("Plugin {} unavailable", node.getType()); return null; } @Override public NodeConnectorStatistics nonCachedReadNodeConnector( NodeConnector connector) { Node node = connector.getNode(); if (pluginReader != null && node != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readNodeConnector(connector, false); } } logger.warn("Plugin {} unavailable", node.getType()); return null; } @Override public List readNodeConnectors(Node node) { if (pluginReader != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readAllNodeConnector(node, true); } } logger.warn("Plugin {} unavailable", node.getType()); return Collections.emptyList(); } @Override public List readNodeTable(Node node) { if (pluginReader != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readAllNodeTable(node, true); } } logger.warn("Plugin {} unavailable", node.getType()); return Collections.emptyList(); } @Override public NodeTableStatistics nonCachedReadNodeTable(NodeTable table) { Node node = table.getNode(); if (pluginReader != null && node != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readNodeTable(table, false); } } logger.warn("Plugin {} unavailable", node.getType()); return null; } @Override public NodeTableStatistics readNodeTable(NodeTable table) { Node node = table.getNode(); if (pluginReader != null && node != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readNodeTable(table, true); } } logger.warn("Plugin {} unavailable", node.getType()); return null; } @Override public List nonCachedReadNodeConnectors(Node node) { if (pluginReader != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().readAllNodeConnector(node, false); } } logger.warn("Plugin {} unavailable", node.getType()); return Collections.emptyList(); } @Override public long getTransmitRate(NodeConnector connector) { Node node = connector.getNode(); if (pluginReader != null && node != null) { ProtocolService service = this.pluginReader.get(node.getType()); if (service != null) { return service.getService().getTransmitRate(connector); } } logger.warn("Plugin {} unavailable", node.getType()); return 0; } @Override public void nodeFlowStatisticsUpdated(Node node, List flowStatsList) { for (IReadServiceListener l : readerListeners){ l.nodeFlowStatisticsUpdated(node, flowStatsList); } } @Override public void nodeConnectorStatisticsUpdated(Node node, List ncStatsList) { for (IReadServiceListener l : readerListeners){ l.nodeConnectorStatisticsUpdated(node, ncStatsList); } } @Override public void nodeTableStatisticsUpdated(Node node, List tableStatsList) { for (IReadServiceListener l : readerListeners){ l.nodeTableStatisticsUpdated(node, tableStatsList); } } @Override public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) { for (IReadServiceListener l : readerListeners){ l.descriptionStatisticsUpdated(node, nodeDescription); } } // ---------------- OSGI TEST CODE ------------------------------// private void registerWithOSGIConsole() { BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()) .getBundleContext(); bundleContext.registerService(CommandProvider.class.getName(), this, null); } @Override public String getHelp() { StringBuffer help = new StringBuffer(); help.append("---SAL Reader testing commands---\n"); help.append("\t readflows - Read all the (cached) flows from the openflow switch \n"); help.append("\t readflow - Read the (cached) sample flow from the openflow switch \n"); help.append("\t readdescr - Read the (cached) description from openflow switch \n"); help.append("\t\t cached = (true|false). If false or not specified, the plugin cached info\n"); help.append("\t\t is returned. If true, the info is directly retrieved from the switch\n"); help.append("\t readport - Read port statistics for the specified port\n"); help.append("\t readports - Read port statistics for all ports of specified switch\n"); help.append("\t readtable - Read specified table statistics\n"); return help.toString(); } public void _readflows(CommandInterpreter ci) { String nodeId = ci.nextArgument(); String cacheReq = ci.nextArgument(); boolean cached; if (nodeId == null) { ci.print("Node id not specified"); return; } cached = (cacheReq == null) ? true : cacheReq.equals("true"); Node node = null; try { node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId)); } catch (NumberFormatException e) { logger.error("",e); } catch (ConstructionException e) { logger.error("",e); } List list = (cached) ? this.readAllFlows(node) : this .nonCachedReadAllFlows(node); if (list != null) { ci.println(list.toString()); } else { ci.println("null"); } } // Requests the hw view for the specific sample flow public void _readflow(CommandInterpreter ci) throws UnknownHostException { String nodeId = ci.nextArgument(); String cacheReq = ci.nextArgument(); boolean cached; if (nodeId == null) { ci.print("Node id not specified"); return; } cached = (cacheReq == null) ? true : cacheReq.equals("true"); Node node = null; try { node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId)); } catch (NumberFormatException e) { logger.error("",e); } catch (ConstructionException e) { logger.error("",e); } Flow flow = getSampleFlow(node); FlowOnNode flowOnNode = (cached) ? this.readFlow(node, flow) : this .nonCachedReadFlow(node, flow); if (flowOnNode != null) { ci.println(flowOnNode.toString()); } else { ci.println("null"); } } public void _readports(CommandInterpreter ci) { String nodeId = ci.nextArgument(); String cacheReq = ci.nextArgument(); boolean cached; if (nodeId == null) { ci.print("Node id not specified"); return; } cached = (cacheReq == null) ? true : cacheReq.equals("true"); Node node = null; try { node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId)); } catch (NumberFormatException e) { logger.error("",e); } catch (ConstructionException e) { logger.error("",e); } List list = (cached) ? this .readNodeConnectors(node) : this .nonCachedReadNodeConnectors(node); if (list != null) { ci.println(list.toString()); } else { ci.println("null"); } } public void _readport(CommandInterpreter ci) { String nodeId = ci.nextArgument(); String portId = ci.nextArgument(); String cacheReq = ci.nextArgument(); boolean cached; if (nodeId == null) { ci.print("Node id not specified"); return; } if (portId == null) { ci.print("Port id not specified"); return; } cached = (cacheReq == null) ? true : cacheReq.equals("true"); NodeConnector nodeConnector = null; Node node = NodeCreator.createOFNode(Long.parseLong(nodeId)); nodeConnector = NodeConnectorCreator.createNodeConnector(Short .valueOf(portId), node); NodeConnectorStatistics stats = (cached) ? this .readNodeConnector(nodeConnector) : this .nonCachedReadNodeConnector(nodeConnector); if (stats != null) { ci.println(stats.toString()); } else { ci.println("null"); } } public void _readtable(CommandInterpreter ci) { String nodeId = ci.nextArgument(); String tableId = ci.nextArgument(); String cacheReq = ci.nextArgument(); boolean cached; if (nodeId == null) { ci.print("Node id not specified"); return; } if (tableId == null) { ci.print("Table id not specified"); return; } cached = (cacheReq == null) ? true : cacheReq.equals("true"); NodeTable nodeTable = null; Node node = NodeCreator.createOFNode(Long.parseLong(nodeId)); nodeTable = NodeTableCreator.createNodeTable(Byte .valueOf(tableId), node); NodeTableStatistics stats = (cached) ? this .readNodeTable(nodeTable) : this .nonCachedReadNodeTable(nodeTable); if (stats != null) { ci.println(stats.toString()); } else { ci.println("null"); } } public void _readdescr(CommandInterpreter ci) { String nodeId = ci.nextArgument(); String cacheReq = ci.nextArgument(); boolean cached; if (nodeId == null) { ci.print("Node id not specified"); return; } cached = (cacheReq == null) ? true : cacheReq.equals("true"); Node node = null; try { node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId)); } catch (NumberFormatException e) { logger.error("",e); } catch (ConstructionException e) { logger.error("",e); } NodeDescription desc = (cached) ? this.readDescription(node) : this .nonCachedReadDescription(node); if (desc != null) { ci.println(desc.toString()); } else { ci.println("null"); } } private Flow getSampleFlow(Node node) throws UnknownHostException { NodeConnector port = NodeConnectorCreator.createOFNodeConnector( (short) 24, node); NodeConnector oport = NodeConnectorCreator.createOFNodeConnector( (short) 30, node); byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0x9a, (byte) 0xbc }; byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d, (byte) 0x5e, (byte) 0x6f }; InetAddress srcIP = InetAddress.getByName("172.28.30.50"); InetAddress dstIP = InetAddress.getByName("171.71.9.52"); InetAddress ipMask = InetAddress.getByName("255.255.255.0"); InetAddress ipMask2 = InetAddress.getByName("255.0.0.0"); short ethertype = EtherTypes.IPv4.shortValue(); short vlan = (short) 27; byte vlanPr = 3; Byte tos = 4; byte proto = IPProtocols.TCP.byteValue(); short src = (short) 55000; short dst = 80; /* * Create a SAL Flow aFlow */ Match match = new Match(); match.setField(MatchType.IN_PORT, port); match.setField(MatchType.DL_SRC, srcMac); match.setField(MatchType.DL_DST, dstMac); match.setField(MatchType.DL_TYPE, ethertype); match.setField(MatchType.DL_VLAN, vlan); match.setField(MatchType.DL_VLAN_PR, vlanPr); match.setField(MatchType.NW_SRC, srcIP, ipMask); match.setField(MatchType.NW_DST, dstIP, ipMask2); match.setField(MatchType.NW_TOS, tos); match.setField(MatchType.NW_PROTO, proto); match.setField(MatchType.TP_SRC, src); match.setField(MatchType.TP_DST, dst); List actions = new ArrayList(); actions.add(new Output(oport)); actions.add(new PopVlan()); actions.add(new Flood()); actions.add(new Controller()); return new Flow(match, actions); } }