blob: 36d105938eb83c457850678a8f6c3b92703a9801 [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 Radoslavovb6f53542013-03-01 16:02:14 -08008import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08009import java.util.Map;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070010import java.util.TreeMap;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070011import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080012import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070013import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.ScheduledExecutorService;
15import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070016import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080018
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import net.floodlightcontroller.core.IFloodlightProviderService;
20import net.floodlightcontroller.core.INetMapStorage;
21import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
22import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070023import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080024import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080025import net.floodlightcontroller.core.module.FloodlightModuleContext;
26import net.floodlightcontroller.core.module.FloodlightModuleException;
27import net.floodlightcontroller.core.module.IFloodlightModule;
28import net.floodlightcontroller.core.module.IFloodlightService;
29import net.floodlightcontroller.flowcache.IFlowService;
30import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
31import net.floodlightcontroller.restserver.IRestApiService;
32import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033import net.floodlightcontroller.util.DataPath;
34import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080035import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080036import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070037import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080038import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070039import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080040import net.floodlightcontroller.util.FlowEntrySwitchState;
41import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080042import net.floodlightcontroller.util.FlowId;
43import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070044import net.floodlightcontroller.util.IPv4Net;
45import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046import net.floodlightcontroller.util.OFMessageDamper;
47import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070048import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080049import net.onrc.onos.util.GraphDBConnection;
50import net.onrc.onos.util.GraphDBConnection.Transaction;
51
52import org.openflow.protocol.OFFlowMod;
53import org.openflow.protocol.OFMatch;
54import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070055import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056import org.openflow.protocol.OFType;
57import org.openflow.protocol.action.OFAction;
58import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080059
60import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080063public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
64
65 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080066
67 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080068 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070069 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070
71 protected OFMessageDamper messageDamper;
72
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070073 //
74 // TODO: Values copied from elsewhere (class LearningSwitch).
75 // The local copy should go away!
76 //
77 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
78 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
79 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
80 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
81 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080082
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070083 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070084 private static long measurementFlowId = 100000;
85 private static String measurementFlowIdStr = "0x186a0"; // 100000
86 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070087
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080088 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080089 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
90
91 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070092 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080093 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070094 private final ScheduledExecutorService measureMapReaderScheduler =
95 Executors.newScheduledThreadPool(1);
96 private final ScheduledExecutorService mapReaderScheduler =
97 Executors.newScheduledThreadPool(1);
98
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070099 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
100 private ThreadPoolExecutor shortestPathExecutor =
101 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
102
103 class ShortestPathTask implements Runnable {
104 private int hint;
105 private ITopoRouteService topoRouteService;
106 private ArrayList<DataPath> dpList;
107
108 public ShortestPathTask(int hint,
109 ITopoRouteService topoRouteService,
110 ArrayList<DataPath> dpList) {
111 this.hint = hint;
112 this.topoRouteService = topoRouteService;
113 this.dpList = dpList;
114 }
115
116 @Override
117 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700118 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700119 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
120 log.debug(logMsg);
121 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700122 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700123 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700124 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700125 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700126 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700127 long estimatedTime = System.nanoTime() - startTime;
128 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
129 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
130 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700131 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700132 }
133 }
134
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700135 final Runnable measureShortestPath = new Runnable() {
136 public void run() {
137 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
138 if (floodlightProvider == null) {
139 log.debug("FloodlightProvider service not found!");
140 return;
141 }
142
143 ITopoRouteService topoRouteService =
144 context.getServiceImpl(ITopoRouteService.class);
145 if (topoRouteService == null) {
146 log.debug("Topology Route Service not found");
147 return;
148 }
149
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700150 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
151 if (leftoverQueueSize > 0) {
152 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
153 log.debug(logMsg);
154 return;
155 }
156 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
157
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700158 //
159 // Recompute the Shortest Paths for all Flows
160 //
161 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700162 int hint = 0;
163 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700164 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700165
166 topoRouteService.prepareShortestPathTopo();
167
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700168 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
169 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700170 FlowId flowId = new FlowId(flowPathObj.getFlowId());
171
172 // log.debug("Found Path {}", flowId.toString());
173 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
174 Port srcPort = new Port(flowPathObj.getSrcPort());
175 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
176 Port dstPort = new Port(flowPathObj.getDstPort());
177 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
178 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700179
180 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700181 DataPath dp = new DataPath();
182 dp.setSrcPort(srcSwitchPort);
183 dp.setDstPort(dstSwitchPort);
184 dpList.add(dp);
185 if ((dpList.size() % 10) == 0) {
186 shortestPathExecutor.execute(
187 new ShortestPathTask(hint, topoRouteService,
188 dpList));
189 dpList = new ArrayList<DataPath>();
190 hint++;
191 }
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700192 */
193
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700194 DataPath dataPath =
195 topoRouteService.getTopoShortestPath(srcSwitchPort,
196 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700197 counter++;
198 }
199 if (dpList.size() > 0) {
200 shortestPathExecutor.execute(
201 new ShortestPathTask(hint, topoRouteService,
202 dpList));
203 }
204
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700205 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700206 // Wait for all tasks to finish
207 try {
208 while (shortestPathExecutor.getQueue().size() > 0) {
209 Thread.sleep(100);
210 }
211 } catch (InterruptedException ex) {
212 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700213 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700214 */
215
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700216 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700217 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700218
219 long estimatedTime = System.nanoTime() - startTime;
220 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
221 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
222 log.debug(logMsg);
223 }
224 };
225
226 final Runnable measureMapReader = new Runnable() {
227 public void run() {
228 if (floodlightProvider == null) {
229 log.debug("FloodlightProvider service not found!");
230 return;
231 }
232
233 //
234 // Fetch all Flow Entries
235 //
236 int counter = 0;
237 long startTime = System.nanoTime();
238 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
239 for (IFlowEntry flowEntryObj : allFlowEntries) {
240 counter++;
241 FlowEntryId flowEntryId =
242 new FlowEntryId(flowEntryObj.getFlowEntryId());
243 String userState = flowEntryObj.getUserState();
244 String switchState = flowEntryObj.getSwitchState();
245 }
246 conn.endTx(Transaction.COMMIT);
247
248 long estimatedTime = System.nanoTime() - startTime;
249 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
250 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
251 log.debug(logMsg);
252 }
253 };
254
255 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800256 public void run() {
257 // log.debug("Reading Flow Entries from the Network Map...");
258 if (floodlightProvider == null) {
259 log.debug("FloodlightProvider service not found!");
260 return;
261 }
262
263 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
264
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700265 Map<Long, IFlowEntry> myFlowEntries = new TreeMap<Long, IFlowEntry>();
266
267 //
268 // Fetch all Flow Entries and select only my Flow Entries
269 //
270 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
271 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800272 FlowEntryId flowEntryId =
273 new FlowEntryId(flowEntryObj.getFlowEntryId());
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700274 String userState = flowEntryObj.getUserState();
275 String switchState = flowEntryObj.getSwitchState();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800276
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700277 log.debug("Found Flow Entry {}: {}",
278 flowEntryId.toString(),
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700279 "User State: " + userState +
280 " Switch State: " + switchState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800281
282 if (! switchState.equals("FE_SWITCH_NOT_UPDATED")) {
283 // Ignore the entry: nothing to do
284 continue;
285 }
286
287 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
288 IOFSwitch mySwitch = mySwitches.get(dpid.value());
289 if (mySwitch == null) {
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700290 log.debug("Flow Entry ignored: not my switch (FlowEntryId = {} DPID = {})", flowEntryId.toString(), dpid.toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800291 continue;
292 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700293 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
294 }
295
296 //
297 // Process my Flow Entries
298 //
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700299 Boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700300 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
301 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700302 // Code for measurement purpose
303 {
304 IFlowPath flowObj =
305 conn.utils().getFlowPathByFlowEntry(conn,
306 flowEntryObj);
307 if ((flowObj != null) &&
308 flowObj.getFlowId().equals(measurementFlowIdStr)) {
309 processed_measurement_flow = true;
310 }
311 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700312
313 //
314 // TODO: Eliminate the re-fetching of flowEntryId,
315 // userState, switchState, and dpid from the flowEntryObj.
316 //
317 FlowEntryId flowEntryId =
318 new FlowEntryId(flowEntryObj.getFlowEntryId());
319 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
320 String userState = flowEntryObj.getUserState();
321 String switchState = flowEntryObj.getSwitchState();
322 IOFSwitch mySwitch = mySwitches.get(dpid.value());
323 if (mySwitch == null) {
324 log.debug("Flow Entry ignored: not my switch");
325 continue;
326 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800327
328 //
329 // Create the Open Flow Flow Modification Entry to push
330 //
331 OFFlowMod fm =
332 (OFFlowMod) floodlightProvider.getOFMessageFactory()
333 .getMessage(OFType.FLOW_MOD);
334 long cookie = flowEntryId.value();
335
336 short flowModCommand = OFFlowMod.OFPFC_ADD;
337 if (userState.equals("FE_USER_ADD")) {
338 flowModCommand = OFFlowMod.OFPFC_ADD;
339 } else if (userState.equals("FE_USER_MODIFY")) {
340 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
341 } else if (userState.equals("FE_USER_DELETE")) {
342 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
343 } else {
344 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700345 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
346 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800347 continue;
348 }
349
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700350 //
351 // Fetch the match conditions
352 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800353 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700354 match.setWildcards(OFMatch.OFPFW_ALL);
355 Short matchInPort = flowEntryObj.getMatchInPort();
356 if (matchInPort != null) {
357 match.setInputPort(matchInPort);
358 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
359 }
360 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
361 if (matchEthernetFrameType != null) {
362 match.setDataLayerType(matchEthernetFrameType);
363 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
364 }
365 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
366 if (matchSrcIPv4Net != null) {
367 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
368 }
369 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
370 if (matchDstIPv4Net != null) {
371 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
372 }
373 String matchSrcMac = flowEntryObj.getMatchSrcMac();
374 if (matchSrcMac != null) {
375 match.setDataLayerSource(matchSrcMac);
376 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
377 }
378 String matchDstMac = flowEntryObj.getMatchDstMac();
379 if (matchDstMac != null) {
380 match.setDataLayerDestination(matchDstMac);
381 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
382 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700383
384 //
385 // Fetch the actions
386 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800387 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700388 Short actionOutputPort = flowEntryObj.getActionOutput();
389 if (actionOutputPort != null) {
390 OFActionOutput action = new OFActionOutput();
391 // XXX: The max length is hard-coded for now
392 action.setMaxLength((short)0xffff);
393 action.setPort(actionOutputPort);
394 actions.add(action);
395 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800396
397 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
398 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700399 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800400 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
401 .setCookie(cookie)
402 .setCommand(flowModCommand)
403 .setMatch(match)
404 .setActions(actions)
405 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700406 fm.setOutPort(OFPort.OFPP_NONE.getValue());
407 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
408 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
409 if (actionOutputPort != null)
410 fm.setOutPort(actionOutputPort);
411 }
412
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800413 //
414 // TODO: Set the following flag
415 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
416 // See method ForwardingBase::pushRoute()
417 //
418 try {
419 messageDamper.write(mySwitch, fm, null);
420 mySwitch.flush();
421 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
422 if (userState.equals("FE_USER_DELETE")) {
423 // Delete the entry
424 IFlowPath flowObj = null;
425 flowObj = conn.utils().getFlowPathByFlowEntry(conn,
426 flowEntryObj);
427 if (flowObj != null)
428 log.debug("Found FlowPath to be deleted");
429 else
430 log.debug("Did not find FlowPath to be deleted");
431 flowObj.removeFlowEntry(flowEntryObj);
432 conn.utils().removeFlowEntry(conn, flowEntryObj);
433
434 // Test whether the last flow entry
435 Iterable<IFlowEntry> tmpflowEntries =
436 flowObj.getFlowEntries();
437 boolean found = false;
438 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
439 found = true;
440 break;
441 }
442 if (! found) {
443 // Remove the Flow Path as well
444 conn.utils().removeFlowPath(conn, flowObj);
445 }
446 }
447 } catch (IOException e) {
448 log.error("Failure writing flow mod from network map", e);
449 }
450 }
451 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700452
453 if (processed_measurement_flow) {
454 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
455 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
456 (double)estimatedTime / 1000000000 + " sec";
457 log.debug(logMsg);
458 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800459 }
460 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700461
462 /*
463 final ScheduledFuture<?> measureShortestPathHandle =
464 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
465 */
466
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700467 final ScheduledFuture<?> measureMapReaderHandle =
468 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700469
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700470 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700471 final ScheduledFuture<?> mapReaderHandle =
472 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700473 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800474
475 @Override
476 public void init(String conf) {
477 conn = GraphDBConnection.getInstance(conf);
478 }
479
480 public void finalize() {
481 close();
482 }
483
484 @Override
485 public void close() {
486 conn.close();
487 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800488
489 @Override
490 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
491 Collection<Class<? extends IFloodlightService>> l =
492 new ArrayList<Class<? extends IFloodlightService>>();
493 l.add(IFlowService.class);
494 return l;
495 }
496
497 @Override
498 public Map<Class<? extends IFloodlightService>, IFloodlightService>
499 getServiceImpls() {
500 Map<Class<? extends IFloodlightService>,
501 IFloodlightService> m =
502 new HashMap<Class<? extends IFloodlightService>,
503 IFloodlightService>();
504 m.put(IFlowService.class, this);
505 return m;
506 }
507
508 @Override
509 public Collection<Class<? extends IFloodlightService>>
510 getModuleDependencies() {
511 Collection<Class<? extends IFloodlightService>> l =
512 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800513 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800514 l.add(IRestApiService.class);
515 return l;
516 }
517
518 @Override
519 public void init(FloodlightModuleContext context)
520 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700521 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800522 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800523 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800524 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
525 EnumSet.of(OFType.FLOW_MOD),
526 OFMESSAGE_DAMPER_TIMEOUT);
527 // TODO: An ugly hack!
528 String conf = "/tmp/cassandra.titan";
529 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800530 }
531
532 @Override
533 public void startUp(FloodlightModuleContext context) {
534 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700535
536 //
537 // Extract all flow entries and assign the next Flow Entry ID
538 // to be larger than the largest Flow Entry ID
539 //
540 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
541 for (IFlowEntry flowEntryObj : allFlowEntries) {
542 FlowEntryId flowEntryId =
543 new FlowEntryId(flowEntryObj.getFlowEntryId());
544 if (flowEntryId.value() >= nextFlowEntryId)
545 nextFlowEntryId = flowEntryId.value() + 1;
546 }
547 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800548 }
549
550 /**
551 * Add a flow.
552 *
553 * Internally, ONOS will automatically register the installer for
554 * receiving Flow Path Notifications for that path.
555 *
556 * @param flowPath the Flow Path to install.
557 * @param flowId the return-by-reference Flow ID as assigned internally.
558 * @return true on success, otherwise false.
559 */
560 @Override
561 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700562 if (flowPath.flowId().value() == measurementFlowId) {
563 modifiedMeasurementFlowTime = System.nanoTime();
564 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800565
566 //
567 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700568 // Right now every new flow entry gets a new flow entry ID
569 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800570 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800571 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700572 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800573 flowEntry.setFlowEntryId(new FlowEntryId(id));
574 }
575
576 IFlowPath flowObj = null;
577 try {
578 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
579 != null) {
580 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
581 flowPath.flowId().toString());
582 } else {
583 flowObj = conn.utils().newFlowPath(conn);
584 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
585 flowPath.flowId().toString());
586 }
587 } catch (Exception e) {
588 // TODO: handle exceptions
589 conn.endTx(Transaction.ROLLBACK);
590 log.error(":addFlow FlowId:{} failed",
591 flowPath.flowId().toString());
592 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700593 if (flowObj == null) {
594 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800595 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700596 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800597
598 //
599 // Set the Flow key:
600 // - flowId
601 //
602 flowObj.setFlowId(flowPath.flowId().toString());
603 flowObj.setType("flow");
604
605 //
606 // Set the Flow attributes:
607 // - flowPath.installerId()
608 // - flowPath.dataPath().srcPort()
609 // - flowPath.dataPath().dstPort()
610 //
611 flowObj.setInstallerId(flowPath.installerId().toString());
612 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
613 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
614 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
615 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
616
617 // Flow edges:
618 // HeadFE
619
620
621 //
622 // Flow Entries:
623 // flowPath.dataPath().flowEntries()
624 //
625 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
626 IFlowEntry flowEntryObj = null;
627 boolean found = false;
628 try {
629 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
630 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
631 flowEntry.flowEntryId().toString());
632 found = true;
633 } else {
634 flowEntryObj = conn.utils().newFlowEntry(conn);
635 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
636 flowEntry.flowEntryId().toString());
637 }
638 } catch (Exception e) {
639 // TODO: handle exceptions
640 conn.endTx(Transaction.ROLLBACK);
641 log.error(":addFlow FlowEntryId:{} failed",
642 flowEntry.flowEntryId().toString());
643 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700644 if (flowEntryObj == null) {
645 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800646 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700647 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800648
649 //
650 // Set the Flow Entry key:
651 // - flowEntry.flowEntryId()
652 //
653 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
654 flowEntryObj.setType("flow_entry");
655
656 //
657 // Set the Flow Entry attributes:
658 // - flowEntry.flowEntryMatch()
659 // - flowEntry.flowEntryActions()
660 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800661 // - flowEntry.flowEntryUserState()
662 // - flowEntry.flowEntrySwitchState()
663 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700664 // - flowEntry.matchInPort()
665 // - flowEntry.matchEthernetFrameType()
666 // - flowEntry.matchSrcIPv4Net()
667 // - flowEntry.matchDstIPv4Net()
668 // - flowEntry.matchSrcMac()
669 // - flowEntry.matchDstMac()
670 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800671 //
672 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700673 if (flowEntry.flowEntryMatch().matchInPort())
674 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
675 if (flowEntry.flowEntryMatch().matchEthernetFrameType())
676 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
677 if (flowEntry.flowEntryMatch().matchSrcIPv4Net())
678 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
679 if (flowEntry.flowEntryMatch().matchDstIPv4Net())
680 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
681 if (flowEntry.flowEntryMatch().matchSrcMac())
682 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
683 if (flowEntry.flowEntryMatch().matchDstMac())
684 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
685
686 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
687 if (fa.actionOutput() != null)
688 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
689 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800690 // TODO: Hacks with hard-coded state names!
691 if (found)
692 flowEntryObj.setUserState("FE_USER_MODIFY");
693 else
694 flowEntryObj.setUserState("FE_USER_ADD");
695 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
696 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800697 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800698 // and FlowEntryErrorState.
699 //
700
701 // Flow Entries edges:
702 // Flow
703 // NextFE
704 // InPort
705 // OutPort
706 // Switch
707 if (! found)
708 flowObj.addFlowEntry(flowEntryObj);
709 }
710 conn.endTx(Transaction.COMMIT);
711
712 //
713 // TODO: We need a proper Flow ID allocation mechanism.
714 //
715 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700716
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800717 return true;
718 }
719
720 /**
721 * Delete a previously added flow.
722 *
723 * @param flowId the Flow ID of the flow to delete.
724 * @return true on success, otherwise false.
725 */
726 @Override
727 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700728 if (flowId.value() == measurementFlowId) {
729 modifiedMeasurementFlowTime = System.nanoTime();
730 }
731
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800732 IFlowPath flowObj = null;
733 //
734 // We just mark the entries for deletion,
735 // and let the switches remove each individual entry after
736 // it has been removed from the switches.
737 //
738 try {
739 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
740 != null) {
741 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
742 flowId.toString());
743 } else {
744 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
745 flowId.toString());
746 }
747 } catch (Exception e) {
748 // TODO: handle exceptions
749 conn.endTx(Transaction.ROLLBACK);
750 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
751 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700752 if (flowObj == null) {
753 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800754 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700755 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800756
757 //
758 // Find and mark for deletion all Flow Entries
759 //
760 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
761 boolean empty = true; // TODO: an ugly hack
762 for (IFlowEntry flowEntryObj : flowEntries) {
763 empty = false;
764 // flowObj.removeFlowEntry(flowEntryObj);
765 // conn.utils().removeFlowEntry(conn, flowEntryObj);
766 flowEntryObj.setUserState("FE_USER_DELETE");
767 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
768 }
769 // Remove from the database empty flows
770 if (empty)
771 conn.utils().removeFlowPath(conn, flowObj);
772 conn.endTx(Transaction.COMMIT);
773
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800774 return true;
775 }
776
777 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700778 * Clear the state for a previously added flow.
779 *
780 * @param flowId the Flow ID of the flow to clear.
781 * @return true on success, otherwise false.
782 */
783 @Override
784 public boolean clearFlow(FlowId flowId) {
785 IFlowPath flowObj = null;
786 try {
787 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
788 != null) {
789 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
790 flowId.toString());
791 } else {
792 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
793 flowId.toString());
794 }
795 } catch (Exception e) {
796 // TODO: handle exceptions
797 conn.endTx(Transaction.ROLLBACK);
798 log.error(":clearFlow FlowId:{} failed", flowId.toString());
799 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700800 if (flowObj == null) {
801 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700802 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700803 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700804
805 //
806 // Remove all Flow Entries
807 //
808 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
809 for (IFlowEntry flowEntryObj : flowEntries) {
810 flowObj.removeFlowEntry(flowEntryObj);
811 conn.utils().removeFlowEntry(conn, flowEntryObj);
812 }
813 // Remove the Flow itself
814 conn.utils().removeFlowPath(conn, flowObj);
815 conn.endTx(Transaction.COMMIT);
816
817 return true;
818 }
819
820 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800821 * Get a previously added flow.
822 *
823 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800824 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800825 */
826 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800827 public FlowPath getFlow(FlowId flowId) {
828 IFlowPath flowObj = null;
829 try {
830 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
831 != null) {
832 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
833 flowId.toString());
834 } else {
835 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
836 flowId.toString());
837 }
838 } catch (Exception e) {
839 // TODO: handle exceptions
840 conn.endTx(Transaction.ROLLBACK);
841 log.error(":getFlow FlowId:{} failed", flowId.toString());
842 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700843 if (flowObj == null) {
844 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800845 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700846 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800847
848 //
849 // Extract the Flow state
850 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800851 FlowPath flowPath = extractFlowPath(flowObj);
852 conn.endTx(Transaction.COMMIT);
853
854 return flowPath;
855 }
856
857 /**
858 * Get all previously added flows by a specific installer for a given
859 * data path endpoints.
860 *
861 * @param installerId the Caller ID of the installer of the flow to get.
862 * @param dataPathEndpoints the data path endpoints of the flow to get.
863 * @return the Flow Paths if found, otherwise null.
864 */
865 @Override
866 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
867 DataPathEndpoints dataPathEndpoints) {
868 //
869 // TODO: The implementation below is not optimal:
870 // We fetch all flows, and then return only the subset that match
871 // the query conditions.
872 // We should use the appropriate Titan/Gremlin query to filter-out
873 // the flows as appropriate.
874 //
875 ArrayList<FlowPath> allFlows = getAllFlows();
876
877 if (allFlows == null) {
878 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
879 return null;
880 }
881
882 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
883 for (FlowPath flow : allFlows) {
884 //
885 // TODO: String-based comparison is sub-optimal.
886 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800887 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800888 //
889 if (! flow.installerId().toString().equals(installerId.toString()))
890 continue;
891 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
892 continue;
893 }
894 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
895 continue;
896 }
897 flowPaths.add(flow);
898 }
899
900 if (flowPaths.isEmpty()) {
901 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
902 flowPaths = null;
903 } else {
904 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
905 }
906
907 return flowPaths;
908 }
909
910 /**
911 * Get all installed flows by all installers for given data path endpoints.
912 *
913 * @param dataPathEndpoints the data path endpoints of the flows to get.
914 * @return the Flow Paths if found, otherwise null.
915 */
916 @Override
917 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
918 //
919 // TODO: The implementation below is not optimal:
920 // We fetch all flows, and then return only the subset that match
921 // the query conditions.
922 // We should use the appropriate Titan/Gremlin query to filter-out
923 // the flows as appropriate.
924 //
925 ArrayList<FlowPath> allFlows = getAllFlows();
926
927 if (allFlows == null) {
928 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
929 return null;
930 }
931
932 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
933 for (FlowPath flow : allFlows) {
934 //
935 // TODO: String-based comparison is sub-optimal.
936 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800937 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800938 //
939 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
940 continue;
941 }
942 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
943 continue;
944 }
945 flowPaths.add(flow);
946 }
947
948 if (flowPaths.isEmpty()) {
949 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
950 flowPaths = null;
951 } else {
952 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
953 }
954
955 return flowPaths;
956 }
957
958 /**
959 * Get all installed flows by all installers.
960 *
961 * @return the Flow Paths if found, otherwise null.
962 */
963 @Override
964 public ArrayList<FlowPath> getAllFlows() {
965 Iterable<IFlowPath> flowPathsObj = null;
966
967 try {
968 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
969 log.debug("Get all FlowPaths: found FlowPaths");
970 } else {
971 log.debug("Get all FlowPaths: no FlowPaths found");
972 }
973 } catch (Exception e) {
974 // TODO: handle exceptions
975 conn.endTx(Transaction.ROLLBACK);
976 log.error(":getAllFlowPaths failed");
977 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700978 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
979 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800980 return null; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700981 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800982
983 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
984 for (IFlowPath flowObj : flowPathsObj) {
985 //
986 // Extract the Flow state
987 //
988 FlowPath flowPath = extractFlowPath(flowObj);
989 flowPaths.add(flowPath);
990 }
991
992 conn.endTx(Transaction.COMMIT);
993
994 return flowPaths;
995 }
996
997 /**
998 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
999 *
1000 * @param flowObj the object to extract the Flow Path State from.
1001 * @return the extracted Flow Path State.
1002 */
1003 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001004 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001005
1006 //
1007 // Extract the Flow state
1008 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001009 flowPath.setFlowId(new FlowId(flowObj.getFlowId()));
1010 flowPath.setInstallerId(new CallerId(flowObj.getInstallerId()));
1011 flowPath.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
1012 flowPath.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
1013 flowPath.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
1014 flowPath.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
1015
1016 //
1017 // Extract all Flow Entries
1018 //
1019 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1020 for (IFlowEntry flowEntryObj : flowEntries) {
1021 FlowEntry flowEntry = new FlowEntry();
1022 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
1023 flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001024
1025 //
1026 // Extract the match conditions
1027 //
1028 FlowEntryMatch match = new FlowEntryMatch();
1029 Short matchInPort = flowEntryObj.getMatchInPort();
1030 if (matchInPort != null)
1031 match.enableInPort(new Port(matchInPort));
1032 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1033 if (matchEthernetFrameType != null)
1034 match.enableEthernetFrameType(matchEthernetFrameType);
1035 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1036 if (matchSrcIPv4Net != null)
1037 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1038 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1039 if (matchDstIPv4Net != null)
1040 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1041 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1042 if (matchSrcMac != null)
1043 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1044 String matchDstMac = flowEntryObj.getMatchDstMac();
1045 if (matchDstMac != null)
1046 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1047 flowEntry.setFlowEntryMatch(match);
1048
1049 //
1050 // Extract the actions
1051 //
1052 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1053 Short actionOutputPort = flowEntryObj.getActionOutput();
1054 if (actionOutputPort != null) {
1055 FlowEntryAction action = new FlowEntryAction();
1056 action.setActionOutput(new Port(actionOutputPort));
1057 actions.add(action);
1058 }
1059 flowEntry.setFlowEntryActions(actions);
1060
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001061 String userState = flowEntryObj.getUserState();
1062 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1063 String switchState = flowEntryObj.getSwitchState();
1064 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1065 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001066 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001067 // and FlowEntryErrorState.
1068 //
1069 flowPath.dataPath().flowEntries().add(flowEntry);
1070 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001071
1072 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001073 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001074}