blob: a0c1635cd3711e8b4f1d95a79e4d37df2a371c5b [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;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070011import java.util.Collections;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070012import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070014import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import java.util.concurrent.ScheduledExecutorService;
16import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070017import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080018import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080019
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080020import net.floodlightcontroller.core.IFloodlightProviderService;
21import net.floodlightcontroller.core.INetMapStorage;
22import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
23import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070024import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080025import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080026import net.floodlightcontroller.core.module.FloodlightModuleContext;
27import net.floodlightcontroller.core.module.FloodlightModuleException;
28import net.floodlightcontroller.core.module.IFloodlightModule;
29import net.floodlightcontroller.core.module.IFloodlightService;
30import net.floodlightcontroller.flowcache.IFlowService;
31import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
32import net.floodlightcontroller.restserver.IRestApiService;
33import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080034import net.floodlightcontroller.util.DataPath;
35import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080036import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080037import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070038import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070040import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.FlowEntrySwitchState;
42import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080043import net.floodlightcontroller.util.FlowId;
44import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070045import net.floodlightcontroller.util.IPv4Net;
46import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080047import net.floodlightcontroller.util.OFMessageDamper;
48import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070049import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080050import net.onrc.onos.util.GraphDBConnection;
51import net.onrc.onos.util.GraphDBConnection.Transaction;
52
53import org.openflow.protocol.OFFlowMod;
54import org.openflow.protocol.OFMatch;
55import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070056import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080057import org.openflow.protocol.OFType;
58import org.openflow.protocol.action.OFAction;
59import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080060
61import org.slf4j.Logger;
62import org.slf4j.LoggerFactory;
63
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080064public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
65
66 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080067
68 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080069 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070070 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071
72 protected OFMessageDamper messageDamper;
73
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070074 //
75 // TODO: Values copied from elsewhere (class LearningSwitch).
76 // The local copy should go away!
77 //
78 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
79 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
80 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
81 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
82 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080083
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070084 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070085 private static long measurementFlowId = 100000;
86 private static String measurementFlowIdStr = "0x186a0"; // 100000
87 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070088
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080089 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080090 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
91
92 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070093 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080094 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070095 private final ScheduledExecutorService measureMapReaderScheduler =
96 Executors.newScheduledThreadPool(1);
97 private final ScheduledExecutorService mapReaderScheduler =
98 Executors.newScheduledThreadPool(1);
99
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700100 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
101 private ThreadPoolExecutor shortestPathExecutor =
102 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
103
104 class ShortestPathTask implements Runnable {
105 private int hint;
106 private ITopoRouteService topoRouteService;
107 private ArrayList<DataPath> dpList;
108
109 public ShortestPathTask(int hint,
110 ITopoRouteService topoRouteService,
111 ArrayList<DataPath> dpList) {
112 this.hint = hint;
113 this.topoRouteService = topoRouteService;
114 this.dpList = dpList;
115 }
116
117 @Override
118 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700119 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700120 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
121 log.debug(logMsg);
122 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700123 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700124 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700125 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700126 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700127 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700128 long estimatedTime = System.nanoTime() - startTime;
129 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
130 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
131 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700132 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700133 }
134 }
135
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700136 final Runnable measureShortestPath = new Runnable() {
137 public void run() {
138 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
139 if (floodlightProvider == null) {
140 log.debug("FloodlightProvider service not found!");
141 return;
142 }
143
144 ITopoRouteService topoRouteService =
145 context.getServiceImpl(ITopoRouteService.class);
146 if (topoRouteService == null) {
147 log.debug("Topology Route Service not found");
148 return;
149 }
150
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700151 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
152 if (leftoverQueueSize > 0) {
153 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
154 log.debug(logMsg);
155 return;
156 }
157 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
158
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700159 //
160 // Recompute the Shortest Paths for all Flows
161 //
162 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700163 int hint = 0;
164 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700165 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700166
167 topoRouteService.prepareShortestPathTopo();
168
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700169 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
170 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700171 FlowId flowId = new FlowId(flowPathObj.getFlowId());
172
173 // log.debug("Found Path {}", flowId.toString());
174 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
175 Port srcPort = new Port(flowPathObj.getSrcPort());
176 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
177 Port dstPort = new Port(flowPathObj.getDstPort());
178 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
179 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700180
181 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700182 DataPath dp = new DataPath();
183 dp.setSrcPort(srcSwitchPort);
184 dp.setDstPort(dstSwitchPort);
185 dpList.add(dp);
186 if ((dpList.size() % 10) == 0) {
187 shortestPathExecutor.execute(
188 new ShortestPathTask(hint, topoRouteService,
189 dpList));
190 dpList = new ArrayList<DataPath>();
191 hint++;
192 }
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700193 */
194
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700195 DataPath dataPath =
196 topoRouteService.getTopoShortestPath(srcSwitchPort,
197 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700198 counter++;
199 }
200 if (dpList.size() > 0) {
201 shortestPathExecutor.execute(
202 new ShortestPathTask(hint, topoRouteService,
203 dpList));
204 }
205
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700206 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700207 // Wait for all tasks to finish
208 try {
209 while (shortestPathExecutor.getQueue().size() > 0) {
210 Thread.sleep(100);
211 }
212 } catch (InterruptedException ex) {
213 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700214 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700215 */
216
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700217 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700218 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700219
220 long estimatedTime = System.nanoTime() - startTime;
221 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
222 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
223 log.debug(logMsg);
224 }
225 };
226
227 final Runnable measureMapReader = new Runnable() {
228 public void run() {
229 if (floodlightProvider == null) {
230 log.debug("FloodlightProvider service not found!");
231 return;
232 }
233
234 //
235 // Fetch all Flow Entries
236 //
237 int counter = 0;
238 long startTime = System.nanoTime();
239 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
240 for (IFlowEntry flowEntryObj : allFlowEntries) {
241 counter++;
242 FlowEntryId flowEntryId =
243 new FlowEntryId(flowEntryObj.getFlowEntryId());
244 String userState = flowEntryObj.getUserState();
245 String switchState = flowEntryObj.getSwitchState();
246 }
247 conn.endTx(Transaction.COMMIT);
248
249 long estimatedTime = System.nanoTime() - startTime;
250 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
251 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
252 log.debug(logMsg);
253 }
254 };
255
256 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800257 public void run() {
258 // log.debug("Reading Flow Entries from the Network Map...");
259 if (floodlightProvider == null) {
260 log.debug("FloodlightProvider service not found!");
261 return;
262 }
263
264 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
265
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700266 Map<Long, IFlowEntry> myFlowEntries = new TreeMap<Long, IFlowEntry>();
267
268 //
269 // Fetch all Flow Entries and select only my Flow Entries
270 //
271 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
272 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800273 FlowEntryId flowEntryId =
274 new FlowEntryId(flowEntryObj.getFlowEntryId());
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700275 String userState = flowEntryObj.getUserState();
276 String switchState = flowEntryObj.getSwitchState();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800277
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700278 /**
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700279 log.debug("Found Flow Entry {}: {}",
280 flowEntryId.toString(),
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700281 "User State: " + userState +
282 " Switch State: " + switchState);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700283 */
284
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800285 if (! switchState.equals("FE_SWITCH_NOT_UPDATED")) {
286 // Ignore the entry: nothing to do
287 continue;
288 }
289
290 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
291 IOFSwitch mySwitch = mySwitches.get(dpid.value());
292 if (mySwitch == null) {
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700293 log.debug("Flow Entry ignored: not my switch (FlowEntryId = {} DPID = {})", flowEntryId.toString(), dpid.toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800294 continue;
295 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700296 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
297 }
298
299 //
300 // Process my Flow Entries
301 //
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700302 Boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700303 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
304 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700305 // Code for measurement purpose
306 {
307 IFlowPath flowObj =
308 conn.utils().getFlowPathByFlowEntry(conn,
309 flowEntryObj);
310 if ((flowObj != null) &&
311 flowObj.getFlowId().equals(measurementFlowIdStr)) {
312 processed_measurement_flow = true;
313 }
314 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700315
316 //
317 // TODO: Eliminate the re-fetching of flowEntryId,
318 // userState, switchState, and dpid from the flowEntryObj.
319 //
320 FlowEntryId flowEntryId =
321 new FlowEntryId(flowEntryObj.getFlowEntryId());
322 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
323 String userState = flowEntryObj.getUserState();
324 String switchState = flowEntryObj.getSwitchState();
325 IOFSwitch mySwitch = mySwitches.get(dpid.value());
326 if (mySwitch == null) {
327 log.debug("Flow Entry ignored: not my switch");
328 continue;
329 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800330
331 //
332 // Create the Open Flow Flow Modification Entry to push
333 //
334 OFFlowMod fm =
335 (OFFlowMod) floodlightProvider.getOFMessageFactory()
336 .getMessage(OFType.FLOW_MOD);
337 long cookie = flowEntryId.value();
338
339 short flowModCommand = OFFlowMod.OFPFC_ADD;
340 if (userState.equals("FE_USER_ADD")) {
341 flowModCommand = OFFlowMod.OFPFC_ADD;
342 } else if (userState.equals("FE_USER_MODIFY")) {
343 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
344 } else if (userState.equals("FE_USER_DELETE")) {
345 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
346 } else {
347 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700348 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
349 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800350 continue;
351 }
352
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700353 //
354 // Fetch the match conditions
355 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800356 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700357 match.setWildcards(OFMatch.OFPFW_ALL);
358 Short matchInPort = flowEntryObj.getMatchInPort();
359 if (matchInPort != null) {
360 match.setInputPort(matchInPort);
361 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
362 }
363 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
364 if (matchEthernetFrameType != null) {
365 match.setDataLayerType(matchEthernetFrameType);
366 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
367 }
368 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
369 if (matchSrcIPv4Net != null) {
370 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
371 }
372 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
373 if (matchDstIPv4Net != null) {
374 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
375 }
376 String matchSrcMac = flowEntryObj.getMatchSrcMac();
377 if (matchSrcMac != null) {
378 match.setDataLayerSource(matchSrcMac);
379 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
380 }
381 String matchDstMac = flowEntryObj.getMatchDstMac();
382 if (matchDstMac != null) {
383 match.setDataLayerDestination(matchDstMac);
384 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
385 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700386
387 //
388 // Fetch the actions
389 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800390 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700391 Short actionOutputPort = flowEntryObj.getActionOutput();
392 if (actionOutputPort != null) {
393 OFActionOutput action = new OFActionOutput();
394 // XXX: The max length is hard-coded for now
395 action.setMaxLength((short)0xffff);
396 action.setPort(actionOutputPort);
397 actions.add(action);
398 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800399
400 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
401 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700402 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800403 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
404 .setCookie(cookie)
405 .setCommand(flowModCommand)
406 .setMatch(match)
407 .setActions(actions)
408 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700409 fm.setOutPort(OFPort.OFPP_NONE.getValue());
410 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
411 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
412 if (actionOutputPort != null)
413 fm.setOutPort(actionOutputPort);
414 }
415
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800416 //
417 // TODO: Set the following flag
418 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
419 // See method ForwardingBase::pushRoute()
420 //
421 try {
422 messageDamper.write(mySwitch, fm, null);
423 mySwitch.flush();
424 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
425 if (userState.equals("FE_USER_DELETE")) {
426 // Delete the entry
427 IFlowPath flowObj = null;
428 flowObj = conn.utils().getFlowPathByFlowEntry(conn,
429 flowEntryObj);
430 if (flowObj != null)
431 log.debug("Found FlowPath to be deleted");
432 else
433 log.debug("Did not find FlowPath to be deleted");
434 flowObj.removeFlowEntry(flowEntryObj);
435 conn.utils().removeFlowEntry(conn, flowEntryObj);
436
437 // Test whether the last flow entry
438 Iterable<IFlowEntry> tmpflowEntries =
439 flowObj.getFlowEntries();
440 boolean found = false;
441 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
442 found = true;
443 break;
444 }
445 if (! found) {
446 // Remove the Flow Path as well
447 conn.utils().removeFlowPath(conn, flowObj);
448 }
449 }
450 } catch (IOException e) {
451 log.error("Failure writing flow mod from network map", e);
452 }
453 }
454 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700455
456 if (processed_measurement_flow) {
457 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
458 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
459 (double)estimatedTime / 1000000000 + " sec";
460 log.debug(logMsg);
461 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800462 }
463 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700464
465 /*
466 final ScheduledFuture<?> measureShortestPathHandle =
467 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
468 */
469
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700470 final ScheduledFuture<?> measureMapReaderHandle =
471 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700472
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700473 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700474 final ScheduledFuture<?> mapReaderHandle =
475 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700476 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800477
478 @Override
479 public void init(String conf) {
480 conn = GraphDBConnection.getInstance(conf);
481 }
482
483 public void finalize() {
484 close();
485 }
486
487 @Override
488 public void close() {
489 conn.close();
490 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800491
492 @Override
493 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
494 Collection<Class<? extends IFloodlightService>> l =
495 new ArrayList<Class<? extends IFloodlightService>>();
496 l.add(IFlowService.class);
497 return l;
498 }
499
500 @Override
501 public Map<Class<? extends IFloodlightService>, IFloodlightService>
502 getServiceImpls() {
503 Map<Class<? extends IFloodlightService>,
504 IFloodlightService> m =
505 new HashMap<Class<? extends IFloodlightService>,
506 IFloodlightService>();
507 m.put(IFlowService.class, this);
508 return m;
509 }
510
511 @Override
512 public Collection<Class<? extends IFloodlightService>>
513 getModuleDependencies() {
514 Collection<Class<? extends IFloodlightService>> l =
515 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800516 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800517 l.add(IRestApiService.class);
518 return l;
519 }
520
521 @Override
522 public void init(FloodlightModuleContext context)
523 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700524 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800525 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800526 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800527 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
528 EnumSet.of(OFType.FLOW_MOD),
529 OFMESSAGE_DAMPER_TIMEOUT);
530 // TODO: An ugly hack!
531 String conf = "/tmp/cassandra.titan";
532 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800533 }
534
535 @Override
536 public void startUp(FloodlightModuleContext context) {
537 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700538
539 //
540 // Extract all flow entries and assign the next Flow Entry ID
541 // to be larger than the largest Flow Entry ID
542 //
543 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
544 for (IFlowEntry flowEntryObj : allFlowEntries) {
545 FlowEntryId flowEntryId =
546 new FlowEntryId(flowEntryObj.getFlowEntryId());
547 if (flowEntryId.value() >= nextFlowEntryId)
548 nextFlowEntryId = flowEntryId.value() + 1;
549 }
550 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800551 }
552
553 /**
554 * Add a flow.
555 *
556 * Internally, ONOS will automatically register the installer for
557 * receiving Flow Path Notifications for that path.
558 *
559 * @param flowPath the Flow Path to install.
560 * @param flowId the return-by-reference Flow ID as assigned internally.
561 * @return true on success, otherwise false.
562 */
563 @Override
564 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700565 if (flowPath.flowId().value() == measurementFlowId) {
566 modifiedMeasurementFlowTime = System.nanoTime();
567 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800568
569 //
570 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700571 // Right now every new flow entry gets a new flow entry ID
572 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800573 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800574 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700575 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800576 flowEntry.setFlowEntryId(new FlowEntryId(id));
577 }
578
579 IFlowPath flowObj = null;
580 try {
581 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
582 != null) {
583 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
584 flowPath.flowId().toString());
585 } else {
586 flowObj = conn.utils().newFlowPath(conn);
587 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
588 flowPath.flowId().toString());
589 }
590 } catch (Exception e) {
591 // TODO: handle exceptions
592 conn.endTx(Transaction.ROLLBACK);
593 log.error(":addFlow FlowId:{} failed",
594 flowPath.flowId().toString());
595 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700596 if (flowObj == null) {
597 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800598 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700599 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800600
601 //
602 // Set the Flow key:
603 // - flowId
604 //
605 flowObj.setFlowId(flowPath.flowId().toString());
606 flowObj.setType("flow");
607
608 //
609 // Set the Flow attributes:
610 // - flowPath.installerId()
611 // - flowPath.dataPath().srcPort()
612 // - flowPath.dataPath().dstPort()
613 //
614 flowObj.setInstallerId(flowPath.installerId().toString());
615 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
616 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
617 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
618 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
619
620 // Flow edges:
621 // HeadFE
622
623
624 //
625 // Flow Entries:
626 // flowPath.dataPath().flowEntries()
627 //
628 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
629 IFlowEntry flowEntryObj = null;
630 boolean found = false;
631 try {
632 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
633 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
634 flowEntry.flowEntryId().toString());
635 found = true;
636 } else {
637 flowEntryObj = conn.utils().newFlowEntry(conn);
638 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
639 flowEntry.flowEntryId().toString());
640 }
641 } catch (Exception e) {
642 // TODO: handle exceptions
643 conn.endTx(Transaction.ROLLBACK);
644 log.error(":addFlow FlowEntryId:{} failed",
645 flowEntry.flowEntryId().toString());
646 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700647 if (flowEntryObj == null) {
648 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800649 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700650 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800651
652 //
653 // Set the Flow Entry key:
654 // - flowEntry.flowEntryId()
655 //
656 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
657 flowEntryObj.setType("flow_entry");
658
659 //
660 // Set the Flow Entry attributes:
661 // - flowEntry.flowEntryMatch()
662 // - flowEntry.flowEntryActions()
663 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800664 // - flowEntry.flowEntryUserState()
665 // - flowEntry.flowEntrySwitchState()
666 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700667 // - flowEntry.matchInPort()
668 // - flowEntry.matchEthernetFrameType()
669 // - flowEntry.matchSrcIPv4Net()
670 // - flowEntry.matchDstIPv4Net()
671 // - flowEntry.matchSrcMac()
672 // - flowEntry.matchDstMac()
673 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800674 //
675 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700676 if (flowEntry.flowEntryMatch().matchInPort())
677 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
678 if (flowEntry.flowEntryMatch().matchEthernetFrameType())
679 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
680 if (flowEntry.flowEntryMatch().matchSrcIPv4Net())
681 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
682 if (flowEntry.flowEntryMatch().matchDstIPv4Net())
683 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
684 if (flowEntry.flowEntryMatch().matchSrcMac())
685 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
686 if (flowEntry.flowEntryMatch().matchDstMac())
687 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
688
689 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
690 if (fa.actionOutput() != null)
691 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
692 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800693 // TODO: Hacks with hard-coded state names!
694 if (found)
695 flowEntryObj.setUserState("FE_USER_MODIFY");
696 else
697 flowEntryObj.setUserState("FE_USER_ADD");
698 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
699 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800700 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800701 // and FlowEntryErrorState.
702 //
703
704 // Flow Entries edges:
705 // Flow
706 // NextFE
707 // InPort
708 // OutPort
709 // Switch
710 if (! found)
711 flowObj.addFlowEntry(flowEntryObj);
712 }
713 conn.endTx(Transaction.COMMIT);
714
715 //
716 // TODO: We need a proper Flow ID allocation mechanism.
717 //
718 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700719
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800720 return true;
721 }
722
723 /**
724 * Delete a previously added flow.
725 *
726 * @param flowId the Flow ID of the flow to delete.
727 * @return true on success, otherwise false.
728 */
729 @Override
730 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700731 if (flowId.value() == measurementFlowId) {
732 modifiedMeasurementFlowTime = System.nanoTime();
733 }
734
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800735 IFlowPath flowObj = null;
736 //
737 // We just mark the entries for deletion,
738 // and let the switches remove each individual entry after
739 // it has been removed from the switches.
740 //
741 try {
742 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
743 != null) {
744 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
745 flowId.toString());
746 } else {
747 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
748 flowId.toString());
749 }
750 } catch (Exception e) {
751 // TODO: handle exceptions
752 conn.endTx(Transaction.ROLLBACK);
753 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
754 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700755 if (flowObj == null) {
756 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800757 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700758 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800759
760 //
761 // Find and mark for deletion all Flow Entries
762 //
763 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
764 boolean empty = true; // TODO: an ugly hack
765 for (IFlowEntry flowEntryObj : flowEntries) {
766 empty = false;
767 // flowObj.removeFlowEntry(flowEntryObj);
768 // conn.utils().removeFlowEntry(conn, flowEntryObj);
769 flowEntryObj.setUserState("FE_USER_DELETE");
770 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
771 }
772 // Remove from the database empty flows
773 if (empty)
774 conn.utils().removeFlowPath(conn, flowObj);
775 conn.endTx(Transaction.COMMIT);
776
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800777 return true;
778 }
779
780 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700781 * Clear the state for a previously added flow.
782 *
783 * @param flowId the Flow ID of the flow to clear.
784 * @return true on success, otherwise false.
785 */
786 @Override
787 public boolean clearFlow(FlowId flowId) {
788 IFlowPath flowObj = null;
789 try {
790 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
791 != null) {
792 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
793 flowId.toString());
794 } else {
795 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
796 flowId.toString());
797 }
798 } catch (Exception e) {
799 // TODO: handle exceptions
800 conn.endTx(Transaction.ROLLBACK);
801 log.error(":clearFlow FlowId:{} failed", flowId.toString());
802 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700803 if (flowObj == null) {
804 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700805 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700806 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700807
808 //
809 // Remove all Flow Entries
810 //
811 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
812 for (IFlowEntry flowEntryObj : flowEntries) {
813 flowObj.removeFlowEntry(flowEntryObj);
814 conn.utils().removeFlowEntry(conn, flowEntryObj);
815 }
816 // Remove the Flow itself
817 conn.utils().removeFlowPath(conn, flowObj);
818 conn.endTx(Transaction.COMMIT);
819
820 return true;
821 }
822
823 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800824 * Get a previously added flow.
825 *
826 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800827 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800828 */
829 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800830 public FlowPath getFlow(FlowId flowId) {
831 IFlowPath flowObj = null;
832 try {
833 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
834 != null) {
835 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
836 flowId.toString());
837 } else {
838 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
839 flowId.toString());
840 }
841 } catch (Exception e) {
842 // TODO: handle exceptions
843 conn.endTx(Transaction.ROLLBACK);
844 log.error(":getFlow FlowId:{} failed", flowId.toString());
845 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700846 if (flowObj == null) {
847 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800848 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700849 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800850
851 //
852 // Extract the Flow state
853 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800854 FlowPath flowPath = extractFlowPath(flowObj);
855 conn.endTx(Transaction.COMMIT);
856
857 return flowPath;
858 }
859
860 /**
861 * Get all previously added flows by a specific installer for a given
862 * data path endpoints.
863 *
864 * @param installerId the Caller ID of the installer of the flow to get.
865 * @param dataPathEndpoints the data path endpoints of the flow to get.
866 * @return the Flow Paths if found, otherwise null.
867 */
868 @Override
869 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
870 DataPathEndpoints dataPathEndpoints) {
871 //
872 // TODO: The implementation below is not optimal:
873 // We fetch all flows, and then return only the subset that match
874 // the query conditions.
875 // We should use the appropriate Titan/Gremlin query to filter-out
876 // the flows as appropriate.
877 //
878 ArrayList<FlowPath> allFlows = getAllFlows();
879
880 if (allFlows == null) {
881 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
882 return null;
883 }
884
885 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
886 for (FlowPath flow : allFlows) {
887 //
888 // TODO: String-based comparison is sub-optimal.
889 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800890 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800891 //
892 if (! flow.installerId().toString().equals(installerId.toString()))
893 continue;
894 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
895 continue;
896 }
897 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
898 continue;
899 }
900 flowPaths.add(flow);
901 }
902
903 if (flowPaths.isEmpty()) {
904 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
905 flowPaths = null;
906 } else {
907 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
908 }
909
910 return flowPaths;
911 }
912
913 /**
914 * Get all installed flows by all installers for given data path endpoints.
915 *
916 * @param dataPathEndpoints the data path endpoints of the flows to get.
917 * @return the Flow Paths if found, otherwise null.
918 */
919 @Override
920 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
921 //
922 // TODO: The implementation below is not optimal:
923 // We fetch all flows, and then return only the subset that match
924 // the query conditions.
925 // We should use the appropriate Titan/Gremlin query to filter-out
926 // the flows as appropriate.
927 //
928 ArrayList<FlowPath> allFlows = getAllFlows();
929
930 if (allFlows == null) {
931 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
932 return null;
933 }
934
935 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
936 for (FlowPath flow : allFlows) {
937 //
938 // TODO: String-based comparison is sub-optimal.
939 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800940 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800941 //
942 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
943 continue;
944 }
945 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
946 continue;
947 }
948 flowPaths.add(flow);
949 }
950
951 if (flowPaths.isEmpty()) {
952 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
953 flowPaths = null;
954 } else {
955 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
956 }
957
958 return flowPaths;
959 }
960
961 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700962 * Get summary of all installed flows by all installers in a given range
963 *
964 * @param flowId the data path endpoints of the flows to get.
965 * @param maxFlows: the maximum number of flows to be returned
966 * @return the Flow Paths if found, otherwise null.
967 */
968 @Override
969 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
970 //
971 // TODO: The implementation below is not optimal:
972 // We fetch all flows, and then return only the subset that match
973 // the query conditions.
974 // We should use the appropriate Titan/Gremlin query to filter-out
975 // the flows as appropriate.
976 //
977 ArrayList<FlowPath> allFlows = getAllFlows();
978
979 if (allFlows == null) {
980 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
981 return null;
982 }
983
984 Collections.sort(allFlows);
985
986 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
987 for (FlowPath flow : allFlows) {
988
989 // start from desired flowId
990 if (flow.flowId().value() < flowId.value()) {
991 continue;
992 }
993
994 // Summarize by making null flow entry fields that are not relevant to report
995 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
996 flowEntry.setFlowEntryActions(null);
997 flowEntry.setFlowEntryMatch(null);
998 }
999
1000 flowPaths.add(flow);
1001 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1002 break;
1003 }
1004 }
1005
1006 if (flowPaths.isEmpty()) {
1007 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
1008 flowPaths = null;
1009 } else {
1010 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1011 }
1012
1013 return flowPaths;
1014 }
1015
1016 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001017 * Get all installed flows by all installers.
1018 *
1019 * @return the Flow Paths if found, otherwise null.
1020 */
1021 @Override
1022 public ArrayList<FlowPath> getAllFlows() {
1023 Iterable<IFlowPath> flowPathsObj = null;
1024
1025 try {
1026 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1027 log.debug("Get all FlowPaths: found FlowPaths");
1028 } else {
1029 log.debug("Get all FlowPaths: no FlowPaths found");
1030 }
1031 } catch (Exception e) {
1032 // TODO: handle exceptions
1033 conn.endTx(Transaction.ROLLBACK);
1034 log.error(":getAllFlowPaths failed");
1035 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001036 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1037 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001038 return null; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001039 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001040
1041 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1042 for (IFlowPath flowObj : flowPathsObj) {
1043 //
1044 // Extract the Flow state
1045 //
1046 FlowPath flowPath = extractFlowPath(flowObj);
1047 flowPaths.add(flowPath);
1048 }
1049
1050 conn.endTx(Transaction.COMMIT);
1051
1052 return flowPaths;
1053 }
1054
1055 /**
1056 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1057 *
1058 * @param flowObj the object to extract the Flow Path State from.
1059 * @return the extracted Flow Path State.
1060 */
1061 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001062 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001063
1064 //
1065 // Extract the Flow state
1066 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001067 flowPath.setFlowId(new FlowId(flowObj.getFlowId()));
1068 flowPath.setInstallerId(new CallerId(flowObj.getInstallerId()));
1069 flowPath.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
1070 flowPath.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
1071 flowPath.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
1072 flowPath.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
1073
1074 //
1075 // Extract all Flow Entries
1076 //
1077 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1078 for (IFlowEntry flowEntryObj : flowEntries) {
1079 FlowEntry flowEntry = new FlowEntry();
1080 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
1081 flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001082
1083 //
1084 // Extract the match conditions
1085 //
1086 FlowEntryMatch match = new FlowEntryMatch();
1087 Short matchInPort = flowEntryObj.getMatchInPort();
1088 if (matchInPort != null)
1089 match.enableInPort(new Port(matchInPort));
1090 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1091 if (matchEthernetFrameType != null)
1092 match.enableEthernetFrameType(matchEthernetFrameType);
1093 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1094 if (matchSrcIPv4Net != null)
1095 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1096 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1097 if (matchDstIPv4Net != null)
1098 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1099 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1100 if (matchSrcMac != null)
1101 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1102 String matchDstMac = flowEntryObj.getMatchDstMac();
1103 if (matchDstMac != null)
1104 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1105 flowEntry.setFlowEntryMatch(match);
1106
1107 //
1108 // Extract the actions
1109 //
1110 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1111 Short actionOutputPort = flowEntryObj.getActionOutput();
1112 if (actionOutputPort != null) {
1113 FlowEntryAction action = new FlowEntryAction();
1114 action.setActionOutput(new Port(actionOutputPort));
1115 actions.add(action);
1116 }
1117 flowEntry.setFlowEntryActions(actions);
1118
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001119 String userState = flowEntryObj.getUserState();
1120 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1121 String switchState = flowEntryObj.getSwitchState();
1122 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1123 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001124 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001125 // and FlowEntryErrorState.
1126 //
1127 flowPath.dataPath().flowEntries().add(flowEntry);
1128 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001129
1130 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001131 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001132}