blob: 320d11463085defb1fe379d78e36bb5f7ea95f7e [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;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00008import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08009import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080010import java.util.Map;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070011import java.util.TreeMap;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070012import java.util.Collections;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070013import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070015import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.ScheduledExecutorService;
17import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070018import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IFloodlightProviderService;
22import net.floodlightcontroller.core.INetMapStorage;
23import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
24import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070025import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080026import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080027import net.floodlightcontroller.core.module.FloodlightModuleContext;
28import net.floodlightcontroller.core.module.FloodlightModuleException;
29import net.floodlightcontroller.core.module.IFloodlightModule;
30import net.floodlightcontroller.core.module.IFloodlightService;
31import net.floodlightcontroller.flowcache.IFlowService;
32import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
33import net.floodlightcontroller.restserver.IRestApiService;
34import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080035import net.floodlightcontroller.util.DataPath;
36import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080037import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080038import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070039import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080040import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070041import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080042import net.floodlightcontroller.util.FlowEntrySwitchState;
43import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080044import net.floodlightcontroller.util.FlowId;
45import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070046import net.floodlightcontroller.util.IPv4Net;
47import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080048import net.floodlightcontroller.util.OFMessageDamper;
49import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070050import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080051import net.onrc.onos.util.GraphDBConnection;
52import net.onrc.onos.util.GraphDBConnection.Transaction;
53
54import org.openflow.protocol.OFFlowMod;
55import org.openflow.protocol.OFMatch;
56import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070057import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080058import org.openflow.protocol.OFType;
59import org.openflow.protocol.action.OFAction;
60import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080061
62import org.slf4j.Logger;
63import org.slf4j.LoggerFactory;
64
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080065public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
66
67 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080068
69 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070071 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072
73 protected OFMessageDamper messageDamper;
74
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070075 //
76 // TODO: Values copied from elsewhere (class LearningSwitch).
77 // The local copy should go away!
78 //
79 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
80 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
81 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
82 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
83 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080084
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070085 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070086 private static long measurementFlowId = 100000;
87 private static String measurementFlowIdStr = "0x186a0"; // 100000
88 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070089
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080090 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080091 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
92
93 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070094 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080095 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070096 private final ScheduledExecutorService measureMapReaderScheduler =
97 Executors.newScheduledThreadPool(1);
98 private final ScheduledExecutorService mapReaderScheduler =
99 Executors.newScheduledThreadPool(1);
100
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700101 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
102 private ThreadPoolExecutor shortestPathExecutor =
103 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
104
105 class ShortestPathTask implements Runnable {
106 private int hint;
107 private ITopoRouteService topoRouteService;
108 private ArrayList<DataPath> dpList;
109
110 public ShortestPathTask(int hint,
111 ITopoRouteService topoRouteService,
112 ArrayList<DataPath> dpList) {
113 this.hint = hint;
114 this.topoRouteService = topoRouteService;
115 this.dpList = dpList;
116 }
117
118 @Override
119 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700120 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700121 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
122 log.debug(logMsg);
123 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700124 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700125 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700126 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700127 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700128 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700129 long estimatedTime = System.nanoTime() - startTime;
130 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
131 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
132 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700133 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700134 }
135 }
136
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700137 final Runnable measureShortestPath = new Runnable() {
138 public void run() {
139 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
140 if (floodlightProvider == null) {
141 log.debug("FloodlightProvider service not found!");
142 return;
143 }
144
145 ITopoRouteService topoRouteService =
146 context.getServiceImpl(ITopoRouteService.class);
147 if (topoRouteService == null) {
148 log.debug("Topology Route Service not found");
149 return;
150 }
151
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700152 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
153 if (leftoverQueueSize > 0) {
154 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
155 log.debug(logMsg);
156 return;
157 }
158 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
159
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700160 //
161 // Recompute the Shortest Paths for all Flows
162 //
163 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700164 int hint = 0;
165 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700166 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700167
168 topoRouteService.prepareShortestPathTopo();
169
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700170 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
171 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700172 FlowId flowId = new FlowId(flowPathObj.getFlowId());
173
174 // log.debug("Found Path {}", flowId.toString());
175 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
176 Port srcPort = new Port(flowPathObj.getSrcPort());
177 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
178 Port dstPort = new Port(flowPathObj.getDstPort());
179 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
180 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700181
182 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700183 DataPath dp = new DataPath();
184 dp.setSrcPort(srcSwitchPort);
185 dp.setDstPort(dstSwitchPort);
186 dpList.add(dp);
187 if ((dpList.size() % 10) == 0) {
188 shortestPathExecutor.execute(
189 new ShortestPathTask(hint, topoRouteService,
190 dpList));
191 dpList = new ArrayList<DataPath>();
192 hint++;
193 }
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700194 */
195
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700196 DataPath dataPath =
197 topoRouteService.getTopoShortestPath(srcSwitchPort,
198 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700199 counter++;
200 }
201 if (dpList.size() > 0) {
202 shortestPathExecutor.execute(
203 new ShortestPathTask(hint, topoRouteService,
204 dpList));
205 }
206
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700207 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700208 // Wait for all tasks to finish
209 try {
210 while (shortestPathExecutor.getQueue().size() > 0) {
211 Thread.sleep(100);
212 }
213 } catch (InterruptedException ex) {
214 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700215 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700216 */
217
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700218 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700219 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700220
221 long estimatedTime = System.nanoTime() - startTime;
222 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
223 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
224 log.debug(logMsg);
225 }
226 };
227
228 final Runnable measureMapReader = new Runnable() {
229 public void run() {
230 if (floodlightProvider == null) {
231 log.debug("FloodlightProvider service not found!");
232 return;
233 }
234
235 //
236 // Fetch all Flow Entries
237 //
238 int counter = 0;
239 long startTime = System.nanoTime();
240 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
241 for (IFlowEntry flowEntryObj : allFlowEntries) {
242 counter++;
243 FlowEntryId flowEntryId =
244 new FlowEntryId(flowEntryObj.getFlowEntryId());
245 String userState = flowEntryObj.getUserState();
246 String switchState = flowEntryObj.getSwitchState();
247 }
248 conn.endTx(Transaction.COMMIT);
249
250 long estimatedTime = System.nanoTime() - startTime;
251 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
252 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
253 log.debug(logMsg);
254 }
255 };
256
257 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800258 public void run() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800259 if (floodlightProvider == null) {
260 log.debug("FloodlightProvider service not found!");
261 return;
262 }
263
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000264 Map<Long, IOFSwitch> mySwitches =
265 floodlightProvider.getSwitches();
266 Map<Long, IFlowEntry> myFlowEntries =
267 new TreeMap<Long, IFlowEntry>();
268 LinkedList<IFlowEntry> deleteFlowEntries =
269 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700270
271 //
272 // Fetch all Flow Entries and select only my Flow Entries
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000273 // that need to be undated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700274 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000275 Iterable<IFlowEntry> allFlowEntries =
276 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700277 for (IFlowEntry flowEntryObj : allFlowEntries) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000278 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700279 String userState = flowEntryObj.getUserState();
280 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000281 String dpidStr = flowEntryObj.getSwitchDpid();
282 if ((flowEntryIdStr == null) ||
283 (userState == null) ||
284 (switchState == null) ||
285 (dpidStr == null)) {
286 log.debug("IGNORING Flow Entry entry with null fields");
287 continue;
288 }
289 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
290 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800291
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000292 /*
293 log.debug("Found Flow Entry Id = {} {}",
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700294 flowEntryId.toString(),
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000295 "DPID = " + dpid.toString() +
296 " User State: " + userState +
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700297 " Switch State: " + switchState);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000298 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800299
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000300 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
301 continue; // Ignore the entry: nothing to do
302
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800303 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000304 if (mySwitch == null)
305 continue; // Ignore the entry: not my switch
306
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700307 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
308 }
309
310 //
311 // Process my Flow Entries
312 //
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700313 Boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700314 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
315 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700316 // Code for measurement purpose
317 {
318 IFlowPath flowObj =
319 conn.utils().getFlowPathByFlowEntry(conn,
320 flowEntryObj);
321 if ((flowObj != null) &&
322 flowObj.getFlowId().equals(measurementFlowIdStr)) {
323 processed_measurement_flow = true;
324 }
325 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700326
327 //
328 // TODO: Eliminate the re-fetching of flowEntryId,
329 // userState, switchState, and dpid from the flowEntryObj.
330 //
331 FlowEntryId flowEntryId =
332 new FlowEntryId(flowEntryObj.getFlowEntryId());
333 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
334 String userState = flowEntryObj.getUserState();
335 String switchState = flowEntryObj.getSwitchState();
336 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000337 if (mySwitch == null)
338 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800339
340 //
341 // Create the Open Flow Flow Modification Entry to push
342 //
343 OFFlowMod fm =
344 (OFFlowMod) floodlightProvider.getOFMessageFactory()
345 .getMessage(OFType.FLOW_MOD);
346 long cookie = flowEntryId.value();
347
348 short flowModCommand = OFFlowMod.OFPFC_ADD;
349 if (userState.equals("FE_USER_ADD")) {
350 flowModCommand = OFFlowMod.OFPFC_ADD;
351 } else if (userState.equals("FE_USER_MODIFY")) {
352 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
353 } else if (userState.equals("FE_USER_DELETE")) {
354 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
355 } else {
356 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700357 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
358 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800359 continue;
360 }
361
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700362 //
363 // Fetch the match conditions
364 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800365 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700366 match.setWildcards(OFMatch.OFPFW_ALL);
367 Short matchInPort = flowEntryObj.getMatchInPort();
368 if (matchInPort != null) {
369 match.setInputPort(matchInPort);
370 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
371 }
372 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
373 if (matchEthernetFrameType != null) {
374 match.setDataLayerType(matchEthernetFrameType);
375 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
376 }
377 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
378 if (matchSrcIPv4Net != null) {
379 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
380 }
381 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
382 if (matchDstIPv4Net != null) {
383 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
384 }
385 String matchSrcMac = flowEntryObj.getMatchSrcMac();
386 if (matchSrcMac != null) {
387 match.setDataLayerSource(matchSrcMac);
388 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
389 }
390 String matchDstMac = flowEntryObj.getMatchDstMac();
391 if (matchDstMac != null) {
392 match.setDataLayerDestination(matchDstMac);
393 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
394 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700395
396 //
397 // Fetch the actions
398 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800399 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700400 Short actionOutputPort = flowEntryObj.getActionOutput();
401 if (actionOutputPort != null) {
402 OFActionOutput action = new OFActionOutput();
403 // XXX: The max length is hard-coded for now
404 action.setMaxLength((short)0xffff);
405 action.setPort(actionOutputPort);
406 actions.add(action);
407 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800408
409 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
410 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700411 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800412 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
413 .setCookie(cookie)
414 .setCommand(flowModCommand)
415 .setMatch(match)
416 .setActions(actions)
417 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700418 fm.setOutPort(OFPort.OFPP_NONE.getValue());
419 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
420 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
421 if (actionOutputPort != null)
422 fm.setOutPort(actionOutputPort);
423 }
424
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800425 //
426 // TODO: Set the following flag
427 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
428 // See method ForwardingBase::pushRoute()
429 //
430 try {
431 messageDamper.write(mySwitch, fm, null);
432 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000433 //
434 // TODO: We should use the OpenFlow Barrier mechanism
435 // to check for errors, and update the SwitchState
436 // for a flow entry after the Barrier message is
437 // is received.
438 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800439 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
440 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000441 // An entry that needs to be deleted.
442 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800443 }
444 } catch (IOException e) {
445 log.error("Failure writing flow mod from network map", e);
446 }
447 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000448
449 //
450 // Delete all entries marked for deletion
451 //
452 // TODO: We should use the OpenFlow Barrier mechanism
453 // to check for errors, and delete the Flow Entries after the
454 // Barrier message is received.
455 //
456 while (! deleteFlowEntries.isEmpty()) {
457 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
458 IFlowPath flowObj =
459 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
460 if (flowObj == null) {
461 log.debug("Did not find FlowPath to be deleted");
462 continue;
463 }
464 flowObj.removeFlowEntry(flowEntryObj);
465 conn.utils().removeFlowEntry(conn, flowEntryObj);
466
467 // Test whether the last flow entry
468 Iterable<IFlowEntry> tmpflowEntries =
469 flowObj.getFlowEntries();
470 boolean found = false;
471 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
472 found = true;
473 break;
474 }
475 if (! found) {
476 // Remove the Flow Path as well
477 conn.utils().removeFlowPath(conn, flowObj);
478 }
479 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800480 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700481
482 if (processed_measurement_flow) {
483 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
484 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
485 (double)estimatedTime / 1000000000 + " sec";
486 log.debug(logMsg);
487 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800488 }
489 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700490
491 /*
492 final ScheduledFuture<?> measureShortestPathHandle =
493 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
494 */
495
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700496 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700497 final ScheduledFuture<?> measureMapReaderHandle =
498 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700499 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700500
501 final ScheduledFuture<?> mapReaderHandle =
502 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800503
504 @Override
505 public void init(String conf) {
506 conn = GraphDBConnection.getInstance(conf);
507 }
508
509 public void finalize() {
510 close();
511 }
512
513 @Override
514 public void close() {
515 conn.close();
516 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800517
518 @Override
519 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
520 Collection<Class<? extends IFloodlightService>> l =
521 new ArrayList<Class<? extends IFloodlightService>>();
522 l.add(IFlowService.class);
523 return l;
524 }
525
526 @Override
527 public Map<Class<? extends IFloodlightService>, IFloodlightService>
528 getServiceImpls() {
529 Map<Class<? extends IFloodlightService>,
530 IFloodlightService> m =
531 new HashMap<Class<? extends IFloodlightService>,
532 IFloodlightService>();
533 m.put(IFlowService.class, this);
534 return m;
535 }
536
537 @Override
538 public Collection<Class<? extends IFloodlightService>>
539 getModuleDependencies() {
540 Collection<Class<? extends IFloodlightService>> l =
541 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800542 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800543 l.add(IRestApiService.class);
544 return l;
545 }
546
547 @Override
548 public void init(FloodlightModuleContext context)
549 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700550 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800551 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800552 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800553 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
554 EnumSet.of(OFType.FLOW_MOD),
555 OFMESSAGE_DAMPER_TIMEOUT);
556 // TODO: An ugly hack!
557 String conf = "/tmp/cassandra.titan";
558 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800559 }
560
561 @Override
562 public void startUp(FloodlightModuleContext context) {
563 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700564
565 //
566 // Extract all flow entries and assign the next Flow Entry ID
567 // to be larger than the largest Flow Entry ID
568 //
569 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
570 for (IFlowEntry flowEntryObj : allFlowEntries) {
571 FlowEntryId flowEntryId =
572 new FlowEntryId(flowEntryObj.getFlowEntryId());
573 if (flowEntryId.value() >= nextFlowEntryId)
574 nextFlowEntryId = flowEntryId.value() + 1;
575 }
576 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800577 }
578
579 /**
580 * Add a flow.
581 *
582 * Internally, ONOS will automatically register the installer for
583 * receiving Flow Path Notifications for that path.
584 *
585 * @param flowPath the Flow Path to install.
586 * @param flowId the return-by-reference Flow ID as assigned internally.
587 * @return true on success, otherwise false.
588 */
589 @Override
590 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700591 if (flowPath.flowId().value() == measurementFlowId) {
592 modifiedMeasurementFlowTime = System.nanoTime();
593 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800594
595 //
596 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700597 // Right now every new flow entry gets a new flow entry ID
598 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800599 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800600 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700601 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800602 flowEntry.setFlowEntryId(new FlowEntryId(id));
603 }
604
605 IFlowPath flowObj = null;
606 try {
607 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
608 != null) {
609 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
610 flowPath.flowId().toString());
611 } else {
612 flowObj = conn.utils().newFlowPath(conn);
613 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
614 flowPath.flowId().toString());
615 }
616 } catch (Exception e) {
617 // TODO: handle exceptions
618 conn.endTx(Transaction.ROLLBACK);
619 log.error(":addFlow FlowId:{} failed",
620 flowPath.flowId().toString());
621 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700622 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000623 log.error(":addFlow FlowId:{} failed: Flow object not created",
624 flowPath.flowId().toString());
625 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800626 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700627 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800628
629 //
630 // Set the Flow key:
631 // - flowId
632 //
633 flowObj.setFlowId(flowPath.flowId().toString());
634 flowObj.setType("flow");
635
636 //
637 // Set the Flow attributes:
638 // - flowPath.installerId()
639 // - flowPath.dataPath().srcPort()
640 // - flowPath.dataPath().dstPort()
641 //
642 flowObj.setInstallerId(flowPath.installerId().toString());
643 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
644 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
645 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
646 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
647
648 // Flow edges:
649 // HeadFE
650
651
652 //
653 // Flow Entries:
654 // flowPath.dataPath().flowEntries()
655 //
656 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
657 IFlowEntry flowEntryObj = null;
658 boolean found = false;
659 try {
660 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
661 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
662 flowEntry.flowEntryId().toString());
663 found = true;
664 } else {
665 flowEntryObj = conn.utils().newFlowEntry(conn);
666 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
667 flowEntry.flowEntryId().toString());
668 }
669 } catch (Exception e) {
670 // TODO: handle exceptions
671 conn.endTx(Transaction.ROLLBACK);
672 log.error(":addFlow FlowEntryId:{} failed",
673 flowEntry.flowEntryId().toString());
674 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700675 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000676 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
677 flowEntry.flowEntryId().toString());
678 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800679 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700680 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800681
682 //
683 // Set the Flow Entry key:
684 // - flowEntry.flowEntryId()
685 //
686 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
687 flowEntryObj.setType("flow_entry");
688
689 //
690 // Set the Flow Entry attributes:
691 // - flowEntry.flowEntryMatch()
692 // - flowEntry.flowEntryActions()
693 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800694 // - flowEntry.flowEntryUserState()
695 // - flowEntry.flowEntrySwitchState()
696 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700697 // - flowEntry.matchInPort()
698 // - flowEntry.matchEthernetFrameType()
699 // - flowEntry.matchSrcIPv4Net()
700 // - flowEntry.matchDstIPv4Net()
701 // - flowEntry.matchSrcMac()
702 // - flowEntry.matchDstMac()
703 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800704 //
705 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700706 if (flowEntry.flowEntryMatch().matchInPort())
707 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
708 if (flowEntry.flowEntryMatch().matchEthernetFrameType())
709 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
710 if (flowEntry.flowEntryMatch().matchSrcIPv4Net())
711 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
712 if (flowEntry.flowEntryMatch().matchDstIPv4Net())
713 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
714 if (flowEntry.flowEntryMatch().matchSrcMac())
715 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
716 if (flowEntry.flowEntryMatch().matchDstMac())
717 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
718
719 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
720 if (fa.actionOutput() != null)
721 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
722 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800723 // TODO: Hacks with hard-coded state names!
724 if (found)
725 flowEntryObj.setUserState("FE_USER_MODIFY");
726 else
727 flowEntryObj.setUserState("FE_USER_ADD");
728 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
729 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800730 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800731 // and FlowEntryErrorState.
732 //
733
734 // Flow Entries edges:
735 // Flow
736 // NextFE
737 // InPort
738 // OutPort
739 // Switch
740 if (! found)
741 flowObj.addFlowEntry(flowEntryObj);
742 }
743 conn.endTx(Transaction.COMMIT);
744
745 //
746 // TODO: We need a proper Flow ID allocation mechanism.
747 //
748 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700749
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800750 return true;
751 }
752
753 /**
754 * Delete a previously added flow.
755 *
756 * @param flowId the Flow ID of the flow to delete.
757 * @return true on success, otherwise false.
758 */
759 @Override
760 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700761 if (flowId.value() == measurementFlowId) {
762 modifiedMeasurementFlowTime = System.nanoTime();
763 }
764
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800765 IFlowPath flowObj = null;
766 //
767 // We just mark the entries for deletion,
768 // and let the switches remove each individual entry after
769 // it has been removed from the switches.
770 //
771 try {
772 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
773 != null) {
774 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
775 flowId.toString());
776 } else {
777 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
778 flowId.toString());
779 }
780 } catch (Exception e) {
781 // TODO: handle exceptions
782 conn.endTx(Transaction.ROLLBACK);
783 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
784 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700785 if (flowObj == null) {
786 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800787 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700788 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800789
790 //
791 // Find and mark for deletion all Flow Entries
792 //
793 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
794 boolean empty = true; // TODO: an ugly hack
795 for (IFlowEntry flowEntryObj : flowEntries) {
796 empty = false;
797 // flowObj.removeFlowEntry(flowEntryObj);
798 // conn.utils().removeFlowEntry(conn, flowEntryObj);
799 flowEntryObj.setUserState("FE_USER_DELETE");
800 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
801 }
802 // Remove from the database empty flows
803 if (empty)
804 conn.utils().removeFlowPath(conn, flowObj);
805 conn.endTx(Transaction.COMMIT);
806
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800807 return true;
808 }
809
810 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700811 * Clear the state for a previously added flow.
812 *
813 * @param flowId the Flow ID of the flow to clear.
814 * @return true on success, otherwise false.
815 */
816 @Override
817 public boolean clearFlow(FlowId flowId) {
818 IFlowPath flowObj = null;
819 try {
820 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
821 != null) {
822 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
823 flowId.toString());
824 } else {
825 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
826 flowId.toString());
827 }
828 } catch (Exception e) {
829 // TODO: handle exceptions
830 conn.endTx(Transaction.ROLLBACK);
831 log.error(":clearFlow FlowId:{} failed", flowId.toString());
832 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700833 if (flowObj == null) {
834 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700835 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700836 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700837
838 //
839 // Remove all Flow Entries
840 //
841 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
842 for (IFlowEntry flowEntryObj : flowEntries) {
843 flowObj.removeFlowEntry(flowEntryObj);
844 conn.utils().removeFlowEntry(conn, flowEntryObj);
845 }
846 // Remove the Flow itself
847 conn.utils().removeFlowPath(conn, flowObj);
848 conn.endTx(Transaction.COMMIT);
849
850 return true;
851 }
852
853 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800854 * Get a previously added flow.
855 *
856 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800857 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800858 */
859 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800860 public FlowPath getFlow(FlowId flowId) {
861 IFlowPath flowObj = null;
862 try {
863 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
864 != null) {
865 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
866 flowId.toString());
867 } else {
868 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
869 flowId.toString());
870 }
871 } catch (Exception e) {
872 // TODO: handle exceptions
873 conn.endTx(Transaction.ROLLBACK);
874 log.error(":getFlow FlowId:{} failed", flowId.toString());
875 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700876 if (flowObj == null) {
877 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800878 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700879 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800880
881 //
882 // Extract the Flow state
883 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800884 FlowPath flowPath = extractFlowPath(flowObj);
885 conn.endTx(Transaction.COMMIT);
886
887 return flowPath;
888 }
889
890 /**
891 * Get all previously added flows by a specific installer for a given
892 * data path endpoints.
893 *
894 * @param installerId the Caller ID of the installer of the flow to get.
895 * @param dataPathEndpoints the data path endpoints of the flow to get.
896 * @return the Flow Paths if found, otherwise null.
897 */
898 @Override
899 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
900 DataPathEndpoints dataPathEndpoints) {
901 //
902 // TODO: The implementation below is not optimal:
903 // We fetch all flows, and then return only the subset that match
904 // the query conditions.
905 // We should use the appropriate Titan/Gremlin query to filter-out
906 // the flows as appropriate.
907 //
908 ArrayList<FlowPath> allFlows = getAllFlows();
909
910 if (allFlows == null) {
911 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
912 return null;
913 }
914
915 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
916 for (FlowPath flow : allFlows) {
917 //
918 // TODO: String-based comparison is sub-optimal.
919 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800920 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800921 //
922 if (! flow.installerId().toString().equals(installerId.toString()))
923 continue;
924 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
925 continue;
926 }
927 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
928 continue;
929 }
930 flowPaths.add(flow);
931 }
932
933 if (flowPaths.isEmpty()) {
934 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
935 flowPaths = null;
936 } else {
937 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
938 }
939
940 return flowPaths;
941 }
942
943 /**
944 * Get all installed flows by all installers for given data path endpoints.
945 *
946 * @param dataPathEndpoints the data path endpoints of the flows to get.
947 * @return the Flow Paths if found, otherwise null.
948 */
949 @Override
950 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
951 //
952 // TODO: The implementation below is not optimal:
953 // We fetch all flows, and then return only the subset that match
954 // the query conditions.
955 // We should use the appropriate Titan/Gremlin query to filter-out
956 // the flows as appropriate.
957 //
958 ArrayList<FlowPath> allFlows = getAllFlows();
959
960 if (allFlows == null) {
961 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
962 return null;
963 }
964
965 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
966 for (FlowPath flow : allFlows) {
967 //
968 // TODO: String-based comparison is sub-optimal.
969 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800970 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800971 //
972 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
973 continue;
974 }
975 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
976 continue;
977 }
978 flowPaths.add(flow);
979 }
980
981 if (flowPaths.isEmpty()) {
982 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
983 flowPaths = null;
984 } else {
985 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
986 }
987
988 return flowPaths;
989 }
990
991 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700992 * Get summary of all installed flows by all installers in a given range
993 *
994 * @param flowId the data path endpoints of the flows to get.
995 * @param maxFlows: the maximum number of flows to be returned
996 * @return the Flow Paths if found, otherwise null.
997 */
998 @Override
999 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1000 //
1001 // TODO: The implementation below is not optimal:
1002 // We fetch all flows, and then return only the subset that match
1003 // the query conditions.
1004 // We should use the appropriate Titan/Gremlin query to filter-out
1005 // the flows as appropriate.
1006 //
1007 ArrayList<FlowPath> allFlows = getAllFlows();
1008
1009 if (allFlows == null) {
1010 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
1011 return null;
1012 }
1013
1014 Collections.sort(allFlows);
1015
1016 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1017 for (FlowPath flow : allFlows) {
1018
1019 // start from desired flowId
1020 if (flow.flowId().value() < flowId.value()) {
1021 continue;
1022 }
1023
1024 // Summarize by making null flow entry fields that are not relevant to report
1025 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1026 flowEntry.setFlowEntryActions(null);
1027 flowEntry.setFlowEntryMatch(null);
1028 }
1029
1030 flowPaths.add(flow);
1031 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1032 break;
1033 }
1034 }
1035
1036 if (flowPaths.isEmpty()) {
1037 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
1038 flowPaths = null;
1039 } else {
1040 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1041 }
1042
1043 return flowPaths;
1044 }
1045
1046 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001047 * Get all installed flows by all installers.
1048 *
1049 * @return the Flow Paths if found, otherwise null.
1050 */
1051 @Override
1052 public ArrayList<FlowPath> getAllFlows() {
1053 Iterable<IFlowPath> flowPathsObj = null;
1054
1055 try {
1056 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1057 log.debug("Get all FlowPaths: found FlowPaths");
1058 } else {
1059 log.debug("Get all FlowPaths: no FlowPaths found");
1060 }
1061 } catch (Exception e) {
1062 // TODO: handle exceptions
1063 conn.endTx(Transaction.ROLLBACK);
1064 log.error(":getAllFlowPaths failed");
1065 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001066 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1067 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001068 return null; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001069 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001070
1071 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1072 for (IFlowPath flowObj : flowPathsObj) {
1073 //
1074 // Extract the Flow state
1075 //
1076 FlowPath flowPath = extractFlowPath(flowObj);
1077 flowPaths.add(flowPath);
1078 }
1079
1080 conn.endTx(Transaction.COMMIT);
1081
1082 return flowPaths;
1083 }
1084
1085 /**
1086 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1087 *
1088 * @param flowObj the object to extract the Flow Path State from.
1089 * @return the extracted Flow Path State.
1090 */
1091 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001092 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001093
1094 //
1095 // Extract the Flow state
1096 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001097 flowPath.setFlowId(new FlowId(flowObj.getFlowId()));
1098 flowPath.setInstallerId(new CallerId(flowObj.getInstallerId()));
1099 flowPath.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
1100 flowPath.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
1101 flowPath.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
1102 flowPath.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
1103
1104 //
1105 // Extract all Flow Entries
1106 //
1107 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1108 for (IFlowEntry flowEntryObj : flowEntries) {
1109 FlowEntry flowEntry = new FlowEntry();
1110 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
1111 flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001112
1113 //
1114 // Extract the match conditions
1115 //
1116 FlowEntryMatch match = new FlowEntryMatch();
1117 Short matchInPort = flowEntryObj.getMatchInPort();
1118 if (matchInPort != null)
1119 match.enableInPort(new Port(matchInPort));
1120 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1121 if (matchEthernetFrameType != null)
1122 match.enableEthernetFrameType(matchEthernetFrameType);
1123 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1124 if (matchSrcIPv4Net != null)
1125 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1126 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1127 if (matchDstIPv4Net != null)
1128 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1129 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1130 if (matchSrcMac != null)
1131 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1132 String matchDstMac = flowEntryObj.getMatchDstMac();
1133 if (matchDstMac != null)
1134 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1135 flowEntry.setFlowEntryMatch(match);
1136
1137 //
1138 // Extract the actions
1139 //
1140 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1141 Short actionOutputPort = flowEntryObj.getActionOutput();
1142 if (actionOutputPort != null) {
1143 FlowEntryAction action = new FlowEntryAction();
1144 action.setActionOutput(new Port(actionOutputPort));
1145 actions.add(action);
1146 }
1147 flowEntry.setFlowEntryActions(actions);
1148
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001149 String userState = flowEntryObj.getUserState();
1150 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1151 String switchState = flowEntryObj.getSwitchState();
1152 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1153 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001154 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001155 // and FlowEntryErrorState.
1156 //
1157 flowPath.dataPath().flowEntries().add(flowEntry);
1158 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001159
1160 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001161 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001162}