Implement cluster wide topology notifications and let routing use it
[controller.git] / opendaylight / sal / implementation / src / main / java / org / opendaylight / controller / sal / implementation / internal / ReadService.java
1
2 /*
3  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
4  *
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
8  */
9
10 package org.opendaylight.controller.sal.implementation.internal;
11
12 import java.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.CopyOnWriteArraySet;
20
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;
54
55 /**
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
58  */
59 public class ReadService implements IReadService, CommandProvider, IPluginOutReadService {
60
61     protected static final Logger logger = LoggerFactory.getLogger(ReadService.class);
62     private ConcurrentHashMap<String, IPluginInReadService> pluginReader;
63     private Set<IReadServiceListener> readerListeners;
64
65     /**
66      * Function called by the dependency manager when all the required
67      * dependencies are satisfied
68      *
69      */
70     void init() {
71         pluginReader = new ConcurrentHashMap<String, IPluginInReadService>();
72         readerListeners = new CopyOnWriteArraySet<IReadServiceListener>();
73     }
74
75     /**
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.
79      *
80      */
81     void destroy() {
82         // In case of plugin disactivating make sure we clear the
83         // dependencies
84         this.pluginReader.clear();
85     }
86
87     /**
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
91      *
92      */
93     void start() {
94         registerWithOSGIConsole();
95     }
96
97     /**
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
101      *
102      */
103     void stop() {
104     }
105
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");
110             return;
111         }
112
113         logger.trace("Got a service set request {}", s);
114         String type = null;
115         for (Object e : props.entrySet()) {
116             Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
117             logger.trace("Prop key:({}) value:({})", entry.getKey(),
118                     entry.getValue());
119         }
120
121         Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
122         if (value instanceof String) {
123             type = (String) value;
124         }
125         if (type == null) {
126             logger.error("Received a pluginReader without any "
127                     + "protocolPluginType provided");
128         } else {
129             this.pluginReader.put(type, s);
130             logger.debug("Stored the pluginReader for type: {}", type);
131         }
132     }
133
134     public void unsetService(Map<?, ?> props, IPluginInReadService s) {
135         if (this.pluginReader == null) {
136             logger.error("pluginReader store null");
137             return;
138         }
139
140         String type = 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(),
145                     entry.getValue());
146         }
147
148         Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
149         if (value instanceof String) {
150             type = (String) value;
151         }
152         if (type == null) {
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);
158         }
159     }
160     public void setReaderListener(IReadServiceListener service) {
161         logger.trace("Got a listener set request {}", service);
162         this.readerListeners.add(service);
163     }
164
165     public void unsetReaderListener(IReadServiceListener service) {
166         logger.trace("Got a listener Unset request");
167         this.readerListeners.remove(service);
168     }
169
170     @Override
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);
176             }
177         }
178         logger.warn("Plugin {} unavailable", node.getType());
179         return null;
180     }
181
182     @Override
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);
188             }
189         }
190         logger.warn("Plugin {} unavailable", node.getType());
191         return null;
192     }
193
194     @Override
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);
200             }
201         }
202         logger.warn("Plugin {} unavailable", node.getType());
203         return null;
204     }
205
206     @Override
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);
212             }
213         }
214         logger.warn("Plugin {} unavailable", node.getType());
215         return null;
216     }
217
218     @Override
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);
224             }
225         }
226         logger.warn("Plugin {} unavailable", node.getType());
227         return null;
228     }
229
230     @Override
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);
236             }
237         }
238         logger.warn("Plugin {} unavailable", node.getType());
239         return null;
240     }
241
242     @Override
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);
249             }
250         }
251         logger.warn("Plugin {} unavailable", node.getType());
252         return null;
253     }
254
255     @Override
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);
263             }
264         }
265         logger.warn("Plugin {} unavailable", node.getType());
266         return null;
267     }
268
269     @Override
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);
275             }
276         }
277         logger.warn("Plugin {} unavailable", node.getType());
278         return null;
279     }
280
281     @Override
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);
287             }
288         }
289         logger.warn("Plugin {} unavailable", node.getType());
290         return null;
291     }
292
293
294     @Override
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);
301             }
302         }
303         logger.warn("Plugin {} unavailable", node.getType());
304         return null;
305     }
306
307     @Override
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);
314             }
315         }
316         logger.warn("Plugin {} unavailable", node.getType());
317         return null;
318     }
319
320     @Override
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);
326             }
327         }
328         logger.warn("Plugin {} unavailable", node.getType());
329         return null;
330     }
331
332     @Override
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);
339             }
340         }
341         logger.warn("Plugin {} unavailable", node.getType());
342         return 0;
343     }
344
345     @Override
346     public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
347         for (IReadServiceListener l : readerListeners){
348             l.nodeFlowStatisticsUpdated(node, flowStatsList);
349         }
350     }
351
352     @Override
353     public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
354         for (IReadServiceListener l : readerListeners){
355             l.nodeConnectorStatisticsUpdated(node, ncStatsList);
356         }
357     }
358
359     @Override
360     public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
361         for (IReadServiceListener l : readerListeners){
362             l.nodeTableStatisticsUpdated(node, tableStatsList);
363         }
364     }
365
366     @Override
367     public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
368         for (IReadServiceListener l : readerListeners){
369             l.descriptionStatisticsUpdated(node, nodeDescription);
370         }
371     }
372
373     // ---------------- OSGI TEST CODE ------------------------------//
374
375     private void registerWithOSGIConsole() {
376         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
377                 .getBundleContext();
378         bundleContext.registerService(CommandProvider.class.getName(), this,
379                 null);
380     }
381
382     @Override
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");
394
395         return help.toString();
396     }
397
398     public void _readflows(CommandInterpreter ci) {
399         String nodeId = ci.nextArgument();
400         String cacheReq = ci.nextArgument();
401         boolean cached;
402         if (nodeId == null) {
403             ci.print("Node id not specified");
404             return;
405         }
406         cached = (cacheReq == null) ? true : cacheReq.equals("true");
407         Node node = null;
408         try {
409             node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
410         } catch (NumberFormatException e) {
411             logger.error("",e);
412         } catch (ConstructionException e) {
413             logger.error("",e);
414         }
415         List<FlowOnNode> list = (cached) ? this.readAllFlows(node) : this
416                 .nonCachedReadAllFlows(node);
417         if (list != null) {
418             ci.println(list.toString());
419         } else {
420             ci.println("null");
421         }
422     }
423
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();
428         boolean cached;
429         if (nodeId == null) {
430             ci.print("Node id not specified");
431             return;
432         }
433         cached = (cacheReq == null) ? true : cacheReq.equals("true");
434         Node node = null;
435         try {
436             node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
437         } catch (NumberFormatException e) {
438             logger.error("",e);
439         } catch (ConstructionException e) {
440             logger.error("",e);
441         }
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());
447         } else {
448             ci.println("null");
449         }
450     }
451
452     public void _readports(CommandInterpreter ci) {
453         String nodeId = ci.nextArgument();
454         String cacheReq = ci.nextArgument();
455         boolean cached;
456         if (nodeId == null) {
457             ci.print("Node id not specified");
458             return;
459         }
460         cached = (cacheReq == null) ? true : cacheReq.equals("true");
461         Node node = null;
462         try {
463             node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
464         } catch (NumberFormatException e) {
465             logger.error("",e);
466         } catch (ConstructionException e) {
467             logger.error("",e);
468         }
469         List<NodeConnectorStatistics> list = (cached) ? this
470                 .readNodeConnectors(node) : this
471                 .nonCachedReadNodeConnectors(node);
472                 if (list != null) {
473                     ci.println(list.toString());
474                 } else {
475                     ci.println("null");
476                 }
477     }
478
479     public void _readport(CommandInterpreter ci) {
480         String nodeId = ci.nextArgument();
481         String portId = ci.nextArgument();
482         String cacheReq = ci.nextArgument();
483         boolean cached;
484         if (nodeId == null) {
485             ci.print("Node id not specified");
486             return;
487         }
488         if (portId == null) {
489             ci.print("Port id not specified");
490             return;
491         }
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);
500                 if (stats != null) {
501                     ci.println(stats.toString());
502                 } else {
503                     ci.println("null");
504                 }
505     }
506
507     public void _readtable(CommandInterpreter ci) {
508         String nodeId = ci.nextArgument();
509         String tableId = ci.nextArgument();
510         String cacheReq = ci.nextArgument();
511         boolean cached;
512         if (nodeId == null) {
513             ci.print("Node id not specified");
514             return;
515         }
516         if (tableId == null) {
517             ci.print("Table id not specified");
518             return;
519         }
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);
528                 if (stats != null) {
529                     ci.println(stats.toString());
530                 } else {
531                     ci.println("null");
532                 }
533     }
534
535     public void _readdescr(CommandInterpreter ci) {
536         String nodeId = ci.nextArgument();
537         String cacheReq = ci.nextArgument();
538         boolean cached;
539         if (nodeId == null) {
540             ci.print("Node id not specified");
541             return;
542         }
543         cached = (cacheReq == null) ? true : cacheReq.equals("true");
544
545         Node node = null;
546         try {
547             node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
548         } catch (NumberFormatException e) {
549             logger.error("",e);
550         } catch (ConstructionException e) {
551             logger.error("",e);
552         }
553         NodeDescription desc = (cached) ? this.readDescription(node) : this
554                 .nonCachedReadDescription(node);
555         if (desc != null) {
556             ci.println(desc.toString());
557         } else {
558             ci.println("null");
559         }
560     }
561
562     private Flow getSampleFlow(Node node) throws UnknownHostException {
563         NodeConnector port = NodeConnectorCreator.createOFNodeConnector(
564                 (short) 24, node);
565         NodeConnector oport = NodeConnectorCreator.createOFNodeConnector(
566                 (short) 30, node);
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;
577         byte vlanPr = 3;
578         Byte tos = 4;
579         byte proto = IPProtocols.TCP.byteValue();
580         short src = (short) 55000;
581         short dst = 80;
582
583         /*
584          * Create a SAL Flow aFlow
585          */
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);
599
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);
606     }
607 }