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.protocol_plugin.openflow.internal;
11 import java.nio.ByteBuffer;
12 import java.util.ArrayList;
13 import java.util.HashSet;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
19 import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier;
20 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
21 import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
22 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
23 import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Error;
24 import org.openflow.protocol.OFError;
25 import org.openflow.protocol.OFFlowMod;
26 import org.openflow.protocol.OFFlowRemoved;
27 import org.openflow.protocol.OFMessage;
28 import org.openflow.protocol.OFPort;
29 import org.openflow.protocol.OFType;
30 import org.openflow.protocol.action.OFAction;
32 import org.opendaylight.controller.sal.core.ContainerFlow;
33 import org.opendaylight.controller.sal.core.IContainerListener;
34 import org.opendaylight.controller.sal.core.Node;
35 import org.opendaylight.controller.sal.core.Node.NodeIDType;
36 import org.opendaylight.controller.sal.core.NodeConnector;
37 import org.opendaylight.controller.sal.core.UpdateType;
38 import org.opendaylight.controller.sal.flowprogrammer.Flow;
39 import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
40 import org.opendaylight.controller.sal.match.Match;
41 import org.opendaylight.controller.sal.match.MatchType;
42 import org.opendaylight.controller.sal.utils.GlobalConstants;
43 import org.opendaylight.controller.sal.utils.NodeCreator;
44 import org.opendaylight.controller.sal.utils.StatusCode;
45 import org.opendaylight.controller.sal.utils.Status;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 * Represents the openflow plugin component in charge of programming the flows
51 * the flow programming and relay them to functional modules above SAL.
53 public class FlowProgrammerService implements IPluginInFlowProgrammerService,
54 IMessageListener, IContainerListener {
55 private static final Logger log = LoggerFactory
56 .getLogger(FlowProgrammerService.class);
57 private IController controller;
58 private ConcurrentMap<String, IFlowProgrammerNotifier> flowProgrammerNotifiers;
59 private Map<String, Set<NodeConnector>> containerToNc;
61 public FlowProgrammerService() {
63 flowProgrammerNotifiers = new ConcurrentHashMap<String, IFlowProgrammerNotifier>();
66 public void setController(IController core) {
67 this.controller = core;
70 public void unsetController(IController core) {
71 if (this.controller == core) {
72 this.controller = null;
76 public void setFlowProgrammerNotifier(Map<String, ?> props,
77 IFlowProgrammerNotifier s) {
78 if (props == null || props.get("containerName") == null) {
79 log.error("Didn't receive the service correct properties");
82 String containerName = (String) props.get("containerName");
83 this.flowProgrammerNotifiers.put(containerName, s);
86 public void unsetFlowProgrammerNotifier(Map<String, ?> props,
87 IFlowProgrammerNotifier s) {
88 if (props == null || props.get("containerName") == null) {
89 log.error("Didn't receive the service correct properties");
92 String containerName = (String) props.get("containerName");
93 if (this.flowProgrammerNotifiers != null
94 && this.flowProgrammerNotifiers.containsKey(containerName)
95 && this.flowProgrammerNotifiers.get(containerName) == s) {
96 this.flowProgrammerNotifiers.remove(containerName);
101 * Function called by the dependency manager when all the required
102 * dependencies are satisfied
106 this.controller.addMessageListener(OFType.FLOW_REMOVED, this);
110 * Function called by the dependency manager when at least one dependency
111 * become unsatisfied or when the component is shutting down because for
112 * example bundle is being stopped.
119 * Function called by dependency manager after "init ()" is called and after
120 * the services provided by the class are registered in the service registry
127 * Function called by the dependency manager before the services exported by
128 * the component are unregistered, this will be followed by a "destroy ()"
136 public Status addFlow(Node node, Flow flow) {
137 String action = "add";
138 if (!node.getType().equals(NodeIDType.OPENFLOW)) {
139 return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
140 action, "Invalid node type"));
143 if (controller != null) {
144 ISwitch sw = controller.getSwitch((Long) node.getID());
146 FlowConverter x = new FlowConverter(flow);
147 OFMessage msg = x.getOFFlowMod(OFFlowMod.OFPFC_ADD, null);
150 * Synchronous message send
152 Object result = sw.syncSend(msg);
153 if (result instanceof Boolean) {
154 return ((Boolean) result == Boolean.TRUE) ? new Status(
155 StatusCode.SUCCESS, null) : new Status(
156 StatusCode.TIMEOUT, errorString(null, action,
157 "Request Timed Out"));
158 } else if (result instanceof OFError) {
159 OFError res = (OFError) result;
160 if (res.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) {
161 V6Error er = new V6Error(res);
162 byte[] b = res.getError();
163 ByteBuffer bb = ByteBuffer.allocate(b.length);
167 return new Status(StatusCode.INTERNALERROR,
168 errorString("program", action,
169 "Vendor Extension Internal Error"));
171 return new Status(StatusCode.INTERNALERROR, errorString(
172 "program", action, Utils.getOFErrorString(res)));
174 return new Status(StatusCode.INTERNALERROR, errorString(
175 "send", action, "Internal Error"));
178 return new Status(StatusCode.GONE, errorString("send", action,
179 "Switch is not available"));
182 return new Status(StatusCode.INTERNALERROR, errorString("send", action,
183 "Internal plugin error"));
187 public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) {
188 String action = "modify";
189 if (!node.getType().equals(NodeIDType.OPENFLOW)) {
190 return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
191 action, "Invalid node type"));
193 if (controller != null) {
194 ISwitch sw = controller.getSwitch((Long) node.getID());
196 OFMessage msg1 = null, msg2 = null;
198 // If priority and match portion are the same, send a
199 // modification message
200 if (oldFlow.getPriority() != newFlow.getPriority()
201 || !oldFlow.getMatch().equals(newFlow.getMatch())) {
202 msg1 = new FlowConverter(oldFlow).getOFFlowMod(
203 OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
204 msg2 = new FlowConverter(newFlow).getOFFlowMod(
205 OFFlowMod.OFPFC_ADD, null);
207 msg1 = new FlowConverter(newFlow).getOFFlowMod(
208 OFFlowMod.OFPFC_MODIFY_STRICT, null);
211 * Synchronous message send
213 action = (msg2 == null) ? "modify" : "delete";
214 Object result = sw.syncSend(msg1);
215 if (result instanceof Boolean) {
216 if ((Boolean) result == Boolean.FALSE) {
217 return new Status(StatusCode.TIMEOUT, errorString(null,
218 action, "Request Timed Out"));
219 } else if (msg2 == null) {
220 return new Status(StatusCode.SUCCESS, null);
222 } else if (result instanceof OFError) {
223 return new Status(StatusCode.INTERNALERROR, errorString(
225 Utils.getOFErrorString((OFError) result)));
227 return new Status(StatusCode.INTERNALERROR, errorString(
228 "send", action, "Internal Error"));
233 result = sw.syncSend(msg2);
234 if (result instanceof Boolean) {
235 return ((Boolean) result == Boolean.TRUE) ? new Status(
236 StatusCode.SUCCESS, null) : new Status(
237 StatusCode.TIMEOUT, errorString(null, action,
238 "Request Timed Out"));
239 } else if (result instanceof OFError) {
240 return new Status(StatusCode.INTERNALERROR,
241 errorString("program", action, Utils
242 .getOFErrorString((OFError) result)));
244 return new Status(StatusCode.INTERNALERROR,
245 errorString("send", action, "Internal Error"));
249 return new Status(StatusCode.GONE, errorString("send", action,
250 "Switch is not available"));
253 return new Status(StatusCode.INTERNALERROR, errorString("send", action,
254 "Internal plugin error"));
258 public Status removeFlow(Node node, Flow flow) {
259 String action = "remove";
260 if (!node.getType().equals(NodeIDType.OPENFLOW)) {
261 return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
262 action, "Invalid node type"));
264 if (controller != null) {
265 ISwitch sw = controller.getSwitch((Long) node.getID());
267 OFMessage msg = new FlowConverter(flow).getOFFlowMod(
268 OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
269 Object result = sw.syncSend(msg);
270 if (result instanceof Boolean) {
271 return ((Boolean) result == Boolean.TRUE) ? new Status(
272 StatusCode.SUCCESS, null) : new Status(
273 StatusCode.TIMEOUT, errorString(null, action,
274 "Request Timed Out"));
275 } else if (result instanceof OFError) {
276 return new Status(StatusCode.INTERNALERROR, errorString(
278 Utils.getOFErrorString((OFError) result)));
280 return new Status(StatusCode.INTERNALERROR, errorString(
281 "send", action, "Internal Error"));
284 return new Status(StatusCode.GONE, errorString("send", action,
285 "Switch is not available"));
288 return new Status(StatusCode.INTERNALERROR, errorString("send", action,
289 "Internal plugin error"));
293 public Status removeAllFlows(Node node) {
294 return new Status(StatusCode.SUCCESS, null);
297 private String errorString(String phase, String action, String cause) {
299 + ((phase != null) ? phase + " the " + action
300 + " flow message: " : action + " the flow: ") + cause;
304 public void receive(ISwitch sw, OFMessage msg) {
305 if (msg instanceof OFFlowRemoved) {
306 handleFlowRemovedMessage(sw, (OFFlowRemoved) msg);
310 private void handleFlowRemovedMessage(ISwitch sw, OFFlowRemoved msg) {
311 Node node = NodeCreator.createOFNode(sw.getId());
312 Flow flow = new FlowConverter(msg.getMatch(),
313 new ArrayList<OFAction>(0)).getFlow(node);
314 flow.setPriority(msg.getPriority());
315 flow.setIdleTimeout(msg.getIdleTimeout());
316 flow.setId(msg.getCookie());
318 Match match = flow.getMatch();
319 NodeConnector inPort = match.isPresent(MatchType.IN_PORT) ? (NodeConnector) match
320 .getField(MatchType.IN_PORT).getValue() : null;
322 for (Map.Entry<String, IFlowProgrammerNotifier> containerNotifier : flowProgrammerNotifiers
324 String container = containerNotifier.getKey();
325 IFlowProgrammerNotifier notifier = containerNotifier.getValue();
327 * Switch only provide us with the match information. For now let's
328 * try to identify the container membership only from the input port
329 * match field. In any case, upper layer consumers can derive
330 * whether the notification was not for them. More sophisticated
331 * filtering can be added later on.
334 || container.equals(GlobalConstants.DEFAULT.toString())
335 || this.containerToNc.get(container).contains(inPort)) {
336 notifier.flowRemoved(node, flow);
342 public void tagUpdated(String containerName, Node n, short oldTag,
343 short newTag, UpdateType t) {
348 public void containerFlowUpdated(String containerName,
349 ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
353 public void nodeConnectorUpdated(String containerName, NodeConnector p,
355 Set<NodeConnector> target = null;
359 if (!containerToNc.containsKey(containerName)) {
360 containerToNc.put(containerName, new HashSet<NodeConnector>());
362 containerToNc.get(containerName).add(p);
367 target = containerToNc.get(containerName);
368 if (target != null) {
378 public void containerModeUpdated(UpdateType t) {