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