983c7c2190e09d19298f7454a093615956f91299
[controller.git] / opendaylight / protocol_plugins / openflow / src / main / java / org / opendaylight / controller / protocol_plugin / openflow / 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.protocol_plugin.openflow.internal;
11
12 import java.nio.ByteBuffer;
13 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
14 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
15 import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Error;
16 import org.openflow.protocol.OFError;
17 import org.openflow.protocol.OFFlowMod;
18 import org.openflow.protocol.OFMessage;
19 import org.openflow.protocol.OFPort;
20
21 import org.opendaylight.controller.sal.core.Node;
22 import org.opendaylight.controller.sal.core.Node.NodeIDType;
23 import org.opendaylight.controller.sal.flowprogrammer.Flow;
24 import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
25 import org.opendaylight.controller.sal.utils.StatusCode;
26 import org.opendaylight.controller.sal.utils.Status;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * Represents the openflow plugin component in charge of programming the flows
32  * on the switch. It servers the install requests coming from the SAL layer.
33  *
34  *
35  *
36  */
37 public class FlowProgrammerService implements IPluginInFlowProgrammerService {
38         private static final Logger log = LoggerFactory
39     .getLogger(FlowProgrammerService.class);
40     private IController controller;
41
42     public FlowProgrammerService() {
43         controller = null;
44     }
45
46     public void setController(IController core) {
47         this.controller = core;
48     }
49
50     public void unsetController(IController core) {
51         if (this.controller == core) {
52             this.controller = null;
53         }
54     }
55
56     /**
57      * Function called by the dependency manager when all the required
58      * dependencies are satisfied
59      *
60      */
61     void init() {
62     }
63
64     /**
65      * Function called by the dependency manager when at least one
66      * dependency become unsatisfied or when the component is shutting
67      * down because for example bundle is being stopped.
68      *
69      */
70     void destroy() {
71     }
72
73     /**
74      * Function called by dependency manager after "init ()" is called
75      * and after the services provided by the class are registered in
76      * the service registry
77      *
78      */
79     void start() {
80     }
81
82     /**
83      * Function called by the dependency manager before the services
84      * exported by the component are unregistered, this will be
85      * followed by a "destroy ()" calls
86      *
87      */
88     void stop() {
89     }
90
91     @Override
92     public Status addFlow(Node node, Flow flow) {
93         String action = "add";
94         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
95             return new Status(StatusCode.NOTACCEPTABLE,
96                     errorString("send", action, "Invalid node type"));
97         }
98
99         if (controller != null) {
100             ISwitch sw = controller.getSwitch((Long) node.getID());
101             if (sw != null) {
102                 FlowConverter x = new FlowConverter(flow);
103                 OFMessage msg = x.getOFFlowMod(OFFlowMod.OFPFC_ADD, null);
104
105                 /*
106                  * Synchronous message send
107                  */
108                 Object result = sw.syncSend(msg);
109                 if (result instanceof Boolean) {
110                     return ((Boolean) result == Boolean.TRUE) ?
111                             new Status(StatusCode.SUCCESS, null)
112                             : new Status(StatusCode.TIMEOUT,
113                                     errorString(null, action,
114                                             "Request Timed Out"));
115                 } else if (result instanceof OFError) {
116                         OFError res = (OFError) result;
117                         if (res.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) {
118                                 V6Error er = new V6Error(res);
119                                 byte[] b = res.getError();
120                                 ByteBuffer bb = ByteBuffer.allocate(b.length);
121                                 bb.put(b);
122                                 bb.rewind();
123                                 er.readFrom(bb);
124                                 log.trace("V6Error {}",er);
125                                 return new Status(StatusCode.INTERNALERROR,
126                                 errorString("program", action, "Vendor Extension Internal Error"));
127                         }
128                     return new Status(StatusCode.INTERNALERROR,
129                             errorString("program", action, Utils
130                             .getOFErrorString(res)));
131                 } else {
132                     return new Status(StatusCode.INTERNALERROR,
133                             errorString("send", action, "Internal Error"));
134                 }
135             } else {
136                 return new Status(StatusCode.GONE, errorString("send", action,
137                                 "Switch is not available"));
138             }
139         }
140         return new Status(StatusCode.INTERNALERROR,
141                 errorString("send", action, "Internal plugin error"));
142     }
143
144     @Override
145     public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) {
146         String action = "modify";
147         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
148             return new Status(StatusCode.NOTACCEPTABLE,
149                     errorString("send", action, "Invalid node type"));
150         }
151         if (controller != null) {
152             ISwitch sw = controller.getSwitch((Long) node.getID());
153             if (sw != null) {
154                 OFMessage msg1 = null, msg2 = null;
155
156                 // If priority and match portion are the same, send a modification message
157                 if (oldFlow.getPriority() != newFlow.getPriority()
158                         || !oldFlow.getMatch().equals(newFlow.getMatch())) {
159                     msg1 = new FlowConverter(oldFlow).getOFFlowMod(
160                             OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
161                     msg2 = new FlowConverter(newFlow).getOFFlowMod(
162                             OFFlowMod.OFPFC_ADD, null);
163                 } else {
164                     msg1 = new FlowConverter(newFlow).getOFFlowMod(
165                             OFFlowMod.OFPFC_MODIFY_STRICT, null);
166                 }
167                 /*
168                  * Synchronous message send
169                  */
170                 action = (msg2 == null) ? "modify" : "delete";
171                 Object result = sw.syncSend(msg1);
172                 if (result instanceof Boolean) {
173                     if ((Boolean) result == Boolean.FALSE) {
174                         return new Status(StatusCode.TIMEOUT,
175                                 errorString(null, action,
176                                         "Request Timed Out"));
177                     } else if (msg2 == null) {
178                         return new Status(StatusCode.SUCCESS, null);
179                     }
180                 } else if (result instanceof OFError) {
181                     return new Status(StatusCode.INTERNALERROR,
182                             errorString("program", action, Utils
183                             .getOFErrorString((OFError) result)));
184                 } else {
185                     return new Status(StatusCode.INTERNALERROR,
186                             errorString("send", action, "Internal Error"));
187                 }
188
189                 if (msg2 != null) {
190                     action = "add";
191                     result = sw.syncSend(msg2);
192                     if (result instanceof Boolean) {
193                         return ((Boolean) result == Boolean.TRUE) ?
194                                 new Status(StatusCode.SUCCESS, null)
195                                 : new Status(StatusCode.TIMEOUT,
196                                         errorString(null, action,
197                                                 "Request Timed Out"));
198                     } else if (result instanceof OFError) {
199                         return new Status(StatusCode.INTERNALERROR,
200                                 errorString("program", action, Utils
201                                 .getOFErrorString((OFError) result)));
202                     } else {
203                         return new Status(StatusCode.INTERNALERROR,
204                                 errorString("send", action, "Internal Error"));
205                     }
206                 }
207             } else {
208                 return new Status(StatusCode.GONE, errorString("send", action,
209                         "Switch is not available"));
210             }
211         }
212         return new Status(StatusCode.INTERNALERROR,
213                 errorString("send", action, "Internal plugin error"));
214     }
215
216     @Override
217     public Status removeFlow(Node node, Flow flow) {
218         String action = "remove";
219         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
220             return new Status(StatusCode.NOTACCEPTABLE,
221                     errorString("send", action, "Invalid node type"));
222         }
223         if (controller != null) {
224             ISwitch sw = controller.getSwitch((Long) node.getID());
225             if (sw != null) {
226                 OFMessage msg = new FlowConverter(flow).getOFFlowMod(
227                         OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
228                 Object result = sw.syncSend(msg);
229                 if (result instanceof Boolean) {
230                     return ((Boolean) result == Boolean.TRUE) ?
231                             new Status(StatusCode.SUCCESS, null)
232                             : new Status(StatusCode.TIMEOUT,
233                                     errorString(null, action,
234                                             "Request Timed Out"));
235                 } else if (result instanceof OFError) {
236                     return new Status(StatusCode.INTERNALERROR,
237                             errorString("program", action, Utils
238                             .getOFErrorString((OFError) result)));
239                 } else {
240                     return new Status(StatusCode.INTERNALERROR,
241                             errorString("send", action, "Internal Error"));
242                 }
243             } else {
244                 return new Status(StatusCode.GONE,  errorString("send", action,
245                         "Switch is not available"));
246             }
247         }
248         return new Status(StatusCode.INTERNALERROR,
249                 errorString("send", action, "Internal plugin error"));
250     }
251
252     @Override
253     public Status removeAllFlows(Node node) {
254         return new Status(StatusCode.SUCCESS, null);
255     }
256
257     private String errorString(String phase, String action, String cause) {
258         return "Failed to "
259                 + ((phase != null) ? phase + " the " + action
260                         + " flow message: " : action + " the flow: ") + cause;
261     }
262
263 }