blob: 3eec2ecab0943632582c4c78cedebccb574f379a [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;
Pankaj Berded0079742013-03-27 17:53:25 -070025import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
26import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070027import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080028import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080029import net.floodlightcontroller.core.module.FloodlightModuleContext;
30import net.floodlightcontroller.core.module.FloodlightModuleException;
31import net.floodlightcontroller.core.module.IFloodlightModule;
32import net.floodlightcontroller.core.module.IFloodlightService;
33import net.floodlightcontroller.flowcache.IFlowService;
34import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
35import net.floodlightcontroller.restserver.IRestApiService;
36import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080037import net.floodlightcontroller.util.DataPath;
38import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080039import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080040import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070041import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080042import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070043import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080044import net.floodlightcontroller.util.FlowEntrySwitchState;
45import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080046import net.floodlightcontroller.util.FlowId;
47import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070048import net.floodlightcontroller.util.IPv4Net;
49import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080050import net.floodlightcontroller.util.OFMessageDamper;
51import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070052import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080053import net.onrc.onos.util.GraphDBConnection;
54import net.onrc.onos.util.GraphDBConnection.Transaction;
55
56import org.openflow.protocol.OFFlowMod;
57import org.openflow.protocol.OFMatch;
58import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070059import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080060import org.openflow.protocol.OFType;
61import org.openflow.protocol.action.OFAction;
62import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080063
64import org.slf4j.Logger;
65import org.slf4j.LoggerFactory;
66
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080067public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
68
69 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080070
71 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070073 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080074
75 protected OFMessageDamper messageDamper;
76
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070077 //
78 // TODO: Values copied from elsewhere (class LearningSwitch).
79 // The local copy should go away!
80 //
81 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
82 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
83 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
84 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
85 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080086
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070087 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070088 private static long measurementFlowId = 100000;
89 private static String measurementFlowIdStr = "0x186a0"; // 100000
90 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070091
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080092 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080093 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
94
95 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070096 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080097 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070098 private final ScheduledExecutorService measureMapReaderScheduler =
99 Executors.newScheduledThreadPool(1);
100 private final ScheduledExecutorService mapReaderScheduler =
101 Executors.newScheduledThreadPool(1);
102
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700103 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
104 private ThreadPoolExecutor shortestPathExecutor =
105 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
106
107 class ShortestPathTask implements Runnable {
108 private int hint;
109 private ITopoRouteService topoRouteService;
110 private ArrayList<DataPath> dpList;
111
112 public ShortestPathTask(int hint,
113 ITopoRouteService topoRouteService,
114 ArrayList<DataPath> dpList) {
115 this.hint = hint;
116 this.topoRouteService = topoRouteService;
117 this.dpList = dpList;
118 }
119
120 @Override
121 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700122 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700123 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
124 log.debug(logMsg);
125 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700126 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700127 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700128 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700129 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700130 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700131 long estimatedTime = System.nanoTime() - startTime;
132 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
133 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
134 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700135 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700136 }
137 }
138
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700139 final Runnable measureShortestPath = new Runnable() {
140 public void run() {
141 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
142 if (floodlightProvider == null) {
143 log.debug("FloodlightProvider service not found!");
144 return;
145 }
146
147 ITopoRouteService topoRouteService =
148 context.getServiceImpl(ITopoRouteService.class);
149 if (topoRouteService == null) {
150 log.debug("Topology Route Service not found");
151 return;
152 }
153
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700154 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
155 if (leftoverQueueSize > 0) {
156 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
157 log.debug(logMsg);
158 return;
159 }
160 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
161
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700162 //
163 // Recompute the Shortest Paths for all Flows
164 //
165 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700166 int hint = 0;
167 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700168 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700169
170 topoRouteService.prepareShortestPathTopo();
171
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700172 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
173 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700174 FlowId flowId = new FlowId(flowPathObj.getFlowId());
175
176 // log.debug("Found Path {}", flowId.toString());
177 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
178 Port srcPort = new Port(flowPathObj.getSrcPort());
179 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
180 Port dstPort = new Port(flowPathObj.getDstPort());
181 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
182 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700183
184 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700185 DataPath dp = new DataPath();
186 dp.setSrcPort(srcSwitchPort);
187 dp.setDstPort(dstSwitchPort);
188 dpList.add(dp);
189 if ((dpList.size() % 10) == 0) {
190 shortestPathExecutor.execute(
191 new ShortestPathTask(hint, topoRouteService,
192 dpList));
193 dpList = new ArrayList<DataPath>();
194 hint++;
195 }
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700196 */
197
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700198 DataPath dataPath =
199 topoRouteService.getTopoShortestPath(srcSwitchPort,
200 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700201 counter++;
202 }
203 if (dpList.size() > 0) {
204 shortestPathExecutor.execute(
205 new ShortestPathTask(hint, topoRouteService,
206 dpList));
207 }
208
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700209 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700210 // Wait for all tasks to finish
211 try {
212 while (shortestPathExecutor.getQueue().size() > 0) {
213 Thread.sleep(100);
214 }
215 } catch (InterruptedException ex) {
216 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700217 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700218 */
219
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700220 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700221 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700222
223 long estimatedTime = System.nanoTime() - startTime;
224 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
225 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
226 log.debug(logMsg);
227 }
228 };
229
230 final Runnable measureMapReader = new Runnable() {
231 public void run() {
232 if (floodlightProvider == null) {
233 log.debug("FloodlightProvider service not found!");
234 return;
235 }
236
237 //
238 // Fetch all Flow Entries
239 //
240 int counter = 0;
241 long startTime = System.nanoTime();
242 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
243 for (IFlowEntry flowEntryObj : allFlowEntries) {
244 counter++;
245 FlowEntryId flowEntryId =
246 new FlowEntryId(flowEntryObj.getFlowEntryId());
247 String userState = flowEntryObj.getUserState();
248 String switchState = flowEntryObj.getSwitchState();
249 }
250 conn.endTx(Transaction.COMMIT);
251
252 long estimatedTime = System.nanoTime() - startTime;
253 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
254 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
255 log.debug(logMsg);
256 }
257 };
258
259 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800260 public void run() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800261 if (floodlightProvider == null) {
262 log.debug("FloodlightProvider service not found!");
263 return;
264 }
265
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000266 Map<Long, IOFSwitch> mySwitches =
267 floodlightProvider.getSwitches();
268 Map<Long, IFlowEntry> myFlowEntries =
269 new TreeMap<Long, IFlowEntry>();
270 LinkedList<IFlowEntry> deleteFlowEntries =
271 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700272
273 //
274 // Fetch all Flow Entries and select only my Flow Entries
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000275 // that need to be undated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700276 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000277 Iterable<IFlowEntry> allFlowEntries =
278 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700279 for (IFlowEntry flowEntryObj : allFlowEntries) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000280 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700281 String userState = flowEntryObj.getUserState();
282 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000283 String dpidStr = flowEntryObj.getSwitchDpid();
284 if ((flowEntryIdStr == null) ||
285 (userState == null) ||
286 (switchState == null) ||
287 (dpidStr == null)) {
288 log.debug("IGNORING Flow Entry entry with null fields");
289 continue;
290 }
291 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
292 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800293
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000294 /*
295 log.debug("Found Flow Entry Id = {} {}",
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700296 flowEntryId.toString(),
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000297 "DPID = " + dpid.toString() +
298 " User State: " + userState +
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700299 " Switch State: " + switchState);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000300 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800301
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000302 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
303 continue; // Ignore the entry: nothing to do
304
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800305 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000306 if (mySwitch == null)
307 continue; // Ignore the entry: not my switch
308
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700309 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
310 }
311
312 //
313 // Process my Flow Entries
314 //
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700315 Boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700316 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
317 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700318 // Code for measurement purpose
319 {
320 IFlowPath flowObj =
321 conn.utils().getFlowPathByFlowEntry(conn,
322 flowEntryObj);
323 if ((flowObj != null) &&
324 flowObj.getFlowId().equals(measurementFlowIdStr)) {
325 processed_measurement_flow = true;
326 }
327 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700328
329 //
330 // TODO: Eliminate the re-fetching of flowEntryId,
331 // userState, switchState, and dpid from the flowEntryObj.
332 //
333 FlowEntryId flowEntryId =
334 new FlowEntryId(flowEntryObj.getFlowEntryId());
335 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
336 String userState = flowEntryObj.getUserState();
337 String switchState = flowEntryObj.getSwitchState();
338 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000339 if (mySwitch == null)
340 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800341
342 //
343 // Create the Open Flow Flow Modification Entry to push
344 //
345 OFFlowMod fm =
346 (OFFlowMod) floodlightProvider.getOFMessageFactory()
347 .getMessage(OFType.FLOW_MOD);
348 long cookie = flowEntryId.value();
349
350 short flowModCommand = OFFlowMod.OFPFC_ADD;
351 if (userState.equals("FE_USER_ADD")) {
352 flowModCommand = OFFlowMod.OFPFC_ADD;
353 } else if (userState.equals("FE_USER_MODIFY")) {
354 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
355 } else if (userState.equals("FE_USER_DELETE")) {
356 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
357 } else {
358 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700359 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
360 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800361 continue;
362 }
363
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700364 //
365 // Fetch the match conditions
366 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800367 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700368 match.setWildcards(OFMatch.OFPFW_ALL);
369 Short matchInPort = flowEntryObj.getMatchInPort();
370 if (matchInPort != null) {
371 match.setInputPort(matchInPort);
372 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
373 }
374 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
375 if (matchEthernetFrameType != null) {
376 match.setDataLayerType(matchEthernetFrameType);
377 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
378 }
379 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
380 if (matchSrcIPv4Net != null) {
381 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
382 }
383 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
384 if (matchDstIPv4Net != null) {
385 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
386 }
387 String matchSrcMac = flowEntryObj.getMatchSrcMac();
388 if (matchSrcMac != null) {
389 match.setDataLayerSource(matchSrcMac);
390 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
391 }
392 String matchDstMac = flowEntryObj.getMatchDstMac();
393 if (matchDstMac != null) {
394 match.setDataLayerDestination(matchDstMac);
395 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
396 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700397
398 //
399 // Fetch the actions
400 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800401 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700402 Short actionOutputPort = flowEntryObj.getActionOutput();
403 if (actionOutputPort != null) {
404 OFActionOutput action = new OFActionOutput();
405 // XXX: The max length is hard-coded for now
406 action.setMaxLength((short)0xffff);
407 action.setPort(actionOutputPort);
408 actions.add(action);
409 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800410
411 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
412 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700413 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800414 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
415 .setCookie(cookie)
416 .setCommand(flowModCommand)
417 .setMatch(match)
418 .setActions(actions)
419 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700420 fm.setOutPort(OFPort.OFPP_NONE.getValue());
421 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
422 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
423 if (actionOutputPort != null)
424 fm.setOutPort(actionOutputPort);
425 }
426
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800427 //
428 // TODO: Set the following flag
429 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
430 // See method ForwardingBase::pushRoute()
431 //
432 try {
433 messageDamper.write(mySwitch, fm, null);
434 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000435 //
436 // TODO: We should use the OpenFlow Barrier mechanism
437 // to check for errors, and update the SwitchState
438 // for a flow entry after the Barrier message is
439 // is received.
440 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800441 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
442 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000443 // An entry that needs to be deleted.
444 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800445 }
446 } catch (IOException e) {
447 log.error("Failure writing flow mod from network map", e);
448 }
449 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000450
451 //
452 // Delete all entries marked for deletion
453 //
454 // TODO: We should use the OpenFlow Barrier mechanism
455 // to check for errors, and delete the Flow Entries after the
456 // Barrier message is received.
457 //
458 while (! deleteFlowEntries.isEmpty()) {
459 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
460 IFlowPath flowObj =
461 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
462 if (flowObj == null) {
463 log.debug("Did not find FlowPath to be deleted");
464 continue;
465 }
466 flowObj.removeFlowEntry(flowEntryObj);
467 conn.utils().removeFlowEntry(conn, flowEntryObj);
468
469 // Test whether the last flow entry
470 Iterable<IFlowEntry> tmpflowEntries =
471 flowObj.getFlowEntries();
472 boolean found = false;
473 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
474 found = true;
475 break;
476 }
477 if (! found) {
478 // Remove the Flow Path as well
479 conn.utils().removeFlowPath(conn, flowObj);
480 }
481 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800482 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700483
484 if (processed_measurement_flow) {
485 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
486 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
487 (double)estimatedTime / 1000000000 + " sec";
488 log.debug(logMsg);
489 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800490 }
491 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700492
493 /*
494 final ScheduledFuture<?> measureShortestPathHandle =
495 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
496 */
497
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700498 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700499 final ScheduledFuture<?> measureMapReaderHandle =
500 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700501 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700502
503 final ScheduledFuture<?> mapReaderHandle =
504 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800505
506 @Override
507 public void init(String conf) {
508 conn = GraphDBConnection.getInstance(conf);
509 }
510
511 public void finalize() {
512 close();
513 }
514
515 @Override
516 public void close() {
517 conn.close();
518 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800519
520 @Override
521 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
522 Collection<Class<? extends IFloodlightService>> l =
523 new ArrayList<Class<? extends IFloodlightService>>();
524 l.add(IFlowService.class);
525 return l;
526 }
527
528 @Override
529 public Map<Class<? extends IFloodlightService>, IFloodlightService>
530 getServiceImpls() {
531 Map<Class<? extends IFloodlightService>,
532 IFloodlightService> m =
533 new HashMap<Class<? extends IFloodlightService>,
534 IFloodlightService>();
535 m.put(IFlowService.class, this);
536 return m;
537 }
538
539 @Override
540 public Collection<Class<? extends IFloodlightService>>
541 getModuleDependencies() {
542 Collection<Class<? extends IFloodlightService>> l =
543 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800544 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800545 l.add(IRestApiService.class);
546 return l;
547 }
548
549 @Override
550 public void init(FloodlightModuleContext context)
551 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700552 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800553 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800554 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800555 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
556 EnumSet.of(OFType.FLOW_MOD),
557 OFMESSAGE_DAMPER_TIMEOUT);
558 // TODO: An ugly hack!
559 String conf = "/tmp/cassandra.titan";
560 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800561 }
562
563 @Override
564 public void startUp(FloodlightModuleContext context) {
565 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700566
567 //
568 // Extract all flow entries and assign the next Flow Entry ID
569 // to be larger than the largest Flow Entry ID
570 //
571 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
572 for (IFlowEntry flowEntryObj : allFlowEntries) {
573 FlowEntryId flowEntryId =
574 new FlowEntryId(flowEntryObj.getFlowEntryId());
575 if (flowEntryId.value() >= nextFlowEntryId)
576 nextFlowEntryId = flowEntryId.value() + 1;
577 }
578 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800579 }
580
581 /**
582 * Add a flow.
583 *
584 * Internally, ONOS will automatically register the installer for
585 * receiving Flow Path Notifications for that path.
586 *
587 * @param flowPath the Flow Path to install.
588 * @param flowId the return-by-reference Flow ID as assigned internally.
589 * @return true on success, otherwise false.
590 */
591 @Override
592 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700593 if (flowPath.flowId().value() == measurementFlowId) {
594 modifiedMeasurementFlowTime = System.nanoTime();
595 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800596
597 //
598 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700599 // Right now every new flow entry gets a new flow entry ID
600 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800601 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800602 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700603 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800604 flowEntry.setFlowEntryId(new FlowEntryId(id));
605 }
606
607 IFlowPath flowObj = null;
608 try {
609 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
610 != null) {
611 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
612 flowPath.flowId().toString());
613 } else {
614 flowObj = conn.utils().newFlowPath(conn);
615 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
616 flowPath.flowId().toString());
617 }
618 } catch (Exception e) {
619 // TODO: handle exceptions
620 conn.endTx(Transaction.ROLLBACK);
621 log.error(":addFlow FlowId:{} failed",
622 flowPath.flowId().toString());
623 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700624 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000625 log.error(":addFlow FlowId:{} failed: Flow object not created",
626 flowPath.flowId().toString());
627 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800628 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700629 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800630
631 //
632 // Set the Flow key:
633 // - flowId
634 //
635 flowObj.setFlowId(flowPath.flowId().toString());
636 flowObj.setType("flow");
637
638 //
639 // Set the Flow attributes:
640 // - flowPath.installerId()
641 // - flowPath.dataPath().srcPort()
642 // - flowPath.dataPath().dstPort()
643 //
644 flowObj.setInstallerId(flowPath.installerId().toString());
645 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
646 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
647 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
648 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
649
650 // Flow edges:
651 // HeadFE
652
653
654 //
655 // Flow Entries:
656 // flowPath.dataPath().flowEntries()
657 //
658 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
659 IFlowEntry flowEntryObj = null;
660 boolean found = false;
661 try {
662 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
663 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
664 flowEntry.flowEntryId().toString());
665 found = true;
666 } else {
667 flowEntryObj = conn.utils().newFlowEntry(conn);
668 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
669 flowEntry.flowEntryId().toString());
670 }
671 } catch (Exception e) {
672 // TODO: handle exceptions
673 conn.endTx(Transaction.ROLLBACK);
674 log.error(":addFlow FlowEntryId:{} failed",
675 flowEntry.flowEntryId().toString());
676 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700677 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000678 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
679 flowEntry.flowEntryId().toString());
680 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800681 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700682 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800683
684 //
685 // Set the Flow Entry key:
686 // - flowEntry.flowEntryId()
687 //
688 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
689 flowEntryObj.setType("flow_entry");
690
691 //
692 // Set the Flow Entry attributes:
693 // - flowEntry.flowEntryMatch()
694 // - flowEntry.flowEntryActions()
695 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800696 // - flowEntry.flowEntryUserState()
697 // - flowEntry.flowEntrySwitchState()
698 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700699 // - flowEntry.matchInPort()
700 // - flowEntry.matchEthernetFrameType()
701 // - flowEntry.matchSrcIPv4Net()
702 // - flowEntry.matchDstIPv4Net()
703 // - flowEntry.matchSrcMac()
704 // - flowEntry.matchDstMac()
705 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800706 //
Pankaj Berded0079742013-03-27 17:53:25 -0700707 ISwitchObject sw = conn.utils().searchSwitch(conn,flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800708 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700709
710 flowEntryObj.setSwitch(sw);
711 if (flowEntry.flowEntryMatch().matchInPort()) {
712 IPortObject inport = conn.utils().searchPort(conn,flowEntry.dpid().toString(),
713 flowEntry.flowEntryMatch().inPort().value());
714 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
715 flowEntryObj.setInPort(inport);
716 }
717 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
718 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
719 }
720 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
721 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
722 }
723 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
724 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
725 }
726 if (flowEntry.flowEntryMatch().matchSrcMac()) {
727 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
728 }
729 if (flowEntry.flowEntryMatch().matchDstMac()) {
730 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
731 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700732
733 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700734 if (fa.actionOutput() != null) {
735 IPortObject outport = conn.utils().searchPort(conn,flowEntry.dpid().toString(),
736 fa.actionOutput().port().value());
737 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
738 flowEntryObj.setOutPort(outport);
739 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700740 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800741 // TODO: Hacks with hard-coded state names!
742 if (found)
743 flowEntryObj.setUserState("FE_USER_MODIFY");
744 else
745 flowEntryObj.setUserState("FE_USER_ADD");
746 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
747 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800748 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800749 // and FlowEntryErrorState.
750 //
751
752 // Flow Entries edges:
753 // Flow
754 // NextFE
755 // InPort
756 // OutPort
757 // Switch
758 if (! found)
759 flowObj.addFlowEntry(flowEntryObj);
760 }
761 conn.endTx(Transaction.COMMIT);
762
763 //
764 // TODO: We need a proper Flow ID allocation mechanism.
765 //
766 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700767
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800768 return true;
769 }
770
771 /**
772 * Delete a previously added flow.
773 *
774 * @param flowId the Flow ID of the flow to delete.
775 * @return true on success, otherwise false.
776 */
777 @Override
778 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700779 if (flowId.value() == measurementFlowId) {
780 modifiedMeasurementFlowTime = System.nanoTime();
781 }
782
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800783 IFlowPath flowObj = null;
784 //
785 // We just mark the entries for deletion,
786 // and let the switches remove each individual entry after
787 // it has been removed from the switches.
788 //
789 try {
790 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
791 != null) {
792 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
793 flowId.toString());
794 } else {
795 log.debug("Deleting 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(":deleteFlow FlowId:{} failed", flowId.toString());
802 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700803 if (flowObj == null) {
804 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800805 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700806 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800807
808 //
809 // Find and mark for deletion all Flow Entries
810 //
811 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
812 boolean empty = true; // TODO: an ugly hack
813 for (IFlowEntry flowEntryObj : flowEntries) {
814 empty = false;
815 // flowObj.removeFlowEntry(flowEntryObj);
816 // conn.utils().removeFlowEntry(conn, flowEntryObj);
817 flowEntryObj.setUserState("FE_USER_DELETE");
818 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
819 }
820 // Remove from the database empty flows
821 if (empty)
822 conn.utils().removeFlowPath(conn, flowObj);
823 conn.endTx(Transaction.COMMIT);
824
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800825 return true;
826 }
827
828 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700829 * Clear the state for a previously added flow.
830 *
831 * @param flowId the Flow ID of the flow to clear.
832 * @return true on success, otherwise false.
833 */
834 @Override
835 public boolean clearFlow(FlowId flowId) {
836 IFlowPath flowObj = null;
837 try {
838 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
839 != null) {
840 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
841 flowId.toString());
842 } else {
843 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
844 flowId.toString());
845 }
846 } catch (Exception e) {
847 // TODO: handle exceptions
848 conn.endTx(Transaction.ROLLBACK);
849 log.error(":clearFlow FlowId:{} failed", flowId.toString());
850 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700851 if (flowObj == null) {
852 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700853 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700854 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700855
856 //
857 // Remove all Flow Entries
858 //
859 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
860 for (IFlowEntry flowEntryObj : flowEntries) {
861 flowObj.removeFlowEntry(flowEntryObj);
862 conn.utils().removeFlowEntry(conn, flowEntryObj);
863 }
864 // Remove the Flow itself
865 conn.utils().removeFlowPath(conn, flowObj);
866 conn.endTx(Transaction.COMMIT);
867
868 return true;
869 }
870
871 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800872 * Get a previously added flow.
873 *
874 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800875 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800876 */
877 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800878 public FlowPath getFlow(FlowId flowId) {
879 IFlowPath flowObj = null;
880 try {
881 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
882 != null) {
883 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
884 flowId.toString());
885 } else {
886 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
887 flowId.toString());
888 }
889 } catch (Exception e) {
890 // TODO: handle exceptions
891 conn.endTx(Transaction.ROLLBACK);
892 log.error(":getFlow FlowId:{} failed", flowId.toString());
893 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700894 if (flowObj == null) {
895 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800896 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700897 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800898
899 //
900 // Extract the Flow state
901 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800902 FlowPath flowPath = extractFlowPath(flowObj);
903 conn.endTx(Transaction.COMMIT);
904
905 return flowPath;
906 }
907
908 /**
909 * Get all previously added flows by a specific installer for a given
910 * data path endpoints.
911 *
912 * @param installerId the Caller ID of the installer of the flow to get.
913 * @param dataPathEndpoints the data path endpoints of the flow to get.
914 * @return the Flow Paths if found, otherwise null.
915 */
916 @Override
917 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
918 DataPathEndpoints dataPathEndpoints) {
919 //
920 // TODO: The implementation below is not optimal:
921 // We fetch all flows, and then return only the subset that match
922 // the query conditions.
923 // We should use the appropriate Titan/Gremlin query to filter-out
924 // the flows as appropriate.
925 //
926 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700927 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800928
929 if (allFlows == null) {
930 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700931 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800932 }
933
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800934 for (FlowPath flow : allFlows) {
935 //
936 // TODO: String-based comparison is sub-optimal.
937 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800938 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800939 //
940 if (! flow.installerId().toString().equals(installerId.toString()))
941 continue;
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 installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800953 } else {
954 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
955 }
956
957 return flowPaths;
958 }
959
960 /**
961 * Get all installed flows by all installers for given data path endpoints.
962 *
963 * @param dataPathEndpoints the data path endpoints of the flows to get.
964 * @return the Flow Paths if found, otherwise null.
965 */
966 @Override
967 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
968 //
969 // TODO: The implementation below is not optimal:
970 // We fetch all flows, and then return only the subset that match
971 // the query conditions.
972 // We should use the appropriate Titan/Gremlin query to filter-out
973 // the flows as appropriate.
974 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700975 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
976 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800977
978 if (allFlows == null) {
979 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700980 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800981 }
982
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800983 for (FlowPath flow : allFlows) {
984 //
985 // TODO: String-based comparison is sub-optimal.
986 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800987 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800988 //
989 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
990 continue;
991 }
992 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
993 continue;
994 }
995 flowPaths.add(flow);
996 }
997
998 if (flowPaths.isEmpty()) {
999 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001000 } else {
1001 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1002 }
1003
1004 return flowPaths;
1005 }
1006
1007 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001008 * Get summary of all installed flows by all installers in a given range
1009 *
1010 * @param flowId the data path endpoints of the flows to get.
1011 * @param maxFlows: the maximum number of flows to be returned
1012 * @return the Flow Paths if found, otherwise null.
1013 */
1014 @Override
1015 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1016 //
1017 // TODO: The implementation below is not optimal:
1018 // We fetch all flows, and then return only the subset that match
1019 // the query conditions.
1020 // We should use the appropriate Titan/Gremlin query to filter-out
1021 // the flows as appropriate.
1022 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001023 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1024
1025 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001026
1027 if (allFlows == null) {
1028 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001029 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001030 }
1031
1032 Collections.sort(allFlows);
1033
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001034 for (FlowPath flow : allFlows) {
1035
1036 // start from desired flowId
1037 if (flow.flowId().value() < flowId.value()) {
1038 continue;
1039 }
1040
1041 // Summarize by making null flow entry fields that are not relevant to report
1042 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1043 flowEntry.setFlowEntryActions(null);
1044 flowEntry.setFlowEntryMatch(null);
1045 }
1046
1047 flowPaths.add(flow);
1048 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1049 break;
1050 }
1051 }
1052
1053 if (flowPaths.isEmpty()) {
1054 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001055 } else {
1056 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1057 }
1058
1059 return flowPaths;
1060 }
1061
1062 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001063 * Get all installed flows by all installers.
1064 *
1065 * @return the Flow Paths if found, otherwise null.
1066 */
1067 @Override
1068 public ArrayList<FlowPath> getAllFlows() {
1069 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001070 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001071
1072 try {
1073 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1074 log.debug("Get all FlowPaths: found FlowPaths");
1075 } else {
1076 log.debug("Get all FlowPaths: no FlowPaths found");
1077 }
1078 } catch (Exception e) {
1079 // TODO: handle exceptions
1080 conn.endTx(Transaction.ROLLBACK);
1081 log.error(":getAllFlowPaths failed");
1082 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001083 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1084 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001085 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001086 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001087
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001088 for (IFlowPath flowObj : flowPathsObj) {
1089 //
1090 // Extract the Flow state
1091 //
1092 FlowPath flowPath = extractFlowPath(flowObj);
1093 flowPaths.add(flowPath);
1094 }
1095
1096 conn.endTx(Transaction.COMMIT);
1097
1098 return flowPaths;
1099 }
1100
1101 /**
1102 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1103 *
1104 * @param flowObj the object to extract the Flow Path State from.
1105 * @return the extracted Flow Path State.
1106 */
1107 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001108 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001109
1110 //
1111 // Extract the Flow state
1112 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001113 flowPath.setFlowId(new FlowId(flowObj.getFlowId()));
1114 flowPath.setInstallerId(new CallerId(flowObj.getInstallerId()));
1115 flowPath.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
1116 flowPath.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
1117 flowPath.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
1118 flowPath.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
1119
1120 //
1121 // Extract all Flow Entries
1122 //
1123 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1124 for (IFlowEntry flowEntryObj : flowEntries) {
1125 FlowEntry flowEntry = new FlowEntry();
1126 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
1127 flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001128
1129 //
1130 // Extract the match conditions
1131 //
1132 FlowEntryMatch match = new FlowEntryMatch();
1133 Short matchInPort = flowEntryObj.getMatchInPort();
1134 if (matchInPort != null)
1135 match.enableInPort(new Port(matchInPort));
1136 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1137 if (matchEthernetFrameType != null)
1138 match.enableEthernetFrameType(matchEthernetFrameType);
1139 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1140 if (matchSrcIPv4Net != null)
1141 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1142 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1143 if (matchDstIPv4Net != null)
1144 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1145 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1146 if (matchSrcMac != null)
1147 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1148 String matchDstMac = flowEntryObj.getMatchDstMac();
1149 if (matchDstMac != null)
1150 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1151 flowEntry.setFlowEntryMatch(match);
1152
1153 //
1154 // Extract the actions
1155 //
1156 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1157 Short actionOutputPort = flowEntryObj.getActionOutput();
1158 if (actionOutputPort != null) {
1159 FlowEntryAction action = new FlowEntryAction();
1160 action.setActionOutput(new Port(actionOutputPort));
1161 actions.add(action);
1162 }
1163 flowEntry.setFlowEntryActions(actions);
1164
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001165 String userState = flowEntryObj.getUserState();
1166 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1167 String switchState = flowEntryObj.getSwitchState();
1168 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1169 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001170 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001171 // and FlowEntryErrorState.
1172 //
1173 flowPath.dataPath().flowEntries().add(flowEntry);
1174 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001175
1176 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001177 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001178}