3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
10 package org.opendaylight.controller.sal.implementation.internal;
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;
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;
47 * The SAL Flow Programmer Service. It dispatches the flow programming
48 * requests to the proper SDN protocol plugin
53 public class FlowProgrammerService implements IFlowProgrammerService,
56 protected static final Logger logger = LoggerFactory
57 .getLogger(FlowProgrammerService.class);
58 private ConcurrentHashMap<String, IPluginInFlowProgrammerService>
59 pluginFlowProgrammer =
60 new ConcurrentHashMap<String, IPluginInFlowProgrammerService>();
63 * Function called by the dependency manager when all the required
64 * dependencies are satisfied
68 logger.debug("INIT called!");
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.
78 // Clear previous registration to avoid they are left hanging
79 this.pluginFlowProgrammer.clear();
80 logger.debug("DESTROY called!");
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
90 logger.debug("START called!");
92 registerWithOSGIConsole();
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
102 logger.debug("STOP called!");
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");
112 logger.trace("Got a service set request {}", s);
114 for (Object e : props.entrySet()) {
115 Map.Entry entry = (Map.Entry) e;
116 logger.trace("Prop key:(" + entry.getKey() + ") value:("
117 + entry.getValue() + ")");
120 Object value = props.get("protocolPluginType");
121 if (value instanceof String) {
122 type = (String) value;
125 logger.error("Received a pluginFlowProgrammer without any "
126 + "protocolPluginType provided");
128 this.pluginFlowProgrammer.put(type, s);
129 logger.debug("Stored the pluginFlowProgrammer for type:" + type);
133 public void unsetService(Map props,
134 IPluginInFlowProgrammerService s) {
135 if (this.pluginFlowProgrammer == null) {
136 logger.error("pluginFlowProgrammer store 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() + ")");
148 Object value = props.get("protocoloPluginType");
149 if (value instanceof String) {
150 type = (String) value;
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);
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);
169 return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
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);
180 return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
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);
191 return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
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);
202 return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
205 // ---------------- OSGI TEST CODE ------------------------------//
207 private void registerWithOSGIConsole() {
208 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
210 bundleContext.registerService(CommandProvider.class.getName(), this,
215 public String getHelp() {
216 StringBuffer help = new StringBuffer();
217 help.append("---SAL Flow Programmer testing commands---\n");
219 .append("\t addflow <sid> - Add a sample flow to the openflow switch <sid>\n");
221 .append("\t removeflow <sid> - Remove the sample flow from the openflow switch <sid>\n");
222 return help.toString();
225 public void _addflow(CommandInterpreter ci) throws UnknownHostException {
227 String nodeId = ci.nextArgument();
228 if (nodeId == null) {
229 ci.print("Node id not specified");
233 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
234 } catch (NumberFormatException e) {
236 } catch (ConstructionException e) {
239 ci.println(this.addFlow(node, getSampleFlow(node)));
242 public void _modifyflow(CommandInterpreter ci) throws UnknownHostException {
244 String nodeId = ci.nextArgument();
245 if (nodeId == null) {
246 ci.print("Node id not specified");
250 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
251 } catch (NumberFormatException e) {
253 } catch (ConstructionException e) {
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));
265 public void _removeflow(CommandInterpreter ci) throws UnknownHostException {
267 String nodeId = ci.nextArgument();
268 if (nodeId == null) {
269 ci.print("Node id not specified");
273 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
274 } catch (NumberFormatException e) {
276 } catch (ConstructionException e) {
279 ci.println(this.removeFlow(node, getSampleFlow(node)));
282 public void _addflowv6(CommandInterpreter ci) throws UnknownHostException {
284 String nodeId = ci.nextArgument();
285 if (nodeId == null) {
286 ci.print("Node id not specified");
290 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
291 } catch (NumberFormatException e) {
293 } catch (ConstructionException e) {
296 ci.println(this.addFlow(node, getSampleFlowV6(node)));
299 public void _removeflowv6(CommandInterpreter ci)
300 throws UnknownHostException {
302 String nodeId = ci.nextArgument();
303 if (nodeId == null) {
304 ci.print("Node id not specified");
308 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
309 } catch (NumberFormatException e) {
311 } catch (ConstructionException e) {
314 ci.println(this.removeFlow(node, getSampleFlowV6(node)));
317 private Flow getSampleFlow(Node node) throws UnknownHostException {
318 NodeConnector port = NodeConnectorCreator.createOFNodeConnector(
320 NodeConnector oport = NodeConnectorCreator.createOFNodeConnector(
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;
335 byte proto = IPProtocols.TCP.byteValue();
336 short src = (short) 55000;
340 * Create a SAL Flow aFlow
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);
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());
363 Flow flow = new Flow(match, actions);
364 flow.setPriority((short) 100);
365 flow.setHardTimeout((short) 360);
370 private Flow getSampleFlowV6(Node node) throws UnknownHostException {
371 NodeConnector port = NodeConnectorCreator.createOFNodeConnector(
373 NodeConnector oport = NodeConnectorCreator.createOFNodeConnector(
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;
389 byte proto = IPProtocols.UDP.byteValue();
390 short src = (short) 5500;
394 * Create a SAL Flow aFlow
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...
410 List<Action> actions = new ArrayList<Action>();
411 actions.add(new Output(oport));
412 actions.add(new PopVlan());
413 actions.add(new Flood());
415 Flow flow = new Flow(match, actions);
416 flow.setPriority((short) 300);
417 flow.setHardTimeout((short) 240);