blob: 8cbf1847311c411de946f599b94df014277ec254 [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 Radoslavov0b22d0e2013-04-02 01:12:46 +00006import java.util.Collections;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08007import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08008import java.util.HashMap;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07009import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000010import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080012import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000013import java.util.Random;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070014import java.util.TreeMap;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070015import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070017import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080018import java.util.concurrent.ScheduledExecutorService;
19import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070020import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080022
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080023import net.floodlightcontroller.core.IFloodlightProviderService;
24import net.floodlightcontroller.core.INetMapStorage;
25import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
26import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070027import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070028import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070029import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080030import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080031import net.floodlightcontroller.core.module.FloodlightModuleContext;
32import net.floodlightcontroller.core.module.FloodlightModuleException;
33import net.floodlightcontroller.core.module.IFloodlightModule;
34import net.floodlightcontroller.core.module.IFloodlightService;
35import net.floodlightcontroller.flowcache.IFlowService;
36import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
37import net.floodlightcontroller.restserver.IRestApiService;
38import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.DataPath;
40import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080041import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080042import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070043import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080044import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070045import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046import net.floodlightcontroller.util.FlowEntrySwitchState;
47import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080048import net.floodlightcontroller.util.FlowId;
49import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070050import net.floodlightcontroller.util.IPv4Net;
51import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080052import net.floodlightcontroller.util.OFMessageDamper;
53import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070054import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070055import net.onrc.onos.flow.IFlowManager;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056import net.onrc.onos.util.GraphDBConnection;
57import net.onrc.onos.util.GraphDBConnection.Transaction;
58
59import org.openflow.protocol.OFFlowMod;
60import org.openflow.protocol.OFMatch;
61import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070062import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080063import org.openflow.protocol.OFType;
64import org.openflow.protocol.action.OFAction;
65import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080066
67import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070070public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071
72 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080073
74 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080075 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070076 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070077 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080078
79 protected OFMessageDamper messageDamper;
80
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070081 //
82 // TODO: Values copied from elsewhere (class LearningSwitch).
83 // The local copy should go away!
84 //
85 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
86 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
87 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
88 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
89 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080090
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000091 // Flow Entry ID generation state
92 private static Random randomGenerator = new Random();
93 private static int nextFlowEntryIdPrefix = 0;
94 private static int nextFlowEntryIdSuffix = 0;
95 private static long nextFlowEntryId = 0;
96
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070097 private static long measurementFlowId = 100000;
98 private static String measurementFlowIdStr = "0x186a0"; // 100000
99 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700100
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800101 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800102 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
103
104 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700105 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800106 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700107 private final ScheduledExecutorService measureMapReaderScheduler =
108 Executors.newScheduledThreadPool(1);
109 private final ScheduledExecutorService mapReaderScheduler =
110 Executors.newScheduledThreadPool(1);
111
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700112 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
113 private ThreadPoolExecutor shortestPathExecutor =
114 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
115
116 class ShortestPathTask implements Runnable {
117 private int hint;
118 private ITopoRouteService topoRouteService;
119 private ArrayList<DataPath> dpList;
120
121 public ShortestPathTask(int hint,
122 ITopoRouteService topoRouteService,
123 ArrayList<DataPath> dpList) {
124 this.hint = hint;
125 this.topoRouteService = topoRouteService;
126 this.dpList = dpList;
127 }
128
129 @Override
130 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700131 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700132 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
133 log.debug(logMsg);
134 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700135 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700136 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700137 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700138 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700139 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700140 long estimatedTime = System.nanoTime() - startTime;
141 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
142 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
143 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700144 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700145 }
146 }
147
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700148 final Runnable measureShortestPath = new Runnable() {
149 public void run() {
150 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
151 if (floodlightProvider == null) {
152 log.debug("FloodlightProvider service not found!");
153 return;
154 }
155
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700156 if (topoRouteService == null) {
157 log.debug("Topology Route Service not found");
158 return;
159 }
160
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700161 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
162 if (leftoverQueueSize > 0) {
163 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
164 log.debug(logMsg);
165 return;
166 }
167 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
168
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700169 //
170 // Recompute the Shortest Paths for all Flows
171 //
172 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700173 int hint = 0;
174 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700175 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700176
177 topoRouteService.prepareShortestPathTopo();
178
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700179 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
180 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700181 FlowId flowId = new FlowId(flowPathObj.getFlowId());
182
183 // log.debug("Found Path {}", flowId.toString());
184 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
185 Port srcPort = new Port(flowPathObj.getSrcPort());
186 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
187 Port dstPort = new Port(flowPathObj.getDstPort());
188 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
189 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700190
191 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700192 DataPath dp = new DataPath();
193 dp.setSrcPort(srcSwitchPort);
194 dp.setDstPort(dstSwitchPort);
195 dpList.add(dp);
196 if ((dpList.size() % 10) == 0) {
197 shortestPathExecutor.execute(
198 new ShortestPathTask(hint, topoRouteService,
199 dpList));
200 dpList = new ArrayList<DataPath>();
201 hint++;
202 }
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700203 */
204
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700205 DataPath dataPath =
206 topoRouteService.getTopoShortestPath(srcSwitchPort,
207 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700208 counter++;
209 }
210 if (dpList.size() > 0) {
211 shortestPathExecutor.execute(
212 new ShortestPathTask(hint, topoRouteService,
213 dpList));
214 }
215
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700216 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700217 // Wait for all tasks to finish
218 try {
219 while (shortestPathExecutor.getQueue().size() > 0) {
220 Thread.sleep(100);
221 }
222 } catch (InterruptedException ex) {
223 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700224 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700225 */
226
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700227 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700228 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700229
230 long estimatedTime = System.nanoTime() - startTime;
231 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
232 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
233 log.debug(logMsg);
234 }
235 };
236
237 final Runnable measureMapReader = new Runnable() {
238 public void run() {
239 if (floodlightProvider == null) {
240 log.debug("FloodlightProvider service not found!");
241 return;
242 }
243
244 //
245 // Fetch all Flow Entries
246 //
247 int counter = 0;
248 long startTime = System.nanoTime();
249 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
250 for (IFlowEntry flowEntryObj : allFlowEntries) {
251 counter++;
252 FlowEntryId flowEntryId =
253 new FlowEntryId(flowEntryObj.getFlowEntryId());
254 String userState = flowEntryObj.getUserState();
255 String switchState = flowEntryObj.getSwitchState();
256 }
257 conn.endTx(Transaction.COMMIT);
258
259 long estimatedTime = System.nanoTime() - startTime;
260 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
261 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
262 log.debug(logMsg);
263 }
264 };
265
266 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800267 public void run() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700268 long startTime = System.nanoTime();
269 int counterAllFlowEntries = 0;
270 int counterMyNotUpdatedFlowEntries = 0;
271 int counterAllFlowPaths = 0;
272 int counterMyFlowPaths = 0;
273
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800274 if (floodlightProvider == null) {
275 log.debug("FloodlightProvider service not found!");
276 return;
277 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000278 Map<Long, IOFSwitch> mySwitches =
279 floodlightProvider.getSwitches();
280 Map<Long, IFlowEntry> myFlowEntries =
281 new TreeMap<Long, IFlowEntry>();
282 LinkedList<IFlowEntry> deleteFlowEntries =
283 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700284
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700285
286 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700287 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700288 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700289 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000290 Iterable<IFlowEntry> allFlowEntries =
291 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700292 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700293 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000294 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700295 String userState = flowEntryObj.getUserState();
296 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000297 String dpidStr = flowEntryObj.getSwitchDpid();
298 if ((flowEntryIdStr == null) ||
299 (userState == null) ||
300 (switchState == null) ||
301 (dpidStr == null)) {
302 log.debug("IGNORING Flow Entry entry with null fields");
303 continue;
304 }
305 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
306 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800307
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000308 /*
309 log.debug("Found Flow Entry Id = {} {}",
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700310 flowEntryId.toString(),
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000311 "DPID = " + dpid.toString() +
312 " User State: " + userState +
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700313 " Switch State: " + switchState);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000314 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800315
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000316 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
317 continue; // Ignore the entry: nothing to do
318
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800319 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000320 if (mySwitch == null)
321 continue; // Ignore the entry: not my switch
322
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700323 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
324 }
325
326 //
327 // Process my Flow Entries
328 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700329 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700330 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700331 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700332 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700333 IFlowPath flowObj =
334 conn.utils().getFlowPathByFlowEntry(conn,
335 flowEntryObj);
336 if (flowObj == null)
337 continue; // Should NOT happen
338
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700339 // Code for measurement purpose
340 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700341 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700342 processed_measurement_flow = true;
343 }
344 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700345
346 //
347 // TODO: Eliminate the re-fetching of flowEntryId,
348 // userState, switchState, and dpid from the flowEntryObj.
349 //
350 FlowEntryId flowEntryId =
351 new FlowEntryId(flowEntryObj.getFlowEntryId());
352 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
353 String userState = flowEntryObj.getUserState();
354 String switchState = flowEntryObj.getSwitchState();
355 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000356 if (mySwitch == null)
357 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800358
359 //
360 // Create the Open Flow Flow Modification Entry to push
361 //
362 OFFlowMod fm =
363 (OFFlowMod) floodlightProvider.getOFMessageFactory()
364 .getMessage(OFType.FLOW_MOD);
365 long cookie = flowEntryId.value();
366
367 short flowModCommand = OFFlowMod.OFPFC_ADD;
368 if (userState.equals("FE_USER_ADD")) {
369 flowModCommand = OFFlowMod.OFPFC_ADD;
370 } else if (userState.equals("FE_USER_MODIFY")) {
371 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
372 } else if (userState.equals("FE_USER_DELETE")) {
373 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
374 } else {
375 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700376 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
377 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800378 continue;
379 }
380
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700381 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700382 // Fetch the match conditions.
383 //
384 // NOTE: The Flow matching conditions common for all
385 // Flow Entries are used ONLY if a Flow Entry does NOT
386 // have the corresponding matching condition set.
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700387 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800388 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700389 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700390 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700391 Short matchInPort = flowEntryObj.getMatchInPort();
392 if (matchInPort != null) {
393 match.setInputPort(matchInPort);
394 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
395 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700396 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700397 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700398 if (matchEthernetFrameType == null)
399 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700400 if (matchEthernetFrameType != null) {
401 match.setDataLayerType(matchEthernetFrameType);
402 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
403 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700404 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700405 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700406 if (matchSrcIPv4Net == null)
407 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700408 if (matchSrcIPv4Net != null) {
409 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
410 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700411 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700412 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700413 if (matchDstIPv4Net == null)
414 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700415 if (matchDstIPv4Net != null) {
416 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
417 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700418 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700419 String matchSrcMac = flowEntryObj.getMatchSrcMac();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700420 if (matchSrcMac == null)
421 matchSrcMac = flowObj.getMatchSrcMac();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700422 if (matchSrcMac != null) {
423 match.setDataLayerSource(matchSrcMac);
424 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
425 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700426 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700427 String matchDstMac = flowEntryObj.getMatchDstMac();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700428 if (matchDstMac == null)
429 matchDstMac = flowObj.getMatchDstMac();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700430 if (matchDstMac != null) {
431 match.setDataLayerDestination(matchDstMac);
432 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
433 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700434
435 //
436 // Fetch the actions
437 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800438 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700439 Short actionOutputPort = flowEntryObj.getActionOutput();
440 if (actionOutputPort != null) {
441 OFActionOutput action = new OFActionOutput();
442 // XXX: The max length is hard-coded for now
443 action.setMaxLength((short)0xffff);
444 action.setPort(actionOutputPort);
445 actions.add(action);
446 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800447
448 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
449 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700450 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800451 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
452 .setCookie(cookie)
453 .setCommand(flowModCommand)
454 .setMatch(match)
455 .setActions(actions)
456 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700457 fm.setOutPort(OFPort.OFPP_NONE.getValue());
458 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
459 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
460 if (actionOutputPort != null)
461 fm.setOutPort(actionOutputPort);
462 }
463
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800464 //
465 // TODO: Set the following flag
466 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
467 // See method ForwardingBase::pushRoute()
468 //
469 try {
470 messageDamper.write(mySwitch, fm, null);
471 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000472 //
473 // TODO: We should use the OpenFlow Barrier mechanism
474 // to check for errors, and update the SwitchState
475 // for a flow entry after the Barrier message is
476 // is received.
477 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800478 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
479 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000480 // An entry that needs to be deleted.
481 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800482 }
483 } catch (IOException e) {
484 log.error("Failure writing flow mod from network map", e);
485 }
486 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000487
488 //
489 // Delete all entries marked for deletion
490 //
491 // TODO: We should use the OpenFlow Barrier mechanism
492 // to check for errors, and delete the Flow Entries after the
493 // Barrier message is received.
494 //
495 while (! deleteFlowEntries.isEmpty()) {
496 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
497 IFlowPath flowObj =
498 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
499 if (flowObj == null) {
500 log.debug("Did not find FlowPath to be deleted");
501 continue;
502 }
503 flowObj.removeFlowEntry(flowEntryObj);
504 conn.utils().removeFlowEntry(conn, flowEntryObj);
505
506 // Test whether the last flow entry
507 Iterable<IFlowEntry> tmpflowEntries =
508 flowObj.getFlowEntries();
509 boolean found = false;
510 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
511 found = true;
512 break;
513 }
514 if (! found) {
515 // Remove the Flow Path as well
516 conn.utils().removeFlowPath(conn, flowObj);
517 }
518 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700519
520
521 //
522 // Fetch and recompute the Shortest Path for those
523 // Flow Paths this controller is responsible for.
524 //
525
526 /*
527 * TODO: For now, the computation of the reconciliation is
528 * commented-out.
529 */
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700530 topoRouteService.prepareShortestPathTopo();
531 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
532 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
533 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700534 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700535 if (flowPathObj == null)
536 continue;
537 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
538 if (dataPathSummaryStr == null)
539 continue; // Could be invalid entry?
540 if (dataPathSummaryStr.isEmpty())
541 continue; // No need to maintain this flow
542
543 // Fetch the fields needed to recompute the shortest path
544 String flowIdStr = flowPathObj.getFlowId();
545 String srcDpidStr = flowPathObj.getSrcSwitch();
546 Short srcPortShort = flowPathObj.getSrcPort();
547 String dstDpidStr = flowPathObj.getDstSwitch();
548 Short dstPortShort = flowPathObj.getDstPort();
549 if ((flowIdStr == null) ||
550 (srcDpidStr == null) ||
551 (srcPortShort == null) ||
552 (dstDpidStr == null) ||
553 (dstPortShort == null)) {
554 log.debug("IGNORING Flow Path entry with null fields");
555 continue;
556 }
557
558 FlowId flowId = new FlowId(flowIdStr);
559 Dpid srcDpid = new Dpid(srcDpidStr);
560 Port srcPort = new Port(srcPortShort);
561 Dpid dstDpid = new Dpid(dstDpidStr);
562 Port dstPort = new Port(dstPortShort);
563 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
564 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700565 //
566 // NOTE: Using here the regular getShortestPath() method
567 // won't work here, because that method calls internally
568 // "conn.endTx(Transaction.COMMIT)", and that will
569 // invalidate all handlers to the Titan database.
570 // If we want to experiment with calling here
571 // getShortestPath(), we need to refactor that code
572 // to avoid closing the transaction.
573 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700574 DataPath dataPath =
575 topoRouteService.getTopoShortestPath(srcSwitchPort,
576 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000577 if (dataPath == null) {
578 // We need the DataPath to compare the paths
579 dataPath = new DataPath();
580 dataPath.setSrcPort(srcSwitchPort);
581 dataPath.setDstPort(dstSwitchPort);
582 }
583
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700584 String newDataPathSummaryStr = dataPath.dataPathSummary();
585 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
586 continue; // Nothing changed
587
588 //
589 // Use the source DPID as a heuristic to decide
590 // which controller is responsible for maintaining the
591 // shortest path.
592 // NOTE: This heuristic is error-prone: if the switch
593 // goes away and no controller is responsible for that
594 // switch, then the original Flow Path is not cleaned-up
595 //
596 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
597 if (mySwitch == null)
598 continue; // Ignore: not my responsibility
599
600 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
601 flowId.toString());
602 flowObjSet.add(flowPathObj);
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700603 counterMyFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700604 }
605 reconcileFlows(flowObjSet);
606 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700607
608
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800609 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700610
611 if (processed_measurement_flow) {
612 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
613 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
614 (double)estimatedTime / 1000000000 + " sec";
615 log.debug(logMsg);
616 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700617
618 long estimatedTime = System.nanoTime() - startTime;
619 double rate = (estimatedTime > 0)? ((double)counterAllFlowPaths * 1000000000) / estimatedTime: 0.0;
620 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " + counterAllFlowEntries + " MyNotUpdatedFlowEntries: " + counterMyNotUpdatedFlowEntries + " AllFlowPaths: " + counterAllFlowPaths + " MyFlowPaths: " + counterMyFlowPaths + " in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " paths/s";
621 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800622 }
623 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700624
625 /*
626 final ScheduledFuture<?> measureShortestPathHandle =
627 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
628 */
629
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700630 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700631 final ScheduledFuture<?> measureMapReaderHandle =
632 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700633 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700634
635 final ScheduledFuture<?> mapReaderHandle =
636 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800637
638 @Override
639 public void init(String conf) {
640 conn = GraphDBConnection.getInstance(conf);
641 }
642
643 public void finalize() {
644 close();
645 }
646
647 @Override
648 public void close() {
649 conn.close();
650 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800651
652 @Override
653 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
654 Collection<Class<? extends IFloodlightService>> l =
655 new ArrayList<Class<? extends IFloodlightService>>();
656 l.add(IFlowService.class);
657 return l;
658 }
659
660 @Override
661 public Map<Class<? extends IFloodlightService>, IFloodlightService>
662 getServiceImpls() {
663 Map<Class<? extends IFloodlightService>,
664 IFloodlightService> m =
665 new HashMap<Class<? extends IFloodlightService>,
666 IFloodlightService>();
667 m.put(IFlowService.class, this);
668 return m;
669 }
670
671 @Override
672 public Collection<Class<? extends IFloodlightService>>
673 getModuleDependencies() {
674 Collection<Class<? extends IFloodlightService>> l =
675 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800676 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700677 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800678 l.add(IRestApiService.class);
679 return l;
680 }
681
682 @Override
683 public void init(FloodlightModuleContext context)
684 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700685 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800686 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700687 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800688 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800689 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
690 EnumSet.of(OFType.FLOW_MOD),
691 OFMESSAGE_DAMPER_TIMEOUT);
692 // TODO: An ugly hack!
693 String conf = "/tmp/cassandra.titan";
694 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800695 }
696
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000697 private long getNextFlowEntryId() {
698 //
699 // Generate the next Flow Entry ID.
700 // NOTE: For now, the higher 32 bits are random, and
701 // the lower 32 bits are sequential.
702 // In the future, we need a better allocation mechanism.
703 //
704 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
705 nextFlowEntryIdPrefix = randomGenerator.nextInt();
706 nextFlowEntryIdSuffix = 0;
707 } else {
708 nextFlowEntryIdSuffix++;
709 }
710 long result = (long)nextFlowEntryIdPrefix << 32;
711 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
712 return result;
713 }
714
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800715 @Override
716 public void startUp(FloodlightModuleContext context) {
717 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700718
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000719 // Initialize the Flow Entry ID generator
720 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800721 }
722
723 /**
724 * Add a flow.
725 *
726 * Internally, ONOS will automatically register the installer for
727 * receiving Flow Path Notifications for that path.
728 *
729 * @param flowPath the Flow Path to install.
730 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700731 * @param dataPathSummaryStr the data path summary string if the added
732 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800733 * @return true on success, otherwise false.
734 */
735 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700736 public boolean addFlow(FlowPath flowPath, FlowId flowId,
737 String dataPathSummaryStr) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700738 if (flowPath.flowId().value() == measurementFlowId) {
739 modifiedMeasurementFlowTime = System.nanoTime();
740 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800741
742 //
743 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700744 // Right now every new flow entry gets a new flow entry ID
745 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800746 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800747 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000748 long id = getNextFlowEntryId();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800749 flowEntry.setFlowEntryId(new FlowEntryId(id));
750 }
751
752 IFlowPath flowObj = null;
753 try {
754 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
755 != null) {
756 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
757 flowPath.flowId().toString());
758 } else {
759 flowObj = conn.utils().newFlowPath(conn);
760 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
761 flowPath.flowId().toString());
762 }
763 } catch (Exception e) {
764 // TODO: handle exceptions
765 conn.endTx(Transaction.ROLLBACK);
766 log.error(":addFlow FlowId:{} failed",
767 flowPath.flowId().toString());
768 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700769 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000770 log.error(":addFlow FlowId:{} failed: Flow object not created",
771 flowPath.flowId().toString());
772 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800773 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700774 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800775
776 //
777 // Set the Flow key:
778 // - flowId
779 //
780 flowObj.setFlowId(flowPath.flowId().toString());
781 flowObj.setType("flow");
782
783 //
784 // Set the Flow attributes:
785 // - flowPath.installerId()
786 // - flowPath.dataPath().srcPort()
787 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700788 // - flowPath.matchEthernetFrameType()
789 // - flowPath.matchSrcIPv4Net()
790 // - flowPath.matchDstIPv4Net()
791 // - flowPath.matchSrcMac()
792 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800793 //
794 flowObj.setInstallerId(flowPath.installerId().toString());
795 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
796 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
797 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
798 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700799 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
800 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
801 }
802 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
803 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
804 }
805 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
806 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
807 }
808 if (flowPath.flowEntryMatch().matchSrcMac()) {
809 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
810 }
811 if (flowPath.flowEntryMatch().matchDstMac()) {
812 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
813 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800814
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700815 if (dataPathSummaryStr != null) {
816 flowObj.setDataPathSummary(dataPathSummaryStr);
817 } else {
818 flowObj.setDataPathSummary("");
819 }
820
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800821 // Flow edges:
822 // HeadFE
823
824
825 //
826 // Flow Entries:
827 // flowPath.dataPath().flowEntries()
828 //
829 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
830 IFlowEntry flowEntryObj = null;
831 boolean found = false;
832 try {
833 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
834 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
835 flowEntry.flowEntryId().toString());
836 found = true;
837 } else {
838 flowEntryObj = conn.utils().newFlowEntry(conn);
839 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
840 flowEntry.flowEntryId().toString());
841 }
842 } catch (Exception e) {
843 // TODO: handle exceptions
844 conn.endTx(Transaction.ROLLBACK);
845 log.error(":addFlow FlowEntryId:{} failed",
846 flowEntry.flowEntryId().toString());
847 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700848 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000849 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
850 flowEntry.flowEntryId().toString());
851 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800852 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700853 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800854
855 //
856 // Set the Flow Entry key:
857 // - flowEntry.flowEntryId()
858 //
859 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
860 flowEntryObj.setType("flow_entry");
861
862 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700863 // Set the Flow Entry Edges and attributes:
864 // - Switch edge
865 // - InPort edge
866 // - OutPort edge
867 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800868 // - flowEntry.flowEntryMatch()
869 // - flowEntry.flowEntryActions()
870 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800871 // - flowEntry.flowEntryUserState()
872 // - flowEntry.flowEntrySwitchState()
873 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700874 // - flowEntry.matchInPort()
875 // - flowEntry.matchEthernetFrameType()
876 // - flowEntry.matchSrcIPv4Net()
877 // - flowEntry.matchDstIPv4Net()
878 // - flowEntry.matchSrcMac()
879 // - flowEntry.matchDstMac()
880 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800881 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700882 ISwitchObject sw =
883 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800884 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700885 flowEntryObj.setSwitch(sw);
886 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700887 IPortObject inport =
888 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
889 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700890 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
891 flowEntryObj.setInPort(inport);
892 }
893 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
894 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
895 }
896 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
897 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
898 }
899 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
900 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
901 }
902 if (flowEntry.flowEntryMatch().matchSrcMac()) {
903 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
904 }
905 if (flowEntry.flowEntryMatch().matchDstMac()) {
906 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
907 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700908
909 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700910 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700911 IPortObject outport =
912 conn.utils().searchPort(conn,
913 flowEntry.dpid().toString(),
914 fa.actionOutput().port().value());
915 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
916 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700917 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700918 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800919 // TODO: Hacks with hard-coded state names!
920 if (found)
921 flowEntryObj.setUserState("FE_USER_MODIFY");
922 else
923 flowEntryObj.setUserState("FE_USER_ADD");
924 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
925 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700926 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800927 //
928
929 // Flow Entries edges:
930 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700931 // NextFE (TODO)
932 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800933 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700934 flowEntryObj.setFlow(flowObj);
935 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800936 }
937 conn.endTx(Transaction.COMMIT);
938
939 //
940 // TODO: We need a proper Flow ID allocation mechanism.
941 //
942 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700943
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800944 return true;
945 }
946
947 /**
948 * Delete a previously added flow.
949 *
950 * @param flowId the Flow ID of the flow to delete.
951 * @return true on success, otherwise false.
952 */
953 @Override
954 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700955 if (flowId.value() == measurementFlowId) {
956 modifiedMeasurementFlowTime = System.nanoTime();
957 }
958
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800959 IFlowPath flowObj = null;
960 //
961 // We just mark the entries for deletion,
962 // and let the switches remove each individual entry after
963 // it has been removed from the switches.
964 //
965 try {
966 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
967 != null) {
968 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
969 flowId.toString());
970 } else {
971 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
972 flowId.toString());
973 }
974 } catch (Exception e) {
975 // TODO: handle exceptions
976 conn.endTx(Transaction.ROLLBACK);
977 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
978 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700979 if (flowObj == null) {
980 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800981 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700982 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800983
984 //
985 // Find and mark for deletion all Flow Entries
986 //
987 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
988 boolean empty = true; // TODO: an ugly hack
989 for (IFlowEntry flowEntryObj : flowEntries) {
990 empty = false;
991 // flowObj.removeFlowEntry(flowEntryObj);
992 // conn.utils().removeFlowEntry(conn, flowEntryObj);
993 flowEntryObj.setUserState("FE_USER_DELETE");
994 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
995 }
996 // Remove from the database empty flows
997 if (empty)
998 conn.utils().removeFlowPath(conn, flowObj);
999 conn.endTx(Transaction.COMMIT);
1000
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001001 return true;
1002 }
1003
1004 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001005 * Clear the state for a previously added flow.
1006 *
1007 * @param flowId the Flow ID of the flow to clear.
1008 * @return true on success, otherwise false.
1009 */
1010 @Override
1011 public boolean clearFlow(FlowId flowId) {
1012 IFlowPath flowObj = null;
1013 try {
1014 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
1015 != null) {
1016 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1017 flowId.toString());
1018 } else {
1019 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1020 flowId.toString());
1021 }
1022 } catch (Exception e) {
1023 // TODO: handle exceptions
1024 conn.endTx(Transaction.ROLLBACK);
1025 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1026 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001027 if (flowObj == null) {
1028 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001029 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001030 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001031
1032 //
1033 // Remove all Flow Entries
1034 //
1035 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1036 for (IFlowEntry flowEntryObj : flowEntries) {
1037 flowObj.removeFlowEntry(flowEntryObj);
1038 conn.utils().removeFlowEntry(conn, flowEntryObj);
1039 }
1040 // Remove the Flow itself
1041 conn.utils().removeFlowPath(conn, flowObj);
1042 conn.endTx(Transaction.COMMIT);
1043
1044 return true;
1045 }
1046
1047 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001048 * Get a previously added flow.
1049 *
1050 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001051 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001052 */
1053 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001054 public FlowPath getFlow(FlowId flowId) {
1055 IFlowPath flowObj = null;
1056 try {
1057 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
1058 != null) {
1059 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1060 flowId.toString());
1061 } else {
1062 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1063 flowId.toString());
1064 }
1065 } catch (Exception e) {
1066 // TODO: handle exceptions
1067 conn.endTx(Transaction.ROLLBACK);
1068 log.error(":getFlow FlowId:{} failed", flowId.toString());
1069 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001070 if (flowObj == null) {
1071 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001072 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001073 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001074
1075 //
1076 // Extract the Flow state
1077 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001078 FlowPath flowPath = extractFlowPath(flowObj);
1079 conn.endTx(Transaction.COMMIT);
1080
1081 return flowPath;
1082 }
1083
1084 /**
1085 * Get all previously added flows by a specific installer for a given
1086 * data path endpoints.
1087 *
1088 * @param installerId the Caller ID of the installer of the flow to get.
1089 * @param dataPathEndpoints the data path endpoints of the flow to get.
1090 * @return the Flow Paths if found, otherwise null.
1091 */
1092 @Override
1093 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1094 DataPathEndpoints dataPathEndpoints) {
1095 //
1096 // TODO: The implementation below is not optimal:
1097 // We fetch all flows, and then return only the subset that match
1098 // the query conditions.
1099 // We should use the appropriate Titan/Gremlin query to filter-out
1100 // the flows as appropriate.
1101 //
1102 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001103 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001104
1105 if (allFlows == null) {
1106 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001107 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001108 }
1109
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001110 for (FlowPath flow : allFlows) {
1111 //
1112 // TODO: String-based comparison is sub-optimal.
1113 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001114 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001115 //
1116 if (! flow.installerId().toString().equals(installerId.toString()))
1117 continue;
1118 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1119 continue;
1120 }
1121 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1122 continue;
1123 }
1124 flowPaths.add(flow);
1125 }
1126
1127 if (flowPaths.isEmpty()) {
1128 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001129 } else {
1130 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1131 }
1132
1133 return flowPaths;
1134 }
1135
1136 /**
1137 * Get all installed flows by all installers for given data path endpoints.
1138 *
1139 * @param dataPathEndpoints the data path endpoints of the flows to get.
1140 * @return the Flow Paths if found, otherwise null.
1141 */
1142 @Override
1143 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1144 //
1145 // TODO: The implementation below is not optimal:
1146 // We fetch all flows, and then return only the subset that match
1147 // the query conditions.
1148 // We should use the appropriate Titan/Gremlin query to filter-out
1149 // the flows as appropriate.
1150 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001151 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1152 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001153
1154 if (allFlows == null) {
1155 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001156 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001157 }
1158
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001159 for (FlowPath flow : allFlows) {
1160 //
1161 // TODO: String-based comparison is sub-optimal.
1162 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001163 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001164 //
1165 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1166 continue;
1167 }
1168 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1169 continue;
1170 }
1171 flowPaths.add(flow);
1172 }
1173
1174 if (flowPaths.isEmpty()) {
1175 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001176 } else {
1177 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1178 }
1179
1180 return flowPaths;
1181 }
1182
1183 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001184 * Get summary of all installed flows by all installers in a given range
1185 *
1186 * @param flowId the data path endpoints of the flows to get.
1187 * @param maxFlows: the maximum number of flows to be returned
1188 * @return the Flow Paths if found, otherwise null.
1189 */
1190 @Override
1191 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1192 //
1193 // TODO: The implementation below is not optimal:
1194 // We fetch all flows, and then return only the subset that match
1195 // the query conditions.
1196 // We should use the appropriate Titan/Gremlin query to filter-out
1197 // the flows as appropriate.
1198 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001199 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1200
1201 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001202
1203 if (allFlows == null) {
1204 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001205 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001206 }
1207
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001208 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001209
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001210 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001211 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001212
1213 // start from desired flowId
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -07001214 //if (flow.flowId().value() < flowId.value()) {
1215 // continue;
1216 //}
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001217
1218 // Summarize by making null flow entry fields that are not relevant to report
1219 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1220 flowEntry.setFlowEntryActions(null);
1221 flowEntry.setFlowEntryMatch(null);
1222 }
1223
1224 flowPaths.add(flow);
1225 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1226 break;
1227 }
1228 }
1229
1230 if (flowPaths.isEmpty()) {
1231 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001232 } else {
1233 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1234 }
1235
1236 return flowPaths;
1237 }
1238
1239 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001240 * Get all installed flows by all installers.
1241 *
1242 * @return the Flow Paths if found, otherwise null.
1243 */
1244 @Override
1245 public ArrayList<FlowPath> getAllFlows() {
1246 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001247 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001248
1249 try {
1250 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1251 log.debug("Get all FlowPaths: found FlowPaths");
1252 } else {
1253 log.debug("Get all FlowPaths: no FlowPaths found");
1254 }
1255 } catch (Exception e) {
1256 // TODO: handle exceptions
1257 conn.endTx(Transaction.ROLLBACK);
1258 log.error(":getAllFlowPaths failed");
1259 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001260 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1261 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001262 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001263 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001264
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001265 for (IFlowPath flowObj : flowPathsObj) {
1266 //
1267 // Extract the Flow state
1268 //
1269 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001270 if (flowPath != null)
1271 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001272 }
1273
1274 conn.endTx(Transaction.COMMIT);
1275
1276 return flowPaths;
1277 }
1278
1279 /**
1280 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1281 *
1282 * @param flowObj the object to extract the Flow Path State from.
1283 * @return the extracted Flow Path State.
1284 */
1285 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001286 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001287
1288 //
1289 // Extract the Flow state
1290 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001291 String flowIdStr = flowObj.getFlowId();
1292 String installerIdStr = flowObj.getInstallerId();
1293 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001294 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001295 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001296 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001297
1298 if ((flowIdStr == null) ||
1299 (installerIdStr == null) ||
1300 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001301 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001302 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001303 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001304 // TODO: A work-around, becauuse of some bogus database objects
1305 return null;
1306 }
1307
1308 flowPath.setFlowId(new FlowId(flowIdStr));
1309 flowPath.setInstallerId(new CallerId(installerIdStr));
1310 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001311 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001312 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001313 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001314 //
1315 // Extract the match conditions common for all Flow Entries
1316 //
1317 {
1318 FlowEntryMatch match = new FlowEntryMatch();
1319 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1320 if (matchEthernetFrameType != null)
1321 match.enableEthernetFrameType(matchEthernetFrameType);
1322 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1323 if (matchSrcIPv4Net != null)
1324 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1325 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1326 if (matchDstIPv4Net != null)
1327 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1328 String matchSrcMac = flowObj.getMatchSrcMac();
1329 if (matchSrcMac != null)
1330 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1331 String matchDstMac = flowObj.getMatchDstMac();
1332 if (matchDstMac != null)
1333 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1334 flowPath.setFlowEntryMatch(match);
1335 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001336
1337 //
1338 // Extract all Flow Entries
1339 //
1340 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1341 for (IFlowEntry flowEntryObj : flowEntries) {
1342 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001343 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1344 String switchDpidStr = flowEntryObj.getSwitchDpid();
1345 String userState = flowEntryObj.getUserState();
1346 String switchState = flowEntryObj.getSwitchState();
1347
1348 if ((flowEntryIdStr == null) ||
1349 (switchDpidStr == null) ||
1350 (userState == null) ||
1351 (switchState == null)) {
1352 // TODO: A work-around, becauuse of some bogus database objects
1353 continue;
1354 }
1355 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1356 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001357
1358 //
1359 // Extract the match conditions
1360 //
1361 FlowEntryMatch match = new FlowEntryMatch();
1362 Short matchInPort = flowEntryObj.getMatchInPort();
1363 if (matchInPort != null)
1364 match.enableInPort(new Port(matchInPort));
1365 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1366 if (matchEthernetFrameType != null)
1367 match.enableEthernetFrameType(matchEthernetFrameType);
1368 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1369 if (matchSrcIPv4Net != null)
1370 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1371 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1372 if (matchDstIPv4Net != null)
1373 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1374 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1375 if (matchSrcMac != null)
1376 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1377 String matchDstMac = flowEntryObj.getMatchDstMac();
1378 if (matchDstMac != null)
1379 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1380 flowEntry.setFlowEntryMatch(match);
1381
1382 //
1383 // Extract the actions
1384 //
1385 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1386 Short actionOutputPort = flowEntryObj.getActionOutput();
1387 if (actionOutputPort != null) {
1388 FlowEntryAction action = new FlowEntryAction();
1389 action.setActionOutput(new Port(actionOutputPort));
1390 actions.add(action);
1391 }
1392 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001393 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001394 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1395 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001396 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001397 // and FlowEntryErrorState.
1398 //
1399 flowPath.dataPath().flowEntries().add(flowEntry);
1400 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001401
1402 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001403 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001404
1405 /**
1406 * Add and maintain a shortest-path flow.
1407 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001408 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001409 *
1410 * @param flowPath the Flow Path with the endpoints and the match
1411 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001412 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001413 */
1414 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001415 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001416 String dataPathSummaryStr = null;
1417
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001418 //
1419 // Do the shortest path computation
1420 //
1421 DataPath dataPath =
1422 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1423 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001424 if (dataPath == null) {
1425 // We need the DataPath to populate the Network MAP
1426 dataPath = new DataPath();
1427 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1428 dataPath.setDstPort(flowPath.dataPath().dstPort());
1429 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001430
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001431 // Compute the Data Path summary
1432 dataPathSummaryStr = dataPath.dataPathSummary();
1433
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001434 //
1435 // Set the incoming port matching and the outgoing port output
1436 // actions for each flow entry.
1437 //
1438 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1439 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001440 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001441 flowEntry.setFlowEntryMatch(flowEntryMatch);
1442 flowEntryMatch.enableInPort(flowEntry.inPort());
1443
1444 // Set the outgoing port output action
1445 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1446 if (flowEntryActions == null) {
1447 flowEntryActions = new ArrayList<FlowEntryAction>();
1448 flowEntry.setFlowEntryActions(flowEntryActions);
1449 }
1450 FlowEntryAction flowEntryAction = new FlowEntryAction();
1451 flowEntryAction.setActionOutput(flowEntry.outPort());
1452 flowEntryActions.add(flowEntryAction);
1453 }
1454
1455 //
1456 // Prepare the computed Flow Path
1457 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001458 FlowPath computedFlowPath = new FlowPath();
1459 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1460 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1461 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001462 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001463
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001464 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001465 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001466 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001467
1468 // TODO: Mark the flow for maintenance purpose
1469
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001470 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001471 }
1472
1473 /**
1474 * Create a Flow from port to port.
1475 *
1476 * TODO: We don't need it for now.
1477 *
1478 * @param src_port the source port.
1479 * @param dest_port the destination port.
1480 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001481 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001482 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1483 // TODO: We don't need it for now.
1484 }
1485
1486 /**
1487 * Get all Flows matching a source and a destination port.
1488 *
1489 * TODO: Pankaj might be implementing it later.
1490 *
1491 * @param src_port the source port to match.
1492 * @param dest_port the destination port to match.
1493 * @return all flows matching the source and the destination port.
1494 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001495 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001496 public Iterable<FlowPath> getFlows(IPortObject src_port,
1497 IPortObject dest_port) {
1498 // TODO: Pankaj might be implementing it later.
1499 return null;
1500 }
1501
1502 /**
1503 * Get all Flows going out from a port.
1504 *
1505 * TODO: We need it now: Pankaj
1506 *
1507 * @param port the port to match.
1508 * @return the list of flows that are going out from the port.
1509 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001510 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001511 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001512 // TODO: We need it now: Pankaj
1513 return null;
1514 }
1515
1516 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001517 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001518 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001519 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001520 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001521 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001522 public void reconcileFlows(IPortObject portObject) {
1523 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1524 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001525
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001526 //
1527 // Collect all affected Flow IDs from the affected flow entries
1528 //
1529 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1530 for (IFlowEntry flowEntryObj: inFlowEntries) {
1531 IFlowPath flowObj = flowEntryObj.getFlow();
1532 if (flowObj != null)
1533 flowObjSet.add(flowObj);
1534 }
1535 for (IFlowEntry flowEntryObj: outFlowEntries) {
1536 IFlowPath flowObj = flowEntryObj.getFlow();
1537 if (flowObj != null)
1538 flowObjSet.add(flowObj);
1539 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001540
1541 // Reconcile the affected flows
1542 reconcileFlows(flowObjSet);
1543 }
1544
1545 /**
1546 * Reconcile all flows in a set.
1547 *
1548 * @param flowObjSet the set of flows that need to be reconciliated.
1549 */
1550 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1551 if (! flowObjSet.iterator().hasNext())
1552 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001553
1554 //
1555 // Remove the old Flow Entries, and add the new Flow Entries
1556 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001557
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001558 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001559 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001560 for (IFlowPath flowObj : flowObjSet) {
1561 FlowPath flowPath = extractFlowPath(flowObj);
1562 if (flowPath == null)
1563 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001564 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001565
1566 //
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001567 // Remove the Flow Entries from the Network MAP
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001568 //
1569 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001570 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001571 for (IFlowEntry flowEntryObj : flowEntries) {
1572 String dpidStr = flowEntryObj.getSwitchDpid();
1573 if (dpidStr == null)
1574 continue;
1575 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001576 /*
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001577 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1578 if (mySwitch == null)
1579 continue; // Ignore the entry: not my switch
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001580 */
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001581 deleteFlowEntries.add(flowEntryObj);
1582 }
1583 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001584 flowObj.removeFlowEntry(flowEntryObj);
1585 conn.utils().removeFlowEntry(conn, flowEntryObj);
1586 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001587 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001588
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001589 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001590 //
1591 // Delete the flow entries from the switches
1592 //
1593 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1594 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001595 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1596 if (mySwitch == null) {
1597 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001598 installRemoteFlowEntry(flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001599 } else {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001600 installFlowEntry(mySwitch, flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001601 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001602 }
1603
1604 //
1605 // Calculate the new shortest path and install it in the
1606 // Network MAP.
1607 //
1608 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1609 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001610 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001611 flowPath.dataPath().srcPort().toString(),
1612 flowPath.dataPath().dstPort().toString());
1613 continue;
1614 }
1615
1616 //
1617 // Add the flow entries to the switches
1618 //
1619 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1620 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001621 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1622 if (mySwitch == null) {
1623 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001624 installRemoteFlowEntry(addedFlowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001625 continue;
1626 }
1627
1628 IFlowEntry flowEntryObj =
1629 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1630 if (flowEntryObj == null) {
1631 //
1632 // TODO: Remove the "new Object[] wrapper in the statement
1633 // below after the SLF4J logger is upgraded to
1634 // Version 1.7.5
1635 //
1636 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1637 new Object[] {
1638 flowEntry.dpid(),
1639 flowPath.dataPath().srcPort(),
1640 flowPath.dataPath().dstPort()
1641 });
1642 continue;
1643 }
1644 // Update the Flow Entry Switch State in the Network MAP
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001645 if (installFlowEntry(mySwitch, addedFlowPath, flowEntry)) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001646 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1647 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001648 }
1649 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001650 }
1651
1652 /**
1653 * Reconcile all flows between a source and a destination port.
1654 *
1655 * TODO: We don't need it for now.
1656 *
1657 * @param src_port the source port.
1658 * @param dest_port the destination port.
1659 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001660 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001661 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1662 // TODO: We don't need it for now.
1663 }
1664
1665 /**
1666 * Compute the shortest path between a source and a destination ports.
1667 *
1668 * @param src_port the source port.
1669 * @param dest_port the destination port.
1670 * @return the computed shortest path between the source and the
1671 * destination ports. The flow entries in the path itself would
1672 * contain the incoming port matching and the outgoing port output
1673 * actions set. However, the path itself will NOT have the Flow ID,
1674 * Installer ID, and any additional matching conditions for the
1675 * flow entries (e.g., source or destination MAC address, etc).
1676 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001677 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001678 public FlowPath computeFlowPath(IPortObject src_port,
1679 IPortObject dest_port) {
1680 //
1681 // Prepare the arguments
1682 //
1683 String dpidStr = src_port.getSwitch().getDPID();
1684 Dpid srcDpid = new Dpid(dpidStr);
1685 Port srcPort = new Port(src_port.getNumber());
1686
1687 dpidStr = dest_port.getSwitch().getDPID();
1688 Dpid dstDpid = new Dpid(dpidStr);
1689 Port dstPort = new Port(dest_port.getNumber());
1690
1691 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1692 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1693
1694 //
1695 // Do the shortest path computation
1696 //
1697 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1698 if (dataPath == null)
1699 return null;
1700
1701 //
1702 // Set the incoming port matching and the outgoing port output
1703 // actions for each flow entry.
1704 //
1705 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1706 // Set the incoming port matching
1707 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1708 if (flowEntryMatch == null) {
1709 flowEntryMatch = new FlowEntryMatch();
1710 flowEntry.setFlowEntryMatch(flowEntryMatch);
1711 }
1712 flowEntryMatch.enableInPort(flowEntry.inPort());
1713
1714 // Set the outgoing port output action
1715 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1716 if (flowEntryActions == null) {
1717 flowEntryActions = new ArrayList<FlowEntryAction>();
1718 flowEntry.setFlowEntryActions(flowEntryActions);
1719 }
1720 FlowEntryAction flowEntryAction = new FlowEntryAction();
1721 flowEntryAction.setActionOutput(flowEntry.outPort());
1722 flowEntryActions.add(flowEntryAction);
1723 }
1724
1725 //
1726 // Prepare the return result
1727 //
1728 FlowPath flowPath = new FlowPath();
1729 flowPath.setDataPath(dataPath);
1730
1731 return flowPath;
1732 }
1733
1734 /**
1735 * Get all Flow Entries of a Flow.
1736 *
1737 * @param flow the flow whose flow entries should be returned.
1738 * @return the flow entries of the flow.
1739 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001740 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001741 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1742 return flow.dataPath().flowEntries();
1743 }
1744
1745 /**
1746 * Install a Flow Entry on a switch.
1747 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001748 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001749 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001750 * @param flowEntry the flow entry to install.
1751 * @return true on success, otherwise false.
1752 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001753 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001754 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1755 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001756 //
1757 // Create the OpenFlow Flow Modification Entry to push
1758 //
1759 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1760 .getMessage(OFType.FLOW_MOD);
1761 long cookie = flowEntry.flowEntryId().value();
1762
1763 short flowModCommand = OFFlowMod.OFPFC_ADD;
1764 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1765 flowModCommand = OFFlowMod.OFPFC_ADD;
1766 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1767 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1768 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1769 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1770 } else {
1771 // Unknown user state. Ignore the entry
1772 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1773 flowEntry.flowEntryId().toString(),
1774 flowEntry.flowEntryUserState());
1775 return false;
1776 }
1777
1778 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001779 // Fetch the match conditions.
1780 //
1781 // NOTE: The Flow matching conditions common for all Flow Entries are
1782 // used ONLY if a Flow Entry does NOT have the corresponding matching
1783 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001784 //
1785 OFMatch match = new OFMatch();
1786 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001787 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1788 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1789
1790 // Match the Incoming Port
1791 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001792 if (matchInPort != null) {
1793 match.setInputPort(matchInPort.value());
1794 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1795 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001796
1797 // Match the Ethernet Frame Type
1798 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1799 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1800 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1801 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001802 if (matchEthernetFrameType != null) {
1803 match.setDataLayerType(matchEthernetFrameType);
1804 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1805 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001806
1807 // Match the Source IPv4 Network prefix
1808 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1809 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1810 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1811 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001812 if (matchSrcIPv4Net != null) {
1813 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1814 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001815
1816 // Natch the Destination IPv4 Network prefix
1817 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1818 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1819 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1820 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001821 if (matchDstIPv4Net != null) {
1822 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1823 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001824
1825 // Match the Source MAC address
1826 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1827 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1828 matchSrcMac = flowPathMatch.srcMac();
1829 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001830 if (matchSrcMac != null) {
1831 match.setDataLayerSource(matchSrcMac.toString());
1832 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1833 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001834
1835 // Match the Destination MAC address
1836 MACAddress matchDstMac = flowEntryMatch.dstMac();
1837 if ((matchDstMac == null) && (flowPathMatch != null)) {
1838 matchDstMac = flowPathMatch.dstMac();
1839 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001840 if (matchDstMac != null) {
1841 match.setDataLayerDestination(matchDstMac.toString());
1842 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1843 }
1844
1845 //
1846 // Fetch the actions
1847 //
1848 // TODO: For now we support only the "OUTPUT" actions.
1849 //
1850 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1851 List<OFAction> actions = new ArrayList<OFAction>();
1852 ArrayList<FlowEntryAction> flowEntryActions =
1853 flowEntry.flowEntryActions();
1854 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1855 FlowEntryAction.ActionOutput actionOutput =
1856 flowEntryAction.actionOutput();
1857 if (actionOutput != null) {
1858 short actionOutputPort = actionOutput.port().value();
1859 OFActionOutput action = new OFActionOutput();
1860 // XXX: The max length is hard-coded for now
1861 action.setMaxLength((short)0xffff);
1862 action.setPort(actionOutputPort);
1863 actions.add(action);
1864 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1865 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1866 fm.setOutPort(actionOutputPort);
1867 }
1868 }
1869 }
1870
1871 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1872 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1873 .setPriority(PRIORITY_DEFAULT)
1874 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1875 .setCookie(cookie)
1876 .setCommand(flowModCommand)
1877 .setMatch(match)
1878 .setActions(actions)
1879 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1880
1881 //
1882 // TODO: Set the following flag
1883 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1884 // See method ForwardingBase::pushRoute()
1885 //
1886
1887 //
1888 // Write the message to the switch
1889 //
1890 try {
1891 messageDamper.write(mySwitch, fm, null);
1892 mySwitch.flush();
1893 } catch (IOException e) {
1894 log.error("Failure writing flow mod from network map", e);
1895 return false;
1896 }
1897 return true;
1898 }
1899
1900 /**
1901 * Remove a Flow Entry from a switch.
1902 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001903 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001904 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001905 * @param flowEntry the flow entry to remove.
1906 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001907 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001908 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001909 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1910 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001911 //
1912 // The installFlowEntry() method implements both installation
1913 // and removal of flow entries.
1914 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001915 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001916 }
1917
1918 /**
1919 * Install a Flow Entry on a remote controller.
1920 *
1921 * TODO: We need it now: Jono
1922 * - For now it will make a REST call to the remote controller.
1923 * - Internally, it needs to know the name of the remote controller.
1924 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001925 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001926 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001927 * @return true on success, otherwise false.
1928 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001929 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001930 public boolean installRemoteFlowEntry(FlowPath flowPath,
1931 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001932 // TODO: We need it now: Jono
1933 // - For now it will make a REST call to the remote controller.
1934 // - Internally, it needs to know the name of the remote controller.
1935 return true;
1936 }
1937
1938 /**
1939 * Remove a flow entry on a remote controller.
1940 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001941 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001942 * @param flowEntry the flow entry to remove.
1943 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001944 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001945 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001946 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1947 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001948 //
1949 // The installRemoteFlowEntry() method implements both installation
1950 // and removal of flow entries.
1951 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001952 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001953 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001954}