Redirecting Caught and Uncaught Exceptions to OSGI Console and Log File
[controller.git] / opendaylight / sal / implementation / src / main / java / org / opendaylight / controller / sal / implementation / internal / FlowProgrammerService.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.sal.implementation.internal;
10
11 import java.util.Map;
12 import java.util.concurrent.ConcurrentHashMap;
13 import java.net.InetAddress;
14 import java.net.UnknownHostException;
15 import java.util.ArrayList;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Set;
19
20 import org.eclipse.osgi.framework.console.CommandInterpreter;
21 import org.eclipse.osgi.framework.console.CommandProvider;
22 import org.opendaylight.controller.sal.action.Action;
23 import org.opendaylight.controller.sal.action.Controller;
24 import org.opendaylight.controller.sal.action.Flood;
25 import org.opendaylight.controller.sal.action.Output;
26 import org.opendaylight.controller.sal.action.PopVlan;
27 import org.opendaylight.controller.sal.action.SetNwDst;
28 import org.opendaylight.controller.sal.core.ConstructionException;
29 import org.opendaylight.controller.sal.core.Node;
30 import org.opendaylight.controller.sal.core.NodeConnector;
31 import org.opendaylight.controller.sal.core.Node.NodeIDType;
32 import org.opendaylight.controller.sal.flowprogrammer.Flow;
33 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener;
34 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
35 import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
36 import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
37 import org.opendaylight.controller.sal.match.Match;
38 import org.opendaylight.controller.sal.match.MatchType;
39 import org.opendaylight.controller.sal.utils.StatusCode;
40 import org.opendaylight.controller.sal.utils.EtherTypes;
41 import org.opendaylight.controller.sal.utils.IPProtocols;
42 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
43 import org.opendaylight.controller.sal.utils.Status;
44 import org.osgi.framework.BundleContext;
45 import org.osgi.framework.FrameworkUtil;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 /**
50  * The SAL Flow Programmer Service. It dispatches the flow programming requests
51  * to the proper SDN protocol plugin and it notifies about asynchronous messages
52  * received from the network node related to flow programming.
53  */
54 public class FlowProgrammerService implements IFlowProgrammerService,
55         IPluginOutFlowProgrammerService, CommandProvider {
56
57     protected static final Logger logger = LoggerFactory
58             .getLogger(FlowProgrammerService.class);
59     private ConcurrentHashMap<String, IPluginInFlowProgrammerService> pluginFlowProgrammer;
60     private Set<IFlowProgrammerListener> listener;
61
62     public FlowProgrammerService() {
63         pluginFlowProgrammer = new ConcurrentHashMap<String, IPluginInFlowProgrammerService>();
64         listener = new HashSet<IFlowProgrammerListener>();
65     }
66
67     /**
68      * Function called by the dependency manager when all the required
69      * dependencies are satisfied
70      * 
71      */
72     void init() {
73         logger.debug("INIT called!");
74     }
75
76     /**
77      * Function called by the dependency manager when at least one dependency
78      * become unsatisfied or when the component is shutting down because for
79      * example bundle is being stopped.
80      * 
81      */
82     void destroy() {
83         // Clear previous registration to avoid they are left hanging
84         this.pluginFlowProgrammer.clear();
85         logger.debug("DESTROY called!");
86     }
87
88     /**
89      * Function called by dependency manager after "init ()" is called and after
90      * the services provided by the class are registered in the service registry
91      * 
92      */
93     void start() {
94         logger.debug("START called!");
95         // OSGI console
96         registerWithOSGIConsole();
97     }
98
99     /**
100      * Function called by the dependency manager before the services exported by
101      * the component are unregistered, this will be followed by a "destroy ()"
102      * calls
103      * 
104      */
105     void stop() {
106         logger.debug("STOP called!");
107     }
108
109     // Set the reference to the plugin flow programmer
110     public void setService(Map props, IPluginInFlowProgrammerService s) {
111         if (this.pluginFlowProgrammer == null) {
112             logger.error("pluginFlowProgrammer store null");
113             return;
114         }
115
116         logger.trace("Got a service set request {}", s);
117         String type = null;
118         for (Object e : props.entrySet()) {
119             Map.Entry entry = (Map.Entry) e;
120             logger.trace("Prop key:({}) value:({})", entry.getKey(),
121                     entry.getValue());
122         }
123
124         Object value = props.get("protocolPluginType");
125         if (value instanceof String) {
126             type = (String) value;
127         }
128         if (type == null) {
129             logger.error("Received a pluginFlowProgrammer without any "
130                     + "protocolPluginType provided");
131         } else {
132             this.pluginFlowProgrammer.put(type, s);
133             logger.debug("Stored the pluginFlowProgrammer for type: {}", type);
134         }
135     }
136
137     public void unsetService(Map props, IPluginInFlowProgrammerService s) {
138         if (this.pluginFlowProgrammer == null) {
139             logger.error("pluginFlowProgrammer store null");
140             return;
141         }
142
143         String type = null;
144         logger.debug("Received unsetpluginFlowProgrammer request");
145         for (Object e : props.entrySet()) {
146             Map.Entry entry = (Map.Entry) e;
147             logger.trace("Prop key:({}) value:({})", entry.getKey(),
148                     entry.getValue());
149         }
150
151         Object value = props.get("protocoloPluginType");
152         if (value instanceof String) {
153             type = (String) value;
154         }
155         if (type == null) {
156             logger.error("Received a pluginFlowProgrammer without any "
157                     + "protocolPluginType provided");
158         } else if (this.pluginFlowProgrammer.get(type).equals(s)) {
159             this.pluginFlowProgrammer.remove(type);
160             logger.debug("Removed the pluginFlowProgrammer for type: {}", type);
161         }
162     }
163
164     public void setListener(IFlowProgrammerListener s) {
165         this.listener.add(s);
166     }
167
168     public void unsetListener(IFlowProgrammerListener s) {
169         this.listener.remove(s);
170     }
171
172     @Override
173     public Status addFlow(Node node, Flow flow) {
174         if (pluginFlowProgrammer != null) {
175             if (this.pluginFlowProgrammer.get(node.getType()) != null) {
176                 return this.pluginFlowProgrammer.get(node.getType()).addFlow(
177                         node, flow);
178             }
179         }
180         return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
181     }
182
183     @Override
184     public Status removeFlow(Node node, Flow flow) {
185         if (pluginFlowProgrammer != null) {
186             if (this.pluginFlowProgrammer.get(node.getType()) != null) {
187                 return this.pluginFlowProgrammer.get(node.getType())
188                         .removeFlow(node, flow);
189             }
190         }
191         return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
192     }
193
194     @Override
195     public Status removeAllFlows(Node node) {
196         if (pluginFlowProgrammer != null) {
197             if (this.pluginFlowProgrammer.get(node.getType()) != null) {
198                 return this.pluginFlowProgrammer.get(node.getType())
199                         .removeAllFlows(node);
200             }
201         }
202         return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
203     }
204
205     @Override
206     public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) {
207         if (pluginFlowProgrammer != null) {
208             if (this.pluginFlowProgrammer.get(node.getType()) != null) {
209                 return this.pluginFlowProgrammer.get(node.getType())
210                         .modifyFlow(node, oldFlow, newFlow);
211             }
212         }
213         return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
214     }
215
216     @Override
217     public void flowRemoved(Node node, Flow flow) {
218         for (IFlowProgrammerListener l : listener) {
219             l.flowRemoved(node, flow);
220         }
221     }
222
223     // ---------------- OSGI TEST CODE ------------------------------//
224
225     private void registerWithOSGIConsole() {
226         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
227                 .getBundleContext();
228         bundleContext.registerService(CommandProvider.class.getName(), this,
229                 null);
230     }
231
232     @Override
233     public String getHelp() {
234         StringBuffer help = new StringBuffer();
235         help.append("---SAL Flow Programmer testing commands---\n");
236         help.append("\t addflow <sid> - Add a sample flow to the openflow switch <sid>\n");
237         help.append("\t removeflow <sid> - Remove the sample flow from the openflow switch <sid>\n");
238         return help.toString();
239     }
240
241     public void _addflow(CommandInterpreter ci) throws UnknownHostException {
242         Node node = null;
243         String nodeId = ci.nextArgument();
244         if (nodeId == null) {
245             ci.print("Node id not specified");
246             return;
247         }
248         try {
249             node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
250         } catch (NumberFormatException e) {
251             logger.error("",e);
252         } catch (ConstructionException e) {
253             logger.error("",e);
254         }
255         ci.println(this.addFlow(node, getSampleFlow(node)));
256     }
257
258     public void _modifyflow(CommandInterpreter ci) throws UnknownHostException {
259         Node node = null;
260         String nodeId = ci.nextArgument();
261         if (nodeId == null) {
262             ci.print("Node id not specified");
263             return;
264         }
265         try {
266             node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
267         } catch (NumberFormatException e) {
268             logger.error("",e);
269         } catch (ConstructionException e) {
270             logger.error("",e);
271         }
272         Flow flowA = getSampleFlow(node);
273         Flow flowB = getSampleFlow(node);
274         Match matchB = flowB.getMatch();
275         matchB.setField(MatchType.NW_DST,
276                 InetAddress.getByName("190.190.190.190"));
277         flowB.setMatch(matchB);
278         ci.println(this.modifyFlow(node, flowA, flowB));
279     }
280
281     public void _removeflow(CommandInterpreter ci) throws UnknownHostException {
282         Node node = null;
283         String nodeId = ci.nextArgument();
284         if (nodeId == null) {
285             ci.print("Node id not specified");
286             return;
287         }
288         try {
289             node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
290         } catch (NumberFormatException e) {
291             logger.error("",e);
292         } catch (ConstructionException e) {
293             logger.error("",e);
294         }
295         ci.println(this.removeFlow(node, getSampleFlow(node)));
296     }
297
298     public void _addflowv6(CommandInterpreter ci) throws UnknownHostException {
299         Node node = null;
300         String nodeId = ci.nextArgument();
301         if (nodeId == null) {
302             ci.print("Node id not specified");
303             return;
304         }
305         try {
306             node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
307         } catch (NumberFormatException e) {
308             logger.error("",e);
309         } catch (ConstructionException e) {
310             logger.error("",e);
311         }
312         ci.println(this.addFlow(node, getSampleFlowV6(node)));
313     }
314
315     public void _removeflowv6(CommandInterpreter ci)
316             throws UnknownHostException {
317         Node node = null;
318         String nodeId = ci.nextArgument();
319         if (nodeId == null) {
320             ci.print("Node id not specified");
321             return;
322         }
323         try {
324             node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
325         } catch (NumberFormatException e) {
326             logger.error("",e);
327         } catch (ConstructionException e) {
328             logger.error("",e);
329         }
330         ci.println(this.removeFlow(node, getSampleFlowV6(node)));
331     }
332
333     private Flow getSampleFlow(Node node) throws UnknownHostException {
334         NodeConnector port = NodeConnectorCreator.createOFNodeConnector(
335                 (short) 24, node);
336         NodeConnector oport = NodeConnectorCreator.createOFNodeConnector(
337                 (short) 30, node);
338         byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78,
339                 (byte) 0x9a, (byte) 0xbc };
340         byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d,
341                 (byte) 0x5e, (byte) 0x6f };
342         InetAddress srcIP = InetAddress.getByName("172.28.30.50");
343         InetAddress dstIP = InetAddress.getByName("171.71.9.52");
344         InetAddress newIP = InetAddress.getByName("200.200.100.1");
345         InetAddress ipMask = InetAddress.getByName("255.255.255.0");
346         InetAddress ipMask2 = InetAddress.getByName("255.240.0.0");
347         short ethertype = EtherTypes.IPv4.shortValue();
348         short vlan = (short) 27;
349         byte vlanPr = 3;
350         Byte tos = 4;
351         byte proto = IPProtocols.TCP.byteValue();
352         short src = (short) 55000;
353         short dst = 80;
354
355         /*
356          * Create a SAL Flow aFlow
357          */
358         Match match = new Match();
359         match.setField(MatchType.IN_PORT, port);
360         match.setField(MatchType.DL_SRC, srcMac);
361         match.setField(MatchType.DL_DST, dstMac);
362         match.setField(MatchType.DL_TYPE, ethertype);
363         match.setField(MatchType.DL_VLAN, vlan);
364         match.setField(MatchType.DL_VLAN_PR, vlanPr);
365         match.setField(MatchType.NW_SRC, srcIP, ipMask);
366         match.setField(MatchType.NW_DST, dstIP, ipMask2);
367         match.setField(MatchType.NW_TOS, tos);
368         match.setField(MatchType.NW_PROTO, proto);
369         match.setField(MatchType.TP_SRC, src);
370         match.setField(MatchType.TP_DST, dst);
371
372         List<Action> actions = new ArrayList<Action>();
373         actions.add(new SetNwDst(newIP));
374         actions.add(new Output(oport));
375         actions.add(new PopVlan());
376         actions.add(new Flood());
377         actions.add(new Controller());
378
379         Flow flow = new Flow(match, actions);
380         flow.setPriority((short) 100);
381         flow.setHardTimeout((short) 360);
382
383         return flow;
384     }
385
386     private Flow getSampleFlowV6(Node node) throws UnknownHostException {
387         NodeConnector port = NodeConnectorCreator.createOFNodeConnector(
388                 (short) 24, node);
389         NodeConnector oport = NodeConnectorCreator.createOFNodeConnector(
390                 (short) 30, node);
391         byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78,
392                 (byte) 0x9a, (byte) 0xbc };
393         byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d,
394                 (byte) 0x5e, (byte) 0x6f };
395         InetAddress srcIP = InetAddress
396                 .getByName("2001:420:281:1004:407a:57f4:4d15:c355");
397         InetAddress dstIP = InetAddress
398                 .getByName("2001:420:281:1004:e123:e688:d655:a1b0");
399         InetAddress ipMask = null; // InetAddress.getByName("ffff:ffff:ffff:ffff:0:0:0:0");
400                                    // V6Match implementation assumes no mask is
401                                    // specified
402         InetAddress ipMask2 = null; // InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0");
403         short ethertype = EtherTypes.IPv6.shortValue();
404         short vlan = (short) 27;
405         byte vlanPr = (byte) 3;
406         Byte tos = 4;
407         byte proto = IPProtocols.UDP.byteValue();
408         short src = (short) 5500;
409         // short dst = 80;
410
411         /*
412          * Create a SAL Flow aFlow
413          */
414         Match match = new Match();
415         match.setField(MatchType.IN_PORT, port);
416         match.setField(MatchType.DL_SRC, srcMac);
417         match.setField(MatchType.DL_DST, dstMac);
418         match.setField(MatchType.DL_TYPE, ethertype);
419         match.setField(MatchType.DL_VLAN, vlan);
420         match.setField(MatchType.DL_VLAN_PR, vlanPr); // V6Match does not handle
421                                                       // this properly...
422         match.setField(MatchType.NW_SRC, srcIP, ipMask);
423         match.setField(MatchType.NW_DST, dstIP, ipMask2);
424         match.setField(MatchType.NW_TOS, tos);
425         match.setField(MatchType.NW_PROTO, proto);
426         match.setField(MatchType.TP_SRC, src); // V6Match does not handle this
427                                                // properly...
428         // match.setField(MatchType.TP_DST, dst); V6Match does not handle this
429         // properly...
430
431         List<Action> actions = new ArrayList<Action>();
432         actions.add(new Output(oport));
433         actions.add(new PopVlan());
434         actions.add(new Flood());
435
436         Flow flow = new Flow(match, actions);
437         flow.setPriority((short) 300);
438         flow.setHardTimeout((short) 240);
439
440         return flow;
441     }
442
443 }