blob: 1b454237625998f083c87c479afe9d622a78ee4b [file] [log] [blame]
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001package net.floodlightcontroller.flowcache;
2
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08004import java.util.ArrayList;
5import java.util.Collection;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08006import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08007import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00008import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08009import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080010import java.util.Map;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070011import java.util.TreeMap;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070012import java.util.Collections;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070013import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070015import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.ScheduledExecutorService;
17import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070018import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IFloodlightProviderService;
22import net.floodlightcontroller.core.INetMapStorage;
23import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
24import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070025import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070026import 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 Radoslavovb9fe6b42013-03-27 16:25:05 -070053import net.onrc.onos.flow.IFlowManager;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080054import net.onrc.onos.util.GraphDBConnection;
55import net.onrc.onos.util.GraphDBConnection.Transaction;
56
57import org.openflow.protocol.OFFlowMod;
58import org.openflow.protocol.OFMatch;
59import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070060import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080061import org.openflow.protocol.OFType;
62import org.openflow.protocol.action.OFAction;
63import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080064
65import org.slf4j.Logger;
66import org.slf4j.LoggerFactory;
67
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070068public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080069
70 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080071
72 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080073 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070074 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070075 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080076
77 protected OFMessageDamper messageDamper;
78
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070079 //
80 // TODO: Values copied from elsewhere (class LearningSwitch).
81 // The local copy should go away!
82 //
83 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
84 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
85 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
86 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
87 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080088
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070089 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070090 private static long measurementFlowId = 100000;
91 private static String measurementFlowIdStr = "0x186a0"; // 100000
92 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070093
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080094 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080095 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
96
97 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070098 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080099 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700100 private final ScheduledExecutorService measureMapReaderScheduler =
101 Executors.newScheduledThreadPool(1);
102 private final ScheduledExecutorService mapReaderScheduler =
103 Executors.newScheduledThreadPool(1);
104
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700105 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
106 private ThreadPoolExecutor shortestPathExecutor =
107 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
108
109 class ShortestPathTask implements Runnable {
110 private int hint;
111 private ITopoRouteService topoRouteService;
112 private ArrayList<DataPath> dpList;
113
114 public ShortestPathTask(int hint,
115 ITopoRouteService topoRouteService,
116 ArrayList<DataPath> dpList) {
117 this.hint = hint;
118 this.topoRouteService = topoRouteService;
119 this.dpList = dpList;
120 }
121
122 @Override
123 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700124 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700125 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
126 log.debug(logMsg);
127 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700128 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700129 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700130 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700131 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700132 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700133 long estimatedTime = System.nanoTime() - startTime;
134 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
135 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
136 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700137 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700138 }
139 }
140
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700141 final Runnable measureShortestPath = new Runnable() {
142 public void run() {
143 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
144 if (floodlightProvider == null) {
145 log.debug("FloodlightProvider service not found!");
146 return;
147 }
148
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700149 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 Radoslavovb9fe6b42013-03-27 16:25:05 -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
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700342 // TODO: PAVPAVPAV: FROM HERE...
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800343 //
344 // Create the Open Flow Flow Modification Entry to push
345 //
346 OFFlowMod fm =
347 (OFFlowMod) floodlightProvider.getOFMessageFactory()
348 .getMessage(OFType.FLOW_MOD);
349 long cookie = flowEntryId.value();
350
351 short flowModCommand = OFFlowMod.OFPFC_ADD;
352 if (userState.equals("FE_USER_ADD")) {
353 flowModCommand = OFFlowMod.OFPFC_ADD;
354 } else if (userState.equals("FE_USER_MODIFY")) {
355 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
356 } else if (userState.equals("FE_USER_DELETE")) {
357 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
358 } else {
359 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700360 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
361 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800362 continue;
363 }
364
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700365 //
366 // Fetch the match conditions
367 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800368 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700369 match.setWildcards(OFMatch.OFPFW_ALL);
370 Short matchInPort = flowEntryObj.getMatchInPort();
371 if (matchInPort != null) {
372 match.setInputPort(matchInPort);
373 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
374 }
375 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
376 if (matchEthernetFrameType != null) {
377 match.setDataLayerType(matchEthernetFrameType);
378 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
379 }
380 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
381 if (matchSrcIPv4Net != null) {
382 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
383 }
384 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
385 if (matchDstIPv4Net != null) {
386 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
387 }
388 String matchSrcMac = flowEntryObj.getMatchSrcMac();
389 if (matchSrcMac != null) {
390 match.setDataLayerSource(matchSrcMac);
391 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
392 }
393 String matchDstMac = flowEntryObj.getMatchDstMac();
394 if (matchDstMac != null) {
395 match.setDataLayerDestination(matchDstMac);
396 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
397 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700398
399 //
400 // Fetch the actions
401 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800402 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700403 Short actionOutputPort = flowEntryObj.getActionOutput();
404 if (actionOutputPort != null) {
405 OFActionOutput action = new OFActionOutput();
406 // XXX: The max length is hard-coded for now
407 action.setMaxLength((short)0xffff);
408 action.setPort(actionOutputPort);
409 actions.add(action);
410 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800411
412 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
413 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700414 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800415 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
416 .setCookie(cookie)
417 .setCommand(flowModCommand)
418 .setMatch(match)
419 .setActions(actions)
420 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700421 fm.setOutPort(OFPort.OFPP_NONE.getValue());
422 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
423 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
424 if (actionOutputPort != null)
425 fm.setOutPort(actionOutputPort);
426 }
427
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800428 //
429 // TODO: Set the following flag
430 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
431 // See method ForwardingBase::pushRoute()
432 //
433 try {
434 messageDamper.write(mySwitch, fm, null);
435 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000436 //
437 // TODO: We should use the OpenFlow Barrier mechanism
438 // to check for errors, and update the SwitchState
439 // for a flow entry after the Barrier message is
440 // is received.
441 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800442 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
443 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000444 // An entry that needs to be deleted.
445 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800446 }
447 } catch (IOException e) {
448 log.error("Failure writing flow mod from network map", e);
449 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700450 // TODO: XXX: PAVPAVPAV: TO HERE.
451 // TODO: XXX: PAVPAVPAV: Update the flowEntryObj
452 // to "FE_SWITCH_UPDATED" in the new (refactored) code.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800453 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000454
455 //
456 // Delete all entries marked for deletion
457 //
458 // TODO: We should use the OpenFlow Barrier mechanism
459 // to check for errors, and delete the Flow Entries after the
460 // Barrier message is received.
461 //
462 while (! deleteFlowEntries.isEmpty()) {
463 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
464 IFlowPath flowObj =
465 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
466 if (flowObj == null) {
467 log.debug("Did not find FlowPath to be deleted");
468 continue;
469 }
470 flowObj.removeFlowEntry(flowEntryObj);
471 conn.utils().removeFlowEntry(conn, flowEntryObj);
472
473 // Test whether the last flow entry
474 Iterable<IFlowEntry> tmpflowEntries =
475 flowObj.getFlowEntries();
476 boolean found = false;
477 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
478 found = true;
479 break;
480 }
481 if (! found) {
482 // Remove the Flow Path as well
483 conn.utils().removeFlowPath(conn, flowObj);
484 }
485 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800486 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700487
488 if (processed_measurement_flow) {
489 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
490 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
491 (double)estimatedTime / 1000000000 + " sec";
492 log.debug(logMsg);
493 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800494 }
495 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700496
497 /*
498 final ScheduledFuture<?> measureShortestPathHandle =
499 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
500 */
501
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700502 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700503 final ScheduledFuture<?> measureMapReaderHandle =
504 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700505 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700506
507 final ScheduledFuture<?> mapReaderHandle =
508 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800509
510 @Override
511 public void init(String conf) {
512 conn = GraphDBConnection.getInstance(conf);
513 }
514
515 public void finalize() {
516 close();
517 }
518
519 @Override
520 public void close() {
521 conn.close();
522 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800523
524 @Override
525 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
526 Collection<Class<? extends IFloodlightService>> l =
527 new ArrayList<Class<? extends IFloodlightService>>();
528 l.add(IFlowService.class);
529 return l;
530 }
531
532 @Override
533 public Map<Class<? extends IFloodlightService>, IFloodlightService>
534 getServiceImpls() {
535 Map<Class<? extends IFloodlightService>,
536 IFloodlightService> m =
537 new HashMap<Class<? extends IFloodlightService>,
538 IFloodlightService>();
539 m.put(IFlowService.class, this);
540 return m;
541 }
542
543 @Override
544 public Collection<Class<? extends IFloodlightService>>
545 getModuleDependencies() {
546 Collection<Class<? extends IFloodlightService>> l =
547 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800548 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700549 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800550 l.add(IRestApiService.class);
551 return l;
552 }
553
554 @Override
555 public void init(FloodlightModuleContext context)
556 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700557 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800558 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700559 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800560 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800561 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
562 EnumSet.of(OFType.FLOW_MOD),
563 OFMESSAGE_DAMPER_TIMEOUT);
564 // TODO: An ugly hack!
565 String conf = "/tmp/cassandra.titan";
566 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800567 }
568
569 @Override
570 public void startUp(FloodlightModuleContext context) {
571 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700572
573 //
574 // Extract all flow entries and assign the next Flow Entry ID
575 // to be larger than the largest Flow Entry ID
576 //
577 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
578 for (IFlowEntry flowEntryObj : allFlowEntries) {
579 FlowEntryId flowEntryId =
580 new FlowEntryId(flowEntryObj.getFlowEntryId());
581 if (flowEntryId.value() >= nextFlowEntryId)
582 nextFlowEntryId = flowEntryId.value() + 1;
583 }
584 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800585 }
586
587 /**
588 * Add a flow.
589 *
590 * Internally, ONOS will automatically register the installer for
591 * receiving Flow Path Notifications for that path.
592 *
593 * @param flowPath the Flow Path to install.
594 * @param flowId the return-by-reference Flow ID as assigned internally.
595 * @return true on success, otherwise false.
596 */
597 @Override
598 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700599 if (flowPath.flowId().value() == measurementFlowId) {
600 modifiedMeasurementFlowTime = System.nanoTime();
601 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800602
603 //
604 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700605 // Right now every new flow entry gets a new flow entry ID
606 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800607 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800608 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700609 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800610 flowEntry.setFlowEntryId(new FlowEntryId(id));
611 }
612
613 IFlowPath flowObj = null;
614 try {
615 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
616 != null) {
617 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
618 flowPath.flowId().toString());
619 } else {
620 flowObj = conn.utils().newFlowPath(conn);
621 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
622 flowPath.flowId().toString());
623 }
624 } catch (Exception e) {
625 // TODO: handle exceptions
626 conn.endTx(Transaction.ROLLBACK);
627 log.error(":addFlow FlowId:{} failed",
628 flowPath.flowId().toString());
629 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700630 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000631 log.error(":addFlow FlowId:{} failed: Flow object not created",
632 flowPath.flowId().toString());
633 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800634 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700635 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800636
637 //
638 // Set the Flow key:
639 // - flowId
640 //
641 flowObj.setFlowId(flowPath.flowId().toString());
642 flowObj.setType("flow");
643
644 //
645 // Set the Flow attributes:
646 // - flowPath.installerId()
647 // - flowPath.dataPath().srcPort()
648 // - flowPath.dataPath().dstPort()
649 //
650 flowObj.setInstallerId(flowPath.installerId().toString());
651 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
652 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
653 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
654 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
655
656 // Flow edges:
657 // HeadFE
658
659
660 //
661 // Flow Entries:
662 // flowPath.dataPath().flowEntries()
663 //
664 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
665 IFlowEntry flowEntryObj = null;
666 boolean found = false;
667 try {
668 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
669 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
670 flowEntry.flowEntryId().toString());
671 found = true;
672 } else {
673 flowEntryObj = conn.utils().newFlowEntry(conn);
674 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
675 flowEntry.flowEntryId().toString());
676 }
677 } catch (Exception e) {
678 // TODO: handle exceptions
679 conn.endTx(Transaction.ROLLBACK);
680 log.error(":addFlow FlowEntryId:{} failed",
681 flowEntry.flowEntryId().toString());
682 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700683 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000684 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
685 flowEntry.flowEntryId().toString());
686 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800687 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700688 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800689
690 //
691 // Set the Flow Entry key:
692 // - flowEntry.flowEntryId()
693 //
694 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
695 flowEntryObj.setType("flow_entry");
696
697 //
698 // Set the Flow Entry attributes:
699 // - flowEntry.flowEntryMatch()
700 // - flowEntry.flowEntryActions()
701 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800702 // - flowEntry.flowEntryUserState()
703 // - flowEntry.flowEntrySwitchState()
704 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700705 // - flowEntry.matchInPort()
706 // - flowEntry.matchEthernetFrameType()
707 // - flowEntry.matchSrcIPv4Net()
708 // - flowEntry.matchDstIPv4Net()
709 // - flowEntry.matchSrcMac()
710 // - flowEntry.matchDstMac()
711 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800712 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700713 ISwitchObject sw =
714 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800715 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700716 flowEntryObj.setSwitch(sw);
717 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700718 IPortObject inport =
719 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
720 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700721 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
722 flowEntryObj.setInPort(inport);
723 }
724 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
725 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
726 }
727 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
728 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
729 }
730 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
731 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
732 }
733 if (flowEntry.flowEntryMatch().matchSrcMac()) {
734 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
735 }
736 if (flowEntry.flowEntryMatch().matchDstMac()) {
737 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
738 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700739
740 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700741 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700742 IPortObject outport =
743 conn.utils().searchPort(conn,
744 flowEntry.dpid().toString(),
745 fa.actionOutput().port().value());
746 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
747 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700748 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700749 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800750 // TODO: Hacks with hard-coded state names!
751 if (found)
752 flowEntryObj.setUserState("FE_USER_MODIFY");
753 else
754 flowEntryObj.setUserState("FE_USER_ADD");
755 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
756 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800757 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800758 // and FlowEntryErrorState.
759 //
760
761 // Flow Entries edges:
762 // Flow
763 // NextFE
764 // InPort
765 // OutPort
766 // Switch
767 if (! found)
768 flowObj.addFlowEntry(flowEntryObj);
769 }
770 conn.endTx(Transaction.COMMIT);
771
772 //
773 // TODO: We need a proper Flow ID allocation mechanism.
774 //
775 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700776
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800777 return true;
778 }
779
780 /**
781 * Delete a previously added flow.
782 *
783 * @param flowId the Flow ID of the flow to delete.
784 * @return true on success, otherwise false.
785 */
786 @Override
787 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700788 if (flowId.value() == measurementFlowId) {
789 modifiedMeasurementFlowTime = System.nanoTime();
790 }
791
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800792 IFlowPath flowObj = null;
793 //
794 // We just mark the entries for deletion,
795 // and let the switches remove each individual entry after
796 // it has been removed from the switches.
797 //
798 try {
799 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
800 != null) {
801 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
802 flowId.toString());
803 } else {
804 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
805 flowId.toString());
806 }
807 } catch (Exception e) {
808 // TODO: handle exceptions
809 conn.endTx(Transaction.ROLLBACK);
810 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
811 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700812 if (flowObj == null) {
813 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800814 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700815 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800816
817 //
818 // Find and mark for deletion all Flow Entries
819 //
820 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
821 boolean empty = true; // TODO: an ugly hack
822 for (IFlowEntry flowEntryObj : flowEntries) {
823 empty = false;
824 // flowObj.removeFlowEntry(flowEntryObj);
825 // conn.utils().removeFlowEntry(conn, flowEntryObj);
826 flowEntryObj.setUserState("FE_USER_DELETE");
827 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
828 }
829 // Remove from the database empty flows
830 if (empty)
831 conn.utils().removeFlowPath(conn, flowObj);
832 conn.endTx(Transaction.COMMIT);
833
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800834 return true;
835 }
836
837 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700838 * Clear the state for a previously added flow.
839 *
840 * @param flowId the Flow ID of the flow to clear.
841 * @return true on success, otherwise false.
842 */
843 @Override
844 public boolean clearFlow(FlowId flowId) {
845 IFlowPath flowObj = null;
846 try {
847 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
848 != null) {
849 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
850 flowId.toString());
851 } else {
852 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
853 flowId.toString());
854 }
855 } catch (Exception e) {
856 // TODO: handle exceptions
857 conn.endTx(Transaction.ROLLBACK);
858 log.error(":clearFlow FlowId:{} failed", flowId.toString());
859 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700860 if (flowObj == null) {
861 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700862 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700863 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700864
865 //
866 // Remove all Flow Entries
867 //
868 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
869 for (IFlowEntry flowEntryObj : flowEntries) {
870 flowObj.removeFlowEntry(flowEntryObj);
871 conn.utils().removeFlowEntry(conn, flowEntryObj);
872 }
873 // Remove the Flow itself
874 conn.utils().removeFlowPath(conn, flowObj);
875 conn.endTx(Transaction.COMMIT);
876
877 return true;
878 }
879
880 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800881 * Get a previously added flow.
882 *
883 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800884 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800885 */
886 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800887 public FlowPath getFlow(FlowId flowId) {
888 IFlowPath flowObj = null;
889 try {
890 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
891 != null) {
892 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
893 flowId.toString());
894 } else {
895 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
896 flowId.toString());
897 }
898 } catch (Exception e) {
899 // TODO: handle exceptions
900 conn.endTx(Transaction.ROLLBACK);
901 log.error(":getFlow FlowId:{} failed", flowId.toString());
902 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700903 if (flowObj == null) {
904 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800905 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700906 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800907
908 //
909 // Extract the Flow state
910 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800911 FlowPath flowPath = extractFlowPath(flowObj);
912 conn.endTx(Transaction.COMMIT);
913
914 return flowPath;
915 }
916
917 /**
918 * Get all previously added flows by a specific installer for a given
919 * data path endpoints.
920 *
921 * @param installerId the Caller ID of the installer of the flow to get.
922 * @param dataPathEndpoints the data path endpoints of the flow to get.
923 * @return the Flow Paths if found, otherwise null.
924 */
925 @Override
926 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
927 DataPathEndpoints dataPathEndpoints) {
928 //
929 // TODO: The implementation below is not optimal:
930 // We fetch all flows, and then return only the subset that match
931 // the query conditions.
932 // We should use the appropriate Titan/Gremlin query to filter-out
933 // the flows as appropriate.
934 //
935 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700936 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800937
938 if (allFlows == null) {
939 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700940 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800941 }
942
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800943 for (FlowPath flow : allFlows) {
944 //
945 // TODO: String-based comparison is sub-optimal.
946 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800947 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800948 //
949 if (! flow.installerId().toString().equals(installerId.toString()))
950 continue;
951 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
952 continue;
953 }
954 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
955 continue;
956 }
957 flowPaths.add(flow);
958 }
959
960 if (flowPaths.isEmpty()) {
961 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800962 } else {
963 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
964 }
965
966 return flowPaths;
967 }
968
969 /**
970 * Get all installed flows by all installers for given data path endpoints.
971 *
972 * @param dataPathEndpoints the data path endpoints of the flows to get.
973 * @return the Flow Paths if found, otherwise null.
974 */
975 @Override
976 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
977 //
978 // TODO: The implementation below is not optimal:
979 // We fetch all flows, and then return only the subset that match
980 // the query conditions.
981 // We should use the appropriate Titan/Gremlin query to filter-out
982 // the flows as appropriate.
983 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700984 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
985 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800986
987 if (allFlows == null) {
988 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700989 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800990 }
991
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800992 for (FlowPath flow : allFlows) {
993 //
994 // TODO: String-based comparison is sub-optimal.
995 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800996 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800997 //
998 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
999 continue;
1000 }
1001 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1002 continue;
1003 }
1004 flowPaths.add(flow);
1005 }
1006
1007 if (flowPaths.isEmpty()) {
1008 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001009 } else {
1010 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1011 }
1012
1013 return flowPaths;
1014 }
1015
1016 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001017 * Get summary of all installed flows by all installers in a given range
1018 *
1019 * @param flowId the data path endpoints of the flows to get.
1020 * @param maxFlows: the maximum number of flows to be returned
1021 * @return the Flow Paths if found, otherwise null.
1022 */
1023 @Override
1024 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1025 //
1026 // TODO: The implementation below is not optimal:
1027 // We fetch all flows, and then return only the subset that match
1028 // the query conditions.
1029 // We should use the appropriate Titan/Gremlin query to filter-out
1030 // the flows as appropriate.
1031 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001032 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1033
1034 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001035
1036 if (allFlows == null) {
1037 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001038 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001039 }
1040
1041 Collections.sort(allFlows);
1042
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001043 for (FlowPath flow : allFlows) {
1044
1045 // start from desired flowId
1046 if (flow.flowId().value() < flowId.value()) {
1047 continue;
1048 }
1049
1050 // Summarize by making null flow entry fields that are not relevant to report
1051 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1052 flowEntry.setFlowEntryActions(null);
1053 flowEntry.setFlowEntryMatch(null);
1054 }
1055
1056 flowPaths.add(flow);
1057 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1058 break;
1059 }
1060 }
1061
1062 if (flowPaths.isEmpty()) {
1063 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001064 } else {
1065 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1066 }
1067
1068 return flowPaths;
1069 }
1070
1071 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001072 * Get all installed flows by all installers.
1073 *
1074 * @return the Flow Paths if found, otherwise null.
1075 */
1076 @Override
1077 public ArrayList<FlowPath> getAllFlows() {
1078 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001079 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001080
1081 try {
1082 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1083 log.debug("Get all FlowPaths: found FlowPaths");
1084 } else {
1085 log.debug("Get all FlowPaths: no FlowPaths found");
1086 }
1087 } catch (Exception e) {
1088 // TODO: handle exceptions
1089 conn.endTx(Transaction.ROLLBACK);
1090 log.error(":getAllFlowPaths failed");
1091 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001092 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1093 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001094 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001095 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001096
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001097 for (IFlowPath flowObj : flowPathsObj) {
1098 //
1099 // Extract the Flow state
1100 //
1101 FlowPath flowPath = extractFlowPath(flowObj);
1102 flowPaths.add(flowPath);
1103 }
1104
1105 conn.endTx(Transaction.COMMIT);
1106
1107 return flowPaths;
1108 }
1109
1110 /**
1111 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1112 *
1113 * @param flowObj the object to extract the Flow Path State from.
1114 * @return the extracted Flow Path State.
1115 */
1116 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001117 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001118
1119 //
1120 // Extract the Flow state
1121 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001122 String flowIdStr = flowObj.getFlowId();
1123 String installerIdStr = flowObj.getInstallerId();
1124 String srcSwitchStr = flowObj.getSrcSwitch();
1125 Short srcPortStr = flowObj.getSrcPort();
1126 String dstSwitchStr = flowObj.getDstSwitch();
1127 Short dstPortStr = flowObj.getDstPort();
1128
1129 if ((flowIdStr == null) ||
1130 (installerIdStr == null) ||
1131 (srcSwitchStr == null) ||
1132 (srcPortStr == null) ||
1133 (dstSwitchStr == null) ||
1134 (dstPortStr == null)) {
1135 // TODO: A work-around, becauuse of some bogus database objects
1136 return null;
1137 }
1138
1139 flowPath.setFlowId(new FlowId(flowIdStr));
1140 flowPath.setInstallerId(new CallerId(installerIdStr));
1141 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
1142 flowPath.dataPath().srcPort().setPort(new Port(srcPortStr));
1143 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
1144 flowPath.dataPath().dstPort().setPort(new Port(dstPortStr));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001145
1146 //
1147 // Extract all Flow Entries
1148 //
1149 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1150 for (IFlowEntry flowEntryObj : flowEntries) {
1151 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001152 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1153 String switchDpidStr = flowEntryObj.getSwitchDpid();
1154 String userState = flowEntryObj.getUserState();
1155 String switchState = flowEntryObj.getSwitchState();
1156
1157 if ((flowEntryIdStr == null) ||
1158 (switchDpidStr == null) ||
1159 (userState == null) ||
1160 (switchState == null)) {
1161 // TODO: A work-around, becauuse of some bogus database objects
1162 continue;
1163 }
1164 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1165 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001166
1167 //
1168 // Extract the match conditions
1169 //
1170 FlowEntryMatch match = new FlowEntryMatch();
1171 Short matchInPort = flowEntryObj.getMatchInPort();
1172 if (matchInPort != null)
1173 match.enableInPort(new Port(matchInPort));
1174 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1175 if (matchEthernetFrameType != null)
1176 match.enableEthernetFrameType(matchEthernetFrameType);
1177 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1178 if (matchSrcIPv4Net != null)
1179 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1180 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1181 if (matchDstIPv4Net != null)
1182 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1183 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1184 if (matchSrcMac != null)
1185 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1186 String matchDstMac = flowEntryObj.getMatchDstMac();
1187 if (matchDstMac != null)
1188 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1189 flowEntry.setFlowEntryMatch(match);
1190
1191 //
1192 // Extract the actions
1193 //
1194 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1195 Short actionOutputPort = flowEntryObj.getActionOutput();
1196 if (actionOutputPort != null) {
1197 FlowEntryAction action = new FlowEntryAction();
1198 action.setActionOutput(new Port(actionOutputPort));
1199 actions.add(action);
1200 }
1201 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001202 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001203 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1204 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001205 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001206 // and FlowEntryErrorState.
1207 //
1208 flowPath.dataPath().flowEntries().add(flowEntry);
1209 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001210
1211 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001212 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001213
1214 /**
1215 * Add and maintain a shortest-path flow.
1216 *
1217 * NOTE: The Flow Path does NOT contain all flow entries.
1218 * Instead, it contains a single dummy flow entry that is used to
1219 * store the matching condition(s).
1220 * That entry is replaced by the appropriate entries from the
1221 * internally performed shortest-path computation.
1222 *
1223 * @param flowPath the Flow Path with the endpoints and the match
1224 * conditions to install.
1225 * @param flowId the return-by-reference Flow ID as assigned internally.
1226 * @return true on success, otherwise false.
1227 */
1228 @Override
1229 public boolean addAndMaintainShortestPathFlow(FlowPath flowPath,
1230 FlowId flowId) {
1231 //
1232 // Do the shortest path computation
1233 //
1234 DataPath dataPath =
1235 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1236 flowPath.dataPath().dstPort());
1237 if (dataPath == null)
1238 return false;
1239
1240 FlowEntryMatch userFlowEntryMatch = null;
1241 if (! flowPath.dataPath().flowEntries().isEmpty()) {
1242 userFlowEntryMatch = flowPath.dataPath().flowEntries().get(0).flowEntryMatch();
1243 }
1244
1245 //
1246 // Set the incoming port matching and the outgoing port output
1247 // actions for each flow entry.
1248 //
1249 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1250 // Set the incoming port matching
1251 FlowEntryMatch flowEntryMatch = null;
1252 if (userFlowEntryMatch != null)
1253 flowEntryMatch = new FlowEntryMatch(userFlowEntryMatch);
1254 else
1255 flowEntryMatch = new FlowEntryMatch();
1256 flowEntry.setFlowEntryMatch(flowEntryMatch);
1257 flowEntryMatch.enableInPort(flowEntry.inPort());
1258
1259 // Set the outgoing port output action
1260 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1261 if (flowEntryActions == null) {
1262 flowEntryActions = new ArrayList<FlowEntryAction>();
1263 flowEntry.setFlowEntryActions(flowEntryActions);
1264 }
1265 FlowEntryAction flowEntryAction = new FlowEntryAction();
1266 flowEntryAction.setActionOutput(flowEntry.outPort());
1267 flowEntryActions.add(flowEntryAction);
1268 }
1269
1270 //
1271 // Prepare the computed Flow Path
1272 //
1273 FlowPath resultFlowPath = new FlowPath();
1274 resultFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1275 resultFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1276 resultFlowPath.setDataPath(dataPath);
1277
1278 boolean returnValue = addFlow(resultFlowPath, flowId);
1279
1280 // TODO: Mark the flow for maintenance purpose
1281
1282 return (returnValue);
1283 }
1284
1285 /**
1286 * Create a Flow from port to port.
1287 *
1288 * TODO: We don't need it for now.
1289 *
1290 * @param src_port the source port.
1291 * @param dest_port the destination port.
1292 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001293 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001294 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1295 // TODO: We don't need it for now.
1296 }
1297
1298 /**
1299 * Get all Flows matching a source and a destination port.
1300 *
1301 * TODO: Pankaj might be implementing it later.
1302 *
1303 * @param src_port the source port to match.
1304 * @param dest_port the destination port to match.
1305 * @return all flows matching the source and the destination port.
1306 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001307 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001308 public Iterable<FlowPath> getFlows(IPortObject src_port,
1309 IPortObject dest_port) {
1310 // TODO: Pankaj might be implementing it later.
1311 return null;
1312 }
1313
1314 /**
1315 * Get all Flows going out from a port.
1316 *
1317 * TODO: We need it now: Pankaj
1318 *
1319 * @param port the port to match.
1320 * @return the list of flows that are going out from the port.
1321 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001322 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001323 public Iterable<FlowPath> getFlows(IPortObject port) {
1324 // TODO: We need it now: Pankaj
1325 return null;
1326 }
1327
1328 /**
1329 * Reconcile all flows on inactive port (src port of link which might be
1330 * broken).
1331 *
1332 * TODO: We need it now: Pavlin
1333 *
1334 * @param src_port the port that has become inactive.
1335 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001336 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001337 public void reconcileFlows(IPortObject src_port) {
1338 // TODO: We need it now: Pavlin
1339
1340 // TODO: It should call installFlowEntry() as appropriate.
1341 }
1342
1343 /**
1344 * Reconcile all flows between a source and a destination port.
1345 *
1346 * TODO: We don't need it for now.
1347 *
1348 * @param src_port the source port.
1349 * @param dest_port the destination port.
1350 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001351 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001352 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1353 // TODO: We don't need it for now.
1354 }
1355
1356 /**
1357 * Compute the shortest path between a source and a destination ports.
1358 *
1359 * @param src_port the source port.
1360 * @param dest_port the destination port.
1361 * @return the computed shortest path between the source and the
1362 * destination ports. The flow entries in the path itself would
1363 * contain the incoming port matching and the outgoing port output
1364 * actions set. However, the path itself will NOT have the Flow ID,
1365 * Installer ID, and any additional matching conditions for the
1366 * flow entries (e.g., source or destination MAC address, etc).
1367 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001368 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001369 public FlowPath computeFlowPath(IPortObject src_port,
1370 IPortObject dest_port) {
1371 //
1372 // Prepare the arguments
1373 //
1374 String dpidStr = src_port.getSwitch().getDPID();
1375 Dpid srcDpid = new Dpid(dpidStr);
1376 Port srcPort = new Port(src_port.getNumber());
1377
1378 dpidStr = dest_port.getSwitch().getDPID();
1379 Dpid dstDpid = new Dpid(dpidStr);
1380 Port dstPort = new Port(dest_port.getNumber());
1381
1382 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1383 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1384
1385 //
1386 // Do the shortest path computation
1387 //
1388 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1389 if (dataPath == null)
1390 return null;
1391
1392 //
1393 // Set the incoming port matching and the outgoing port output
1394 // actions for each flow entry.
1395 //
1396 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1397 // Set the incoming port matching
1398 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1399 if (flowEntryMatch == null) {
1400 flowEntryMatch = new FlowEntryMatch();
1401 flowEntry.setFlowEntryMatch(flowEntryMatch);
1402 }
1403 flowEntryMatch.enableInPort(flowEntry.inPort());
1404
1405 // Set the outgoing port output action
1406 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1407 if (flowEntryActions == null) {
1408 flowEntryActions = new ArrayList<FlowEntryAction>();
1409 flowEntry.setFlowEntryActions(flowEntryActions);
1410 }
1411 FlowEntryAction flowEntryAction = new FlowEntryAction();
1412 flowEntryAction.setActionOutput(flowEntry.outPort());
1413 flowEntryActions.add(flowEntryAction);
1414 }
1415
1416 //
1417 // Prepare the return result
1418 //
1419 FlowPath flowPath = new FlowPath();
1420 flowPath.setDataPath(dataPath);
1421
1422 return flowPath;
1423 }
1424
1425 /**
1426 * Get all Flow Entries of a Flow.
1427 *
1428 * @param flow the flow whose flow entries should be returned.
1429 * @return the flow entries of the flow.
1430 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001431 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001432 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1433 return flow.dataPath().flowEntries();
1434 }
1435
1436 /**
1437 * Install a Flow Entry on a switch.
1438 *
1439 * @param mySwitches the DPID-to-Switch mapping for the switches
1440 * controlled by this controller.
1441 * @param flowEntry the flow entry to install.
1442 * @return true on success, otherwise false.
1443 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001444 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001445 public boolean installFlowEntry(Map<Long, IOFSwitch> mySwitches,
1446 FlowEntry flowEntry) {
1447 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1448 if (mySwitch == null) {
1449 // Not my switch
1450 return (installRemoteFlowEntry(flowEntry));
1451 }
1452
1453 //
1454 // Create the OpenFlow Flow Modification Entry to push
1455 //
1456 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1457 .getMessage(OFType.FLOW_MOD);
1458 long cookie = flowEntry.flowEntryId().value();
1459
1460 short flowModCommand = OFFlowMod.OFPFC_ADD;
1461 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1462 flowModCommand = OFFlowMod.OFPFC_ADD;
1463 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1464 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1465 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1466 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1467 } else {
1468 // Unknown user state. Ignore the entry
1469 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1470 flowEntry.flowEntryId().toString(),
1471 flowEntry.flowEntryUserState());
1472 return false;
1473 }
1474
1475 //
1476 // Fetch the match conditions
1477 //
1478 OFMatch match = new OFMatch();
1479 match.setWildcards(OFMatch.OFPFW_ALL);
1480 Port matchInPort = flowEntry.flowEntryMatch().inPort();
1481 if (matchInPort != null) {
1482 match.setInputPort(matchInPort.value());
1483 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1484 }
1485 Short matchEthernetFrameType =
1486 flowEntry.flowEntryMatch().ethernetFrameType();
1487 if (matchEthernetFrameType != null) {
1488 match.setDataLayerType(matchEthernetFrameType);
1489 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1490 }
1491 IPv4Net matchSrcIPv4Net = flowEntry.flowEntryMatch().srcIPv4Net();
1492 if (matchSrcIPv4Net != null) {
1493 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1494 }
1495 IPv4Net matchDstIPv4Net = flowEntry.flowEntryMatch().dstIPv4Net();
1496 if (matchDstIPv4Net != null) {
1497 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1498 }
1499 MACAddress matchSrcMac = flowEntry.flowEntryMatch().srcMac();
1500 if (matchSrcMac != null) {
1501 match.setDataLayerSource(matchSrcMac.toString());
1502 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1503 }
1504 MACAddress matchDstMac = flowEntry.flowEntryMatch().dstMac();
1505 if (matchDstMac != null) {
1506 match.setDataLayerDestination(matchDstMac.toString());
1507 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1508 }
1509
1510 //
1511 // Fetch the actions
1512 //
1513 // TODO: For now we support only the "OUTPUT" actions.
1514 //
1515 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1516 List<OFAction> actions = new ArrayList<OFAction>();
1517 ArrayList<FlowEntryAction> flowEntryActions =
1518 flowEntry.flowEntryActions();
1519 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1520 FlowEntryAction.ActionOutput actionOutput =
1521 flowEntryAction.actionOutput();
1522 if (actionOutput != null) {
1523 short actionOutputPort = actionOutput.port().value();
1524 OFActionOutput action = new OFActionOutput();
1525 // XXX: The max length is hard-coded for now
1526 action.setMaxLength((short)0xffff);
1527 action.setPort(actionOutputPort);
1528 actions.add(action);
1529 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1530 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1531 fm.setOutPort(actionOutputPort);
1532 }
1533 }
1534 }
1535
1536 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1537 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1538 .setPriority(PRIORITY_DEFAULT)
1539 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1540 .setCookie(cookie)
1541 .setCommand(flowModCommand)
1542 .setMatch(match)
1543 .setActions(actions)
1544 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1545
1546 //
1547 // TODO: Set the following flag
1548 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1549 // See method ForwardingBase::pushRoute()
1550 //
1551
1552 //
1553 // Write the message to the switch
1554 //
1555 try {
1556 messageDamper.write(mySwitch, fm, null);
1557 mySwitch.flush();
1558 } catch (IOException e) {
1559 log.error("Failure writing flow mod from network map", e);
1560 return false;
1561 }
1562 return true;
1563 }
1564
1565 /**
1566 * Remove a Flow Entry from a switch.
1567 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001568 * @param mySwitches the DPID-to-Switch mapping for the switches
1569 * controlled by this controller.
1570 * @param flowEntry the flow entry to remove.
1571 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001572 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001573 @Override
1574 public boolean removeFlowEntry(Map<Long, IOFSwitch> mySwitches,
1575 FlowEntry flowEntry) {
1576 //
1577 // The installFlowEntry() method implements both installation
1578 // and removal of flow entries.
1579 //
1580 return (installFlowEntry(mySwitches, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001581 }
1582
1583 /**
1584 * Install a Flow Entry on a remote controller.
1585 *
1586 * TODO: We need it now: Jono
1587 * - For now it will make a REST call to the remote controller.
1588 * - Internally, it needs to know the name of the remote controller.
1589 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001590 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001591 * @return true on success, otherwise false.
1592 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001593 @Override
1594 public boolean installRemoteFlowEntry(FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001595 // TODO: We need it now: Jono
1596 // - For now it will make a REST call to the remote controller.
1597 // - Internally, it needs to know the name of the remote controller.
1598 return true;
1599 }
1600
1601 /**
1602 * Remove a flow entry on a remote controller.
1603 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001604 * @param flowEntry the flow entry to remove.
1605 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001606 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001607 @Override
1608 public boolean removeRemoteFlowEntry(FlowEntry flowEntry) {
1609 //
1610 // The installRemoteFlowEntry() method implements both installation
1611 // and removal of flow entries.
1612 //
1613 return (installRemoteFlowEntry(flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001614 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001615}