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