2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.controller.sal.implementation.internal;
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;
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;
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.
54 public class FlowProgrammerService implements IFlowProgrammerService,
55 IPluginOutFlowProgrammerService, CommandProvider {
57 protected static final Logger logger = LoggerFactory
58 .getLogger(FlowProgrammerService.class);
59 private ConcurrentHashMap<String, IPluginInFlowProgrammerService> pluginFlowProgrammer;
60 private Set<IFlowProgrammerListener> listener;
62 public FlowProgrammerService() {
63 pluginFlowProgrammer = new ConcurrentHashMap<String, IPluginInFlowProgrammerService>();
64 listener = new HashSet<IFlowProgrammerListener>();
68 * Function called by the dependency manager when all the required
69 * dependencies are satisfied
73 logger.debug("INIT called!");
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.
83 // Clear previous registration to avoid they are left hanging
84 this.pluginFlowProgrammer.clear();
85 logger.debug("DESTROY called!");
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
94 logger.debug("START called!");
96 registerWithOSGIConsole();
100 * Function called by the dependency manager before the services exported by
101 * the component are unregistered, this will be followed by a "destroy ()"
106 logger.debug("STOP called!");
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");
116 logger.trace("Got a service set request {}", s);
118 for (Object e : props.entrySet()) {
119 Map.Entry entry = (Map.Entry) e;
120 logger.trace("Prop key:({}) value:({})", entry.getKey(),
124 Object value = props.get("protocolPluginType");
125 if (value instanceof String) {
126 type = (String) value;
129 logger.error("Received a pluginFlowProgrammer without any "
130 + "protocolPluginType provided");
132 this.pluginFlowProgrammer.put(type, s);
133 logger.debug("Stored the pluginFlowProgrammer for type: {}", type);
137 public void unsetService(Map props, IPluginInFlowProgrammerService s) {
138 if (this.pluginFlowProgrammer == null) {
139 logger.error("pluginFlowProgrammer store 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(),
151 Object value = props.get("protocoloPluginType");
152 if (value instanceof String) {
153 type = (String) value;
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);
164 public void setListener(IFlowProgrammerListener s) {
165 this.listener.add(s);
168 public void unsetListener(IFlowProgrammerListener s) {
169 this.listener.remove(s);
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(
180 return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
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);
191 return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
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);
202 return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
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);
213 return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
217 public void flowRemoved(Node node, Flow flow) {
218 for (IFlowProgrammerListener l : listener) {
219 l.flowRemoved(node, flow);
223 // ---------------- OSGI TEST CODE ------------------------------//
225 private void registerWithOSGIConsole() {
226 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
228 bundleContext.registerService(CommandProvider.class.getName(), this,
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();
241 public void _addflow(CommandInterpreter ci) throws UnknownHostException {
243 String nodeId = ci.nextArgument();
244 if (nodeId == null) {
245 ci.print("Node id not specified");
249 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
250 } catch (NumberFormatException e) {
252 } catch (ConstructionException e) {
255 ci.println(this.addFlow(node, getSampleFlow(node)));
258 public void _modifyflow(CommandInterpreter ci) throws UnknownHostException {
260 String nodeId = ci.nextArgument();
261 if (nodeId == null) {
262 ci.print("Node id not specified");
266 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
267 } catch (NumberFormatException e) {
269 } catch (ConstructionException e) {
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));
281 public void _removeflow(CommandInterpreter ci) throws UnknownHostException {
283 String nodeId = ci.nextArgument();
284 if (nodeId == null) {
285 ci.print("Node id not specified");
289 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
290 } catch (NumberFormatException e) {
292 } catch (ConstructionException e) {
295 ci.println(this.removeFlow(node, getSampleFlow(node)));
298 public void _addflowv6(CommandInterpreter ci) throws UnknownHostException {
300 String nodeId = ci.nextArgument();
301 if (nodeId == null) {
302 ci.print("Node id not specified");
306 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
307 } catch (NumberFormatException e) {
309 } catch (ConstructionException e) {
312 ci.println(this.addFlow(node, getSampleFlowV6(node)));
315 public void _removeflowv6(CommandInterpreter ci)
316 throws UnknownHostException {
318 String nodeId = ci.nextArgument();
319 if (nodeId == null) {
320 ci.print("Node id not specified");
324 node = new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeId));
325 } catch (NumberFormatException e) {
327 } catch (ConstructionException e) {
330 ci.println(this.removeFlow(node, getSampleFlowV6(node)));
333 private Flow getSampleFlow(Node node) throws UnknownHostException {
334 NodeConnector port = NodeConnectorCreator.createOFNodeConnector(
336 NodeConnector oport = NodeConnectorCreator.createOFNodeConnector(
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;
351 byte proto = IPProtocols.TCP.byteValue();
352 short src = (short) 55000;
356 * Create a SAL Flow aFlow
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);
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());
379 Flow flow = new Flow(match, actions);
380 flow.setPriority((short) 100);
381 flow.setHardTimeout((short) 360);
386 private Flow getSampleFlowV6(Node node) throws UnknownHostException {
387 NodeConnector port = NodeConnectorCreator.createOFNodeConnector(
389 NodeConnector oport = NodeConnectorCreator.createOFNodeConnector(
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
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;
407 byte proto = IPProtocols.UDP.byteValue();
408 short src = (short) 5500;
412 * Create a SAL Flow aFlow
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
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
428 // match.setField(MatchType.TP_DST, dst); V6Match does not handle this
431 List<Action> actions = new ArrayList<Action>();
432 actions.add(new Output(oport));
433 actions.add(new PopVlan());
434 actions.add(new Flood());
436 Flow flow = new Flow(match, actions);
437 flow.setPriority((short) 300);
438 flow.setHardTimeout((short) 240);