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