blob: 2893c1dca67b5fce5cd4f593a021b35cf91a87a8 [file] [log] [blame]
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001package net.floodlightcontroller.flowcache;
2
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08004import java.util.ArrayList;
5import java.util.Collection;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08006import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08007import java.util.HashMap;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07008import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00009import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080011import java.util.Map;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070012import java.util.TreeMap;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070013import java.util.Collections;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070014import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070016import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070019import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080020import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080021
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080022import net.floodlightcontroller.core.IFloodlightProviderService;
23import net.floodlightcontroller.core.INetMapStorage;
24import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
25import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070026import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070027import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070028import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080029import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080030import net.floodlightcontroller.core.module.FloodlightModuleContext;
31import net.floodlightcontroller.core.module.FloodlightModuleException;
32import net.floodlightcontroller.core.module.IFloodlightModule;
33import net.floodlightcontroller.core.module.IFloodlightService;
34import net.floodlightcontroller.flowcache.IFlowService;
35import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
36import net.floodlightcontroller.restserver.IRestApiService;
37import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080038import net.floodlightcontroller.util.DataPath;
39import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080040import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070042import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070044import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080045import net.floodlightcontroller.util.FlowEntrySwitchState;
46import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080047import net.floodlightcontroller.util.FlowId;
48import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070049import net.floodlightcontroller.util.IPv4Net;
50import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080051import net.floodlightcontroller.util.OFMessageDamper;
52import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070053import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070054import net.onrc.onos.flow.IFlowManager;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080055import net.onrc.onos.util.GraphDBConnection;
56import net.onrc.onos.util.GraphDBConnection.Transaction;
57
58import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
60import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070061import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080062import org.openflow.protocol.OFType;
63import org.openflow.protocol.action.OFAction;
64import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080065
66import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070069public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070
71 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080072
73 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080074 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070075 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070076 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080077
78 protected OFMessageDamper messageDamper;
79
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070080 //
81 // TODO: Values copied from elsewhere (class LearningSwitch).
82 // The local copy should go away!
83 //
84 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
85 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
86 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
87 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
88 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080089
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070090 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070091 private static long measurementFlowId = 100000;
92 private static String measurementFlowIdStr = "0x186a0"; // 100000
93 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070094
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080095 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080096 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
97
98 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070099 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800100 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700101 private final ScheduledExecutorService measureMapReaderScheduler =
102 Executors.newScheduledThreadPool(1);
103 private final ScheduledExecutorService mapReaderScheduler =
104 Executors.newScheduledThreadPool(1);
105
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700106 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
107 private ThreadPoolExecutor shortestPathExecutor =
108 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
109
110 class ShortestPathTask implements Runnable {
111 private int hint;
112 private ITopoRouteService topoRouteService;
113 private ArrayList<DataPath> dpList;
114
115 public ShortestPathTask(int hint,
116 ITopoRouteService topoRouteService,
117 ArrayList<DataPath> dpList) {
118 this.hint = hint;
119 this.topoRouteService = topoRouteService;
120 this.dpList = dpList;
121 }
122
123 @Override
124 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700125 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700126 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
127 log.debug(logMsg);
128 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700129 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700130 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700131 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700132 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700133 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700134 long estimatedTime = System.nanoTime() - startTime;
135 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
136 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
137 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700138 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700139 }
140 }
141
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700142 final Runnable measureShortestPath = new Runnable() {
143 public void run() {
144 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
145 if (floodlightProvider == null) {
146 log.debug("FloodlightProvider service not found!");
147 return;
148 }
149
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700150 if (topoRouteService == null) {
151 log.debug("Topology Route Service not found");
152 return;
153 }
154
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700155 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
156 if (leftoverQueueSize > 0) {
157 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
158 log.debug(logMsg);
159 return;
160 }
161 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
162
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700163 //
164 // Recompute the Shortest Paths for all Flows
165 //
166 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700167 int hint = 0;
168 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700169 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700170
171 topoRouteService.prepareShortestPathTopo();
172
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700173 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
174 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700175 FlowId flowId = new FlowId(flowPathObj.getFlowId());
176
177 // log.debug("Found Path {}", flowId.toString());
178 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
179 Port srcPort = new Port(flowPathObj.getSrcPort());
180 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
181 Port dstPort = new Port(flowPathObj.getDstPort());
182 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
183 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700184
185 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700186 DataPath dp = new DataPath();
187 dp.setSrcPort(srcSwitchPort);
188 dp.setDstPort(dstSwitchPort);
189 dpList.add(dp);
190 if ((dpList.size() % 10) == 0) {
191 shortestPathExecutor.execute(
192 new ShortestPathTask(hint, topoRouteService,
193 dpList));
194 dpList = new ArrayList<DataPath>();
195 hint++;
196 }
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700197 */
198
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700199 DataPath dataPath =
200 topoRouteService.getTopoShortestPath(srcSwitchPort,
201 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700202 counter++;
203 }
204 if (dpList.size() > 0) {
205 shortestPathExecutor.execute(
206 new ShortestPathTask(hint, topoRouteService,
207 dpList));
208 }
209
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700210 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700211 // Wait for all tasks to finish
212 try {
213 while (shortestPathExecutor.getQueue().size() > 0) {
214 Thread.sleep(100);
215 }
216 } catch (InterruptedException ex) {
217 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700218 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700219 */
220
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700221 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700222 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700223
224 long estimatedTime = System.nanoTime() - startTime;
225 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
226 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
227 log.debug(logMsg);
228 }
229 };
230
231 final Runnable measureMapReader = new Runnable() {
232 public void run() {
233 if (floodlightProvider == null) {
234 log.debug("FloodlightProvider service not found!");
235 return;
236 }
237
238 //
239 // Fetch all Flow Entries
240 //
241 int counter = 0;
242 long startTime = System.nanoTime();
243 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
244 for (IFlowEntry flowEntryObj : allFlowEntries) {
245 counter++;
246 FlowEntryId flowEntryId =
247 new FlowEntryId(flowEntryObj.getFlowEntryId());
248 String userState = flowEntryObj.getUserState();
249 String switchState = flowEntryObj.getSwitchState();
250 }
251 conn.endTx(Transaction.COMMIT);
252
253 long estimatedTime = System.nanoTime() - startTime;
254 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
255 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
256 log.debug(logMsg);
257 }
258 };
259
260 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800261 public void run() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800262 if (floodlightProvider == null) {
263 log.debug("FloodlightProvider service not found!");
264 return;
265 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000266 Map<Long, IOFSwitch> mySwitches =
267 floodlightProvider.getSwitches();
268 Map<Long, IFlowEntry> myFlowEntries =
269 new TreeMap<Long, IFlowEntry>();
270 LinkedList<IFlowEntry> deleteFlowEntries =
271 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700272
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700273
274 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700275 // Fetch all Flow Entries and select only my Flow Entries
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000276 // that need to be undated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700277 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000278 Iterable<IFlowEntry> allFlowEntries =
279 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700280 for (IFlowEntry flowEntryObj : allFlowEntries) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000281 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700282 String userState = flowEntryObj.getUserState();
283 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000284 String dpidStr = flowEntryObj.getSwitchDpid();
285 if ((flowEntryIdStr == null) ||
286 (userState == null) ||
287 (switchState == null) ||
288 (dpidStr == null)) {
289 log.debug("IGNORING Flow Entry entry with null fields");
290 continue;
291 }
292 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
293 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800294
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000295 /*
296 log.debug("Found Flow Entry Id = {} {}",
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700297 flowEntryId.toString(),
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000298 "DPID = " + dpid.toString() +
299 " User State: " + userState +
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700300 " Switch State: " + switchState);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000301 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800302
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000303 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
304 continue; // Ignore the entry: nothing to do
305
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800306 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000307 if (mySwitch == null)
308 continue; // Ignore the entry: not my switch
309
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700310 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
311 }
312
313 //
314 // Process my Flow Entries
315 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700316 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700317 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
318 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700319 // Code for measurement purpose
320 {
321 IFlowPath flowObj =
322 conn.utils().getFlowPathByFlowEntry(conn,
323 flowEntryObj);
324 if ((flowObj != null) &&
325 flowObj.getFlowId().equals(measurementFlowIdStr)) {
326 processed_measurement_flow = true;
327 }
328 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700329
330 //
331 // TODO: Eliminate the re-fetching of flowEntryId,
332 // userState, switchState, and dpid from the flowEntryObj.
333 //
334 FlowEntryId flowEntryId =
335 new FlowEntryId(flowEntryObj.getFlowEntryId());
336 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
337 String userState = flowEntryObj.getUserState();
338 String switchState = flowEntryObj.getSwitchState();
339 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000340 if (mySwitch == null)
341 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800342
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700343 // TODO: PAVPAVPAV: FROM HERE...
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800344 //
345 // Create the Open Flow Flow Modification Entry to push
346 //
347 OFFlowMod fm =
348 (OFFlowMod) floodlightProvider.getOFMessageFactory()
349 .getMessage(OFType.FLOW_MOD);
350 long cookie = flowEntryId.value();
351
352 short flowModCommand = OFFlowMod.OFPFC_ADD;
353 if (userState.equals("FE_USER_ADD")) {
354 flowModCommand = OFFlowMod.OFPFC_ADD;
355 } else if (userState.equals("FE_USER_MODIFY")) {
356 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
357 } else if (userState.equals("FE_USER_DELETE")) {
358 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
359 } else {
360 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700361 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
362 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800363 continue;
364 }
365
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700366 //
367 // Fetch the match conditions
368 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800369 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700370 match.setWildcards(OFMatch.OFPFW_ALL);
371 Short matchInPort = flowEntryObj.getMatchInPort();
372 if (matchInPort != null) {
373 match.setInputPort(matchInPort);
374 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
375 }
376 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
377 if (matchEthernetFrameType != null) {
378 match.setDataLayerType(matchEthernetFrameType);
379 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
380 }
381 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
382 if (matchSrcIPv4Net != null) {
383 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
384 }
385 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
386 if (matchDstIPv4Net != null) {
387 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
388 }
389 String matchSrcMac = flowEntryObj.getMatchSrcMac();
390 if (matchSrcMac != null) {
391 match.setDataLayerSource(matchSrcMac);
392 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
393 }
394 String matchDstMac = flowEntryObj.getMatchDstMac();
395 if (matchDstMac != null) {
396 match.setDataLayerDestination(matchDstMac);
397 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
398 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700399
400 //
401 // Fetch the actions
402 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800403 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700404 Short actionOutputPort = flowEntryObj.getActionOutput();
405 if (actionOutputPort != null) {
406 OFActionOutput action = new OFActionOutput();
407 // XXX: The max length is hard-coded for now
408 action.setMaxLength((short)0xffff);
409 action.setPort(actionOutputPort);
410 actions.add(action);
411 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800412
413 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
414 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700415 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800416 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
417 .setCookie(cookie)
418 .setCommand(flowModCommand)
419 .setMatch(match)
420 .setActions(actions)
421 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700422 fm.setOutPort(OFPort.OFPP_NONE.getValue());
423 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
424 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
425 if (actionOutputPort != null)
426 fm.setOutPort(actionOutputPort);
427 }
428
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800429 //
430 // TODO: Set the following flag
431 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
432 // See method ForwardingBase::pushRoute()
433 //
434 try {
435 messageDamper.write(mySwitch, fm, null);
436 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000437 //
438 // TODO: We should use the OpenFlow Barrier mechanism
439 // to check for errors, and update the SwitchState
440 // for a flow entry after the Barrier message is
441 // is received.
442 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800443 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
444 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000445 // An entry that needs to be deleted.
446 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800447 }
448 } catch (IOException e) {
449 log.error("Failure writing flow mod from network map", e);
450 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700451 // TODO: XXX: PAVPAVPAV: TO HERE.
452 // TODO: XXX: PAVPAVPAV: Update the flowEntryObj
453 // to "FE_SWITCH_UPDATED" in the new (refactored) code.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800454 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000455
456 //
457 // Delete all entries marked for deletion
458 //
459 // TODO: We should use the OpenFlow Barrier mechanism
460 // to check for errors, and delete the Flow Entries after the
461 // Barrier message is received.
462 //
463 while (! deleteFlowEntries.isEmpty()) {
464 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
465 IFlowPath flowObj =
466 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
467 if (flowObj == null) {
468 log.debug("Did not find FlowPath to be deleted");
469 continue;
470 }
471 flowObj.removeFlowEntry(flowEntryObj);
472 conn.utils().removeFlowEntry(conn, flowEntryObj);
473
474 // Test whether the last flow entry
475 Iterable<IFlowEntry> tmpflowEntries =
476 flowObj.getFlowEntries();
477 boolean found = false;
478 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
479 found = true;
480 break;
481 }
482 if (! found) {
483 // Remove the Flow Path as well
484 conn.utils().removeFlowPath(conn, flowObj);
485 }
486 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700487
488
489 //
490 // Fetch and recompute the Shortest Path for those
491 // Flow Paths this controller is responsible for.
492 //
493
494 /*
495 * TODO: For now, the computation of the reconciliation is
496 * commented-out.
497 */
498 /*
499 topoRouteService.prepareShortestPathTopo();
500 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
501 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
502 for (IFlowPath flowPathObj : allFlowPaths) {
503 if (flowPathObj == null)
504 continue;
505 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
506 if (dataPathSummaryStr == null)
507 continue; // Could be invalid entry?
508 if (dataPathSummaryStr.isEmpty())
509 continue; // No need to maintain this flow
510
511 // Fetch the fields needed to recompute the shortest path
512 String flowIdStr = flowPathObj.getFlowId();
513 String srcDpidStr = flowPathObj.getSrcSwitch();
514 Short srcPortShort = flowPathObj.getSrcPort();
515 String dstDpidStr = flowPathObj.getDstSwitch();
516 Short dstPortShort = flowPathObj.getDstPort();
517 if ((flowIdStr == null) ||
518 (srcDpidStr == null) ||
519 (srcPortShort == null) ||
520 (dstDpidStr == null) ||
521 (dstPortShort == null)) {
522 log.debug("IGNORING Flow Path entry with null fields");
523 continue;
524 }
525
526 FlowId flowId = new FlowId(flowIdStr);
527 Dpid srcDpid = new Dpid(srcDpidStr);
528 Port srcPort = new Port(srcPortShort);
529 Dpid dstDpid = new Dpid(dstDpidStr);
530 Port dstPort = new Port(dstPortShort);
531 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
532 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
533 DataPath dataPath =
534 topoRouteService.getTopoShortestPath(srcSwitchPort,
535 dstSwitchPort);
536 String newDataPathSummaryStr = dataPath.dataPathSummary();
537 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
538 continue; // Nothing changed
539
540 //
541 // Use the source DPID as a heuristic to decide
542 // which controller is responsible for maintaining the
543 // shortest path.
544 // NOTE: This heuristic is error-prone: if the switch
545 // goes away and no controller is responsible for that
546 // switch, then the original Flow Path is not cleaned-up
547 //
548 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
549 if (mySwitch == null)
550 continue; // Ignore: not my responsibility
551
552 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
553 flowId.toString());
554 flowObjSet.add(flowPathObj);
555 }
556 reconcileFlows(flowObjSet);
557 topoRouteService.dropShortestPathTopo();
558 */
559
560
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800561 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700562
563 if (processed_measurement_flow) {
564 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
565 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
566 (double)estimatedTime / 1000000000 + " sec";
567 log.debug(logMsg);
568 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800569 }
570 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700571
572 /*
573 final ScheduledFuture<?> measureShortestPathHandle =
574 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
575 */
576
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700577 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700578 final ScheduledFuture<?> measureMapReaderHandle =
579 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700580 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700581
582 final ScheduledFuture<?> mapReaderHandle =
583 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800584
585 @Override
586 public void init(String conf) {
587 conn = GraphDBConnection.getInstance(conf);
588 }
589
590 public void finalize() {
591 close();
592 }
593
594 @Override
595 public void close() {
596 conn.close();
597 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800598
599 @Override
600 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
601 Collection<Class<? extends IFloodlightService>> l =
602 new ArrayList<Class<? extends IFloodlightService>>();
603 l.add(IFlowService.class);
604 return l;
605 }
606
607 @Override
608 public Map<Class<? extends IFloodlightService>, IFloodlightService>
609 getServiceImpls() {
610 Map<Class<? extends IFloodlightService>,
611 IFloodlightService> m =
612 new HashMap<Class<? extends IFloodlightService>,
613 IFloodlightService>();
614 m.put(IFlowService.class, this);
615 return m;
616 }
617
618 @Override
619 public Collection<Class<? extends IFloodlightService>>
620 getModuleDependencies() {
621 Collection<Class<? extends IFloodlightService>> l =
622 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800623 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700624 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800625 l.add(IRestApiService.class);
626 return l;
627 }
628
629 @Override
630 public void init(FloodlightModuleContext context)
631 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700632 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800633 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700634 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800635 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800636 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
637 EnumSet.of(OFType.FLOW_MOD),
638 OFMESSAGE_DAMPER_TIMEOUT);
639 // TODO: An ugly hack!
640 String conf = "/tmp/cassandra.titan";
641 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800642 }
643
644 @Override
645 public void startUp(FloodlightModuleContext context) {
646 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700647
648 //
649 // Extract all flow entries and assign the next Flow Entry ID
650 // to be larger than the largest Flow Entry ID
651 //
652 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
653 for (IFlowEntry flowEntryObj : allFlowEntries) {
654 FlowEntryId flowEntryId =
655 new FlowEntryId(flowEntryObj.getFlowEntryId());
656 if (flowEntryId.value() >= nextFlowEntryId)
657 nextFlowEntryId = flowEntryId.value() + 1;
658 }
659 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800660 }
661
662 /**
663 * Add a flow.
664 *
665 * Internally, ONOS will automatically register the installer for
666 * receiving Flow Path Notifications for that path.
667 *
668 * @param flowPath the Flow Path to install.
669 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700670 * @param dataPathSummaryStr the data path summary string if the added
671 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800672 * @return true on success, otherwise false.
673 */
674 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700675 public boolean addFlow(FlowPath flowPath, FlowId flowId,
676 String dataPathSummaryStr) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700677 if (flowPath.flowId().value() == measurementFlowId) {
678 modifiedMeasurementFlowTime = System.nanoTime();
679 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800680
681 //
682 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700683 // Right now every new flow entry gets a new flow entry ID
684 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800685 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800686 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700687 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800688 flowEntry.setFlowEntryId(new FlowEntryId(id));
689 }
690
691 IFlowPath flowObj = null;
692 try {
693 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
694 != null) {
695 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
696 flowPath.flowId().toString());
697 } else {
698 flowObj = conn.utils().newFlowPath(conn);
699 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
700 flowPath.flowId().toString());
701 }
702 } catch (Exception e) {
703 // TODO: handle exceptions
704 conn.endTx(Transaction.ROLLBACK);
705 log.error(":addFlow FlowId:{} failed",
706 flowPath.flowId().toString());
707 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700708 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000709 log.error(":addFlow FlowId:{} failed: Flow object not created",
710 flowPath.flowId().toString());
711 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800712 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700713 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800714
715 //
716 // Set the Flow key:
717 // - flowId
718 //
719 flowObj.setFlowId(flowPath.flowId().toString());
720 flowObj.setType("flow");
721
722 //
723 // Set the Flow attributes:
724 // - flowPath.installerId()
725 // - flowPath.dataPath().srcPort()
726 // - flowPath.dataPath().dstPort()
727 //
728 flowObj.setInstallerId(flowPath.installerId().toString());
729 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
730 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
731 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
732 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
733
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700734 if (dataPathSummaryStr != null) {
735 flowObj.setDataPathSummary(dataPathSummaryStr);
736 } else {
737 flowObj.setDataPathSummary("");
738 }
739
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800740 // Flow edges:
741 // HeadFE
742
743
744 //
745 // Flow Entries:
746 // flowPath.dataPath().flowEntries()
747 //
748 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
749 IFlowEntry flowEntryObj = null;
750 boolean found = false;
751 try {
752 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
753 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
754 flowEntry.flowEntryId().toString());
755 found = true;
756 } else {
757 flowEntryObj = conn.utils().newFlowEntry(conn);
758 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
759 flowEntry.flowEntryId().toString());
760 }
761 } catch (Exception e) {
762 // TODO: handle exceptions
763 conn.endTx(Transaction.ROLLBACK);
764 log.error(":addFlow FlowEntryId:{} failed",
765 flowEntry.flowEntryId().toString());
766 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700767 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000768 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
769 flowEntry.flowEntryId().toString());
770 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800771 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700772 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800773
774 //
775 // Set the Flow Entry key:
776 // - flowEntry.flowEntryId()
777 //
778 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
779 flowEntryObj.setType("flow_entry");
780
781 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700782 // Set the Flow Entry Edges and attributes:
783 // - Switch edge
784 // - InPort edge
785 // - OutPort edge
786 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800787 // - flowEntry.flowEntryMatch()
788 // - flowEntry.flowEntryActions()
789 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800790 // - flowEntry.flowEntryUserState()
791 // - flowEntry.flowEntrySwitchState()
792 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700793 // - flowEntry.matchInPort()
794 // - flowEntry.matchEthernetFrameType()
795 // - flowEntry.matchSrcIPv4Net()
796 // - flowEntry.matchDstIPv4Net()
797 // - flowEntry.matchSrcMac()
798 // - flowEntry.matchDstMac()
799 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800800 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700801 ISwitchObject sw =
802 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800803 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700804 flowEntryObj.setSwitch(sw);
805 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700806 IPortObject inport =
807 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
808 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700809 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
810 flowEntryObj.setInPort(inport);
811 }
812 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
813 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
814 }
815 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
816 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
817 }
818 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
819 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
820 }
821 if (flowEntry.flowEntryMatch().matchSrcMac()) {
822 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
823 }
824 if (flowEntry.flowEntryMatch().matchDstMac()) {
825 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
826 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700827
828 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700829 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700830 IPortObject outport =
831 conn.utils().searchPort(conn,
832 flowEntry.dpid().toString(),
833 fa.actionOutput().port().value());
834 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
835 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700836 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700837 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800838 // TODO: Hacks with hard-coded state names!
839 if (found)
840 flowEntryObj.setUserState("FE_USER_MODIFY");
841 else
842 flowEntryObj.setUserState("FE_USER_ADD");
843 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
844 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700845 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800846 //
847
848 // Flow Entries edges:
849 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700850 // NextFE (TODO)
851 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800852 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700853 flowEntryObj.setFlow(flowObj);
854 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800855 }
856 conn.endTx(Transaction.COMMIT);
857
858 //
859 // TODO: We need a proper Flow ID allocation mechanism.
860 //
861 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700862
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800863 return true;
864 }
865
866 /**
867 * Delete a previously added flow.
868 *
869 * @param flowId the Flow ID of the flow to delete.
870 * @return true on success, otherwise false.
871 */
872 @Override
873 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700874 if (flowId.value() == measurementFlowId) {
875 modifiedMeasurementFlowTime = System.nanoTime();
876 }
877
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800878 IFlowPath flowObj = null;
879 //
880 // We just mark the entries for deletion,
881 // and let the switches remove each individual entry after
882 // it has been removed from the switches.
883 //
884 try {
885 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
886 != null) {
887 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
888 flowId.toString());
889 } else {
890 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
891 flowId.toString());
892 }
893 } catch (Exception e) {
894 // TODO: handle exceptions
895 conn.endTx(Transaction.ROLLBACK);
896 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
897 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700898 if (flowObj == null) {
899 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800900 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700901 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800902
903 //
904 // Find and mark for deletion all Flow Entries
905 //
906 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
907 boolean empty = true; // TODO: an ugly hack
908 for (IFlowEntry flowEntryObj : flowEntries) {
909 empty = false;
910 // flowObj.removeFlowEntry(flowEntryObj);
911 // conn.utils().removeFlowEntry(conn, flowEntryObj);
912 flowEntryObj.setUserState("FE_USER_DELETE");
913 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
914 }
915 // Remove from the database empty flows
916 if (empty)
917 conn.utils().removeFlowPath(conn, flowObj);
918 conn.endTx(Transaction.COMMIT);
919
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800920 return true;
921 }
922
923 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700924 * Clear the state for a previously added flow.
925 *
926 * @param flowId the Flow ID of the flow to clear.
927 * @return true on success, otherwise false.
928 */
929 @Override
930 public boolean clearFlow(FlowId flowId) {
931 IFlowPath flowObj = null;
932 try {
933 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
934 != null) {
935 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
936 flowId.toString());
937 } else {
938 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
939 flowId.toString());
940 }
941 } catch (Exception e) {
942 // TODO: handle exceptions
943 conn.endTx(Transaction.ROLLBACK);
944 log.error(":clearFlow FlowId:{} failed", flowId.toString());
945 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700946 if (flowObj == null) {
947 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700948 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700949 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700950
951 //
952 // Remove all Flow Entries
953 //
954 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
955 for (IFlowEntry flowEntryObj : flowEntries) {
956 flowObj.removeFlowEntry(flowEntryObj);
957 conn.utils().removeFlowEntry(conn, flowEntryObj);
958 }
959 // Remove the Flow itself
960 conn.utils().removeFlowPath(conn, flowObj);
961 conn.endTx(Transaction.COMMIT);
962
963 return true;
964 }
965
966 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800967 * Get a previously added flow.
968 *
969 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800970 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800971 */
972 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800973 public FlowPath getFlow(FlowId flowId) {
974 IFlowPath flowObj = null;
975 try {
976 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
977 != null) {
978 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
979 flowId.toString());
980 } else {
981 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
982 flowId.toString());
983 }
984 } catch (Exception e) {
985 // TODO: handle exceptions
986 conn.endTx(Transaction.ROLLBACK);
987 log.error(":getFlow FlowId:{} failed", flowId.toString());
988 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700989 if (flowObj == null) {
990 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800991 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700992 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800993
994 //
995 // Extract the Flow state
996 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800997 FlowPath flowPath = extractFlowPath(flowObj);
998 conn.endTx(Transaction.COMMIT);
999
1000 return flowPath;
1001 }
1002
1003 /**
1004 * Get all previously added flows by a specific installer for a given
1005 * data path endpoints.
1006 *
1007 * @param installerId the Caller ID of the installer of the flow to get.
1008 * @param dataPathEndpoints the data path endpoints of the flow to get.
1009 * @return the Flow Paths if found, otherwise null.
1010 */
1011 @Override
1012 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1013 DataPathEndpoints dataPathEndpoints) {
1014 //
1015 // TODO: The implementation below is not optimal:
1016 // We fetch all flows, and then return only the subset that match
1017 // the query conditions.
1018 // We should use the appropriate Titan/Gremlin query to filter-out
1019 // the flows as appropriate.
1020 //
1021 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001022 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001023
1024 if (allFlows == null) {
1025 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001026 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001027 }
1028
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001029 for (FlowPath flow : allFlows) {
1030 //
1031 // TODO: String-based comparison is sub-optimal.
1032 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001033 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001034 //
1035 if (! flow.installerId().toString().equals(installerId.toString()))
1036 continue;
1037 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1038 continue;
1039 }
1040 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1041 continue;
1042 }
1043 flowPaths.add(flow);
1044 }
1045
1046 if (flowPaths.isEmpty()) {
1047 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001048 } else {
1049 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1050 }
1051
1052 return flowPaths;
1053 }
1054
1055 /**
1056 * Get all installed flows by all installers for given data path endpoints.
1057 *
1058 * @param dataPathEndpoints the data path endpoints of the flows to get.
1059 * @return the Flow Paths if found, otherwise null.
1060 */
1061 @Override
1062 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1063 //
1064 // TODO: The implementation below is not optimal:
1065 // We fetch all flows, and then return only the subset that match
1066 // the query conditions.
1067 // We should use the appropriate Titan/Gremlin query to filter-out
1068 // the flows as appropriate.
1069 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001070 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1071 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001072
1073 if (allFlows == null) {
1074 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001075 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001076 }
1077
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001078 for (FlowPath flow : allFlows) {
1079 //
1080 // TODO: String-based comparison is sub-optimal.
1081 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001082 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001083 //
1084 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1085 continue;
1086 }
1087 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1088 continue;
1089 }
1090 flowPaths.add(flow);
1091 }
1092
1093 if (flowPaths.isEmpty()) {
1094 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001095 } else {
1096 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1097 }
1098
1099 return flowPaths;
1100 }
1101
1102 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001103 * Get summary of all installed flows by all installers in a given range
1104 *
1105 * @param flowId the data path endpoints of the flows to get.
1106 * @param maxFlows: the maximum number of flows to be returned
1107 * @return the Flow Paths if found, otherwise null.
1108 */
1109 @Override
1110 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1111 //
1112 // TODO: The implementation below is not optimal:
1113 // We fetch all flows, and then return only the subset that match
1114 // the query conditions.
1115 // We should use the appropriate Titan/Gremlin query to filter-out
1116 // the flows as appropriate.
1117 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001118 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1119
1120 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001121
1122 if (allFlows == null) {
1123 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001124 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001125 }
1126
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001127 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001128
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001129 for (FlowPath flow : allFlows) {
1130
1131 // start from desired flowId
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -07001132 //if (flow.flowId().value() < flowId.value()) {
1133 // continue;
1134 //}
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001135
1136 // Summarize by making null flow entry fields that are not relevant to report
1137 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1138 flowEntry.setFlowEntryActions(null);
1139 flowEntry.setFlowEntryMatch(null);
1140 }
1141
1142 flowPaths.add(flow);
1143 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1144 break;
1145 }
1146 }
1147
1148 if (flowPaths.isEmpty()) {
1149 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001150 } else {
1151 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1152 }
1153
1154 return flowPaths;
1155 }
1156
1157 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001158 * Get all installed flows by all installers.
1159 *
1160 * @return the Flow Paths if found, otherwise null.
1161 */
1162 @Override
1163 public ArrayList<FlowPath> getAllFlows() {
1164 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001165 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001166
1167 try {
1168 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1169 log.debug("Get all FlowPaths: found FlowPaths");
1170 } else {
1171 log.debug("Get all FlowPaths: no FlowPaths found");
1172 }
1173 } catch (Exception e) {
1174 // TODO: handle exceptions
1175 conn.endTx(Transaction.ROLLBACK);
1176 log.error(":getAllFlowPaths failed");
1177 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001178 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1179 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001180 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001181 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001182
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001183 for (IFlowPath flowObj : flowPathsObj) {
1184 //
1185 // Extract the Flow state
1186 //
1187 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001188 if (flowPath != null)
1189 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001190 }
1191
1192 conn.endTx(Transaction.COMMIT);
1193
1194 return flowPaths;
1195 }
1196
1197 /**
1198 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1199 *
1200 * @param flowObj the object to extract the Flow Path State from.
1201 * @return the extracted Flow Path State.
1202 */
1203 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001204 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001205
1206 //
1207 // Extract the Flow state
1208 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001209 String flowIdStr = flowObj.getFlowId();
1210 String installerIdStr = flowObj.getInstallerId();
1211 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001212 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001213 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001214 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001215
1216 if ((flowIdStr == null) ||
1217 (installerIdStr == null) ||
1218 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001219 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001220 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001221 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001222 // TODO: A work-around, becauuse of some bogus database objects
1223 return null;
1224 }
1225
1226 flowPath.setFlowId(new FlowId(flowIdStr));
1227 flowPath.setInstallerId(new CallerId(installerIdStr));
1228 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001229 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001230 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001231 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001232
1233 //
1234 // Extract all Flow Entries
1235 //
1236 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1237 for (IFlowEntry flowEntryObj : flowEntries) {
1238 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001239 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1240 String switchDpidStr = flowEntryObj.getSwitchDpid();
1241 String userState = flowEntryObj.getUserState();
1242 String switchState = flowEntryObj.getSwitchState();
1243
1244 if ((flowEntryIdStr == null) ||
1245 (switchDpidStr == null) ||
1246 (userState == null) ||
1247 (switchState == null)) {
1248 // TODO: A work-around, becauuse of some bogus database objects
1249 continue;
1250 }
1251 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1252 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001253
1254 //
1255 // Extract the match conditions
1256 //
1257 FlowEntryMatch match = new FlowEntryMatch();
1258 Short matchInPort = flowEntryObj.getMatchInPort();
1259 if (matchInPort != null)
1260 match.enableInPort(new Port(matchInPort));
1261 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1262 if (matchEthernetFrameType != null)
1263 match.enableEthernetFrameType(matchEthernetFrameType);
1264 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1265 if (matchSrcIPv4Net != null)
1266 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1267 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1268 if (matchDstIPv4Net != null)
1269 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1270 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1271 if (matchSrcMac != null)
1272 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1273 String matchDstMac = flowEntryObj.getMatchDstMac();
1274 if (matchDstMac != null)
1275 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1276 flowEntry.setFlowEntryMatch(match);
1277
1278 //
1279 // Extract the actions
1280 //
1281 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1282 Short actionOutputPort = flowEntryObj.getActionOutput();
1283 if (actionOutputPort != null) {
1284 FlowEntryAction action = new FlowEntryAction();
1285 action.setActionOutput(new Port(actionOutputPort));
1286 actions.add(action);
1287 }
1288 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001289 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001290 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1291 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001292 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001293 // and FlowEntryErrorState.
1294 //
1295 flowPath.dataPath().flowEntries().add(flowEntry);
1296 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001297
1298 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001299 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001300
1301 /**
1302 * Add and maintain a shortest-path flow.
1303 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001304 * NOTE: The Flow Path argument does NOT contain all flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001305 * Instead, it contains a single dummy flow entry that is used to
1306 * store the matching condition(s).
1307 * That entry is replaced by the appropriate entries from the
1308 * internally performed shortest-path computation.
1309 *
1310 * @param flowPath the Flow Path with the endpoints and the match
1311 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001312 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001313 */
1314 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001315 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001316 String dataPathSummaryStr = null;
1317
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001318 //
1319 // Do the shortest path computation
1320 //
1321 DataPath dataPath =
1322 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1323 flowPath.dataPath().dstPort());
1324 if (dataPath == null)
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001325 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001326
1327 FlowEntryMatch userFlowEntryMatch = null;
1328 if (! flowPath.dataPath().flowEntries().isEmpty()) {
1329 userFlowEntryMatch = flowPath.dataPath().flowEntries().get(0).flowEntryMatch();
1330 }
1331
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001332 // Compute the Data Path summary
1333 dataPathSummaryStr = dataPath.dataPathSummary();
1334
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001335 //
1336 // Set the incoming port matching and the outgoing port output
1337 // actions for each flow entry.
1338 //
1339 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1340 // Set the incoming port matching
1341 FlowEntryMatch flowEntryMatch = null;
1342 if (userFlowEntryMatch != null)
1343 flowEntryMatch = new FlowEntryMatch(userFlowEntryMatch);
1344 else
1345 flowEntryMatch = new FlowEntryMatch();
1346 flowEntry.setFlowEntryMatch(flowEntryMatch);
1347 flowEntryMatch.enableInPort(flowEntry.inPort());
1348
1349 // Set the outgoing port output action
1350 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1351 if (flowEntryActions == null) {
1352 flowEntryActions = new ArrayList<FlowEntryAction>();
1353 flowEntry.setFlowEntryActions(flowEntryActions);
1354 }
1355 FlowEntryAction flowEntryAction = new FlowEntryAction();
1356 flowEntryAction.setActionOutput(flowEntry.outPort());
1357 flowEntryActions.add(flowEntryAction);
1358 }
1359
1360 //
1361 // Prepare the computed Flow Path
1362 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001363 FlowPath computedFlowPath = new FlowPath();
1364 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1365 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1366 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001367
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001368 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001369 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001370 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001371
1372 // TODO: Mark the flow for maintenance purpose
1373
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001374 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001375 }
1376
1377 /**
1378 * Create a Flow from port to port.
1379 *
1380 * TODO: We don't need it for now.
1381 *
1382 * @param src_port the source port.
1383 * @param dest_port the destination port.
1384 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001385 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001386 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1387 // TODO: We don't need it for now.
1388 }
1389
1390 /**
1391 * Get all Flows matching a source and a destination port.
1392 *
1393 * TODO: Pankaj might be implementing it later.
1394 *
1395 * @param src_port the source port to match.
1396 * @param dest_port the destination port to match.
1397 * @return all flows matching the source and the destination port.
1398 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001399 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001400 public Iterable<FlowPath> getFlows(IPortObject src_port,
1401 IPortObject dest_port) {
1402 // TODO: Pankaj might be implementing it later.
1403 return null;
1404 }
1405
1406 /**
1407 * Get all Flows going out from a port.
1408 *
1409 * TODO: We need it now: Pankaj
1410 *
1411 * @param port the port to match.
1412 * @return the list of flows that are going out from the port.
1413 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001414 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001415 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001416 // TODO: We need it now: Pankaj
1417 return null;
1418 }
1419
1420 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001421 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001422 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001423 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001424 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001425 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001426 public void reconcileFlows(IPortObject portObject) {
1427 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1428 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001429
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001430 //
1431 // Collect all affected Flow IDs from the affected flow entries
1432 //
1433 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1434 for (IFlowEntry flowEntryObj: inFlowEntries) {
1435 IFlowPath flowObj = flowEntryObj.getFlow();
1436 if (flowObj != null)
1437 flowObjSet.add(flowObj);
1438 }
1439 for (IFlowEntry flowEntryObj: outFlowEntries) {
1440 IFlowPath flowObj = flowEntryObj.getFlow();
1441 if (flowObj != null)
1442 flowObjSet.add(flowObj);
1443 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001444
1445 // Reconcile the affected flows
1446 reconcileFlows(flowObjSet);
1447 }
1448
1449 /**
1450 * Reconcile all flows in a set.
1451 *
1452 * @param flowObjSet the set of flows that need to be reconciliated.
1453 */
1454 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1455 if (! flowObjSet.iterator().hasNext())
1456 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001457
1458 //
1459 // Remove the old Flow Entries, and add the new Flow Entries
1460 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001461
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001462 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001463 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001464 for (IFlowPath flowObj : flowObjSet) {
1465 FlowPath flowPath = extractFlowPath(flowObj);
1466 if (flowPath == null)
1467 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001468 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001469
1470 //
1471 // Remove my Flow Entries from the Network MAP
1472 //
1473 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001474 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001475 for (IFlowEntry flowEntryObj : flowEntries) {
1476 String dpidStr = flowEntryObj.getSwitchDpid();
1477 if (dpidStr == null)
1478 continue;
1479 Dpid dpid = new Dpid(dpidStr);
1480 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1481 if (mySwitch == null)
1482 continue; // Ignore the entry: not my switch
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001483 deleteFlowEntries.add(flowEntryObj);
1484 }
1485 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001486 flowObj.removeFlowEntry(flowEntryObj);
1487 conn.utils().removeFlowEntry(conn, flowEntryObj);
1488 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001489 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001490
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001491 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001492 //
1493 // Delete the flow entries from the switches
1494 //
1495 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1496 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001497 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1498 if (mySwitch == null) {
1499 // Not my switch
1500 installRemoteFlowEntry(flowEntry);
1501 } else {
1502 installFlowEntry(mySwitch, flowEntry);
1503 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001504 }
1505
1506 //
1507 // Calculate the new shortest path and install it in the
1508 // Network MAP.
1509 //
1510 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1511 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001512 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001513 flowPath.dataPath().srcPort().toString(),
1514 flowPath.dataPath().dstPort().toString());
1515 continue;
1516 }
1517
1518 //
1519 // Add the flow entries to the switches
1520 //
1521 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1522 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001523 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1524 if (mySwitch == null) {
1525 // Not my switch
1526 installRemoteFlowEntry(flowEntry);
1527 continue;
1528 }
1529
1530 IFlowEntry flowEntryObj =
1531 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1532 if (flowEntryObj == null) {
1533 //
1534 // TODO: Remove the "new Object[] wrapper in the statement
1535 // below after the SLF4J logger is upgraded to
1536 // Version 1.7.5
1537 //
1538 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1539 new Object[] {
1540 flowEntry.dpid(),
1541 flowPath.dataPath().srcPort(),
1542 flowPath.dataPath().dstPort()
1543 });
1544 continue;
1545 }
1546 // Update the Flow Entry Switch State in the Network MAP
1547 if (installFlowEntry(mySwitch, flowEntry)) {
1548 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1549 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001550 }
1551 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001552 }
1553
1554 /**
1555 * Reconcile all flows between a source and a destination port.
1556 *
1557 * TODO: We don't need it for now.
1558 *
1559 * @param src_port the source port.
1560 * @param dest_port the destination port.
1561 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001562 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001563 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1564 // TODO: We don't need it for now.
1565 }
1566
1567 /**
1568 * Compute the shortest path between a source and a destination ports.
1569 *
1570 * @param src_port the source port.
1571 * @param dest_port the destination port.
1572 * @return the computed shortest path between the source and the
1573 * destination ports. The flow entries in the path itself would
1574 * contain the incoming port matching and the outgoing port output
1575 * actions set. However, the path itself will NOT have the Flow ID,
1576 * Installer ID, and any additional matching conditions for the
1577 * flow entries (e.g., source or destination MAC address, etc).
1578 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001579 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001580 public FlowPath computeFlowPath(IPortObject src_port,
1581 IPortObject dest_port) {
1582 //
1583 // Prepare the arguments
1584 //
1585 String dpidStr = src_port.getSwitch().getDPID();
1586 Dpid srcDpid = new Dpid(dpidStr);
1587 Port srcPort = new Port(src_port.getNumber());
1588
1589 dpidStr = dest_port.getSwitch().getDPID();
1590 Dpid dstDpid = new Dpid(dpidStr);
1591 Port dstPort = new Port(dest_port.getNumber());
1592
1593 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1594 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1595
1596 //
1597 // Do the shortest path computation
1598 //
1599 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1600 if (dataPath == null)
1601 return null;
1602
1603 //
1604 // Set the incoming port matching and the outgoing port output
1605 // actions for each flow entry.
1606 //
1607 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1608 // Set the incoming port matching
1609 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1610 if (flowEntryMatch == null) {
1611 flowEntryMatch = new FlowEntryMatch();
1612 flowEntry.setFlowEntryMatch(flowEntryMatch);
1613 }
1614 flowEntryMatch.enableInPort(flowEntry.inPort());
1615
1616 // Set the outgoing port output action
1617 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1618 if (flowEntryActions == null) {
1619 flowEntryActions = new ArrayList<FlowEntryAction>();
1620 flowEntry.setFlowEntryActions(flowEntryActions);
1621 }
1622 FlowEntryAction flowEntryAction = new FlowEntryAction();
1623 flowEntryAction.setActionOutput(flowEntry.outPort());
1624 flowEntryActions.add(flowEntryAction);
1625 }
1626
1627 //
1628 // Prepare the return result
1629 //
1630 FlowPath flowPath = new FlowPath();
1631 flowPath.setDataPath(dataPath);
1632
1633 return flowPath;
1634 }
1635
1636 /**
1637 * Get all Flow Entries of a Flow.
1638 *
1639 * @param flow the flow whose flow entries should be returned.
1640 * @return the flow entries of the flow.
1641 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001642 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001643 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1644 return flow.dataPath().flowEntries();
1645 }
1646
1647 /**
1648 * Install a Flow Entry on a switch.
1649 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001650 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001651 * @param flowEntry the flow entry to install.
1652 * @return true on success, otherwise false.
1653 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001654 @Override
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001655 public boolean installFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001656 //
1657 // Create the OpenFlow Flow Modification Entry to push
1658 //
1659 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1660 .getMessage(OFType.FLOW_MOD);
1661 long cookie = flowEntry.flowEntryId().value();
1662
1663 short flowModCommand = OFFlowMod.OFPFC_ADD;
1664 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1665 flowModCommand = OFFlowMod.OFPFC_ADD;
1666 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1667 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1668 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1669 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1670 } else {
1671 // Unknown user state. Ignore the entry
1672 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1673 flowEntry.flowEntryId().toString(),
1674 flowEntry.flowEntryUserState());
1675 return false;
1676 }
1677
1678 //
1679 // Fetch the match conditions
1680 //
1681 OFMatch match = new OFMatch();
1682 match.setWildcards(OFMatch.OFPFW_ALL);
1683 Port matchInPort = flowEntry.flowEntryMatch().inPort();
1684 if (matchInPort != null) {
1685 match.setInputPort(matchInPort.value());
1686 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1687 }
1688 Short matchEthernetFrameType =
1689 flowEntry.flowEntryMatch().ethernetFrameType();
1690 if (matchEthernetFrameType != null) {
1691 match.setDataLayerType(matchEthernetFrameType);
1692 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1693 }
1694 IPv4Net matchSrcIPv4Net = flowEntry.flowEntryMatch().srcIPv4Net();
1695 if (matchSrcIPv4Net != null) {
1696 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1697 }
1698 IPv4Net matchDstIPv4Net = flowEntry.flowEntryMatch().dstIPv4Net();
1699 if (matchDstIPv4Net != null) {
1700 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1701 }
1702 MACAddress matchSrcMac = flowEntry.flowEntryMatch().srcMac();
1703 if (matchSrcMac != null) {
1704 match.setDataLayerSource(matchSrcMac.toString());
1705 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1706 }
1707 MACAddress matchDstMac = flowEntry.flowEntryMatch().dstMac();
1708 if (matchDstMac != null) {
1709 match.setDataLayerDestination(matchDstMac.toString());
1710 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1711 }
1712
1713 //
1714 // Fetch the actions
1715 //
1716 // TODO: For now we support only the "OUTPUT" actions.
1717 //
1718 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1719 List<OFAction> actions = new ArrayList<OFAction>();
1720 ArrayList<FlowEntryAction> flowEntryActions =
1721 flowEntry.flowEntryActions();
1722 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1723 FlowEntryAction.ActionOutput actionOutput =
1724 flowEntryAction.actionOutput();
1725 if (actionOutput != null) {
1726 short actionOutputPort = actionOutput.port().value();
1727 OFActionOutput action = new OFActionOutput();
1728 // XXX: The max length is hard-coded for now
1729 action.setMaxLength((short)0xffff);
1730 action.setPort(actionOutputPort);
1731 actions.add(action);
1732 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1733 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1734 fm.setOutPort(actionOutputPort);
1735 }
1736 }
1737 }
1738
1739 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1740 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1741 .setPriority(PRIORITY_DEFAULT)
1742 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1743 .setCookie(cookie)
1744 .setCommand(flowModCommand)
1745 .setMatch(match)
1746 .setActions(actions)
1747 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1748
1749 //
1750 // TODO: Set the following flag
1751 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1752 // See method ForwardingBase::pushRoute()
1753 //
1754
1755 //
1756 // Write the message to the switch
1757 //
1758 try {
1759 messageDamper.write(mySwitch, fm, null);
1760 mySwitch.flush();
1761 } catch (IOException e) {
1762 log.error("Failure writing flow mod from network map", e);
1763 return false;
1764 }
1765 return true;
1766 }
1767
1768 /**
1769 * Remove a Flow Entry from a switch.
1770 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001771 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001772 * @param flowEntry the flow entry to remove.
1773 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001774 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001775 @Override
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001776 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001777 //
1778 // The installFlowEntry() method implements both installation
1779 // and removal of flow entries.
1780 //
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001781 return (installFlowEntry(mySwitch, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001782 }
1783
1784 /**
1785 * Install a Flow Entry on a remote controller.
1786 *
1787 * TODO: We need it now: Jono
1788 * - For now it will make a REST call to the remote controller.
1789 * - Internally, it needs to know the name of the remote controller.
1790 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001791 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001792 * @return true on success, otherwise false.
1793 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001794 @Override
1795 public boolean installRemoteFlowEntry(FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001796 // TODO: We need it now: Jono
1797 // - For now it will make a REST call to the remote controller.
1798 // - Internally, it needs to know the name of the remote controller.
1799 return true;
1800 }
1801
1802 /**
1803 * Remove a flow entry on a remote controller.
1804 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001805 * @param flowEntry the flow entry to remove.
1806 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001807 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001808 @Override
1809 public boolean removeRemoteFlowEntry(FlowEntry flowEntry) {
1810 //
1811 // The installRemoteFlowEntry() method implements both installation
1812 // and removal of flow entries.
1813 //
1814 return (installRemoteFlowEntry(flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001815 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001816}