blob: f9177f2d6b3ea91c5754559dd85946b26d0216e0 [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 Radoslavov2659a0b2013-04-03 20:30:40 -0700565
566 //
567 // Use the source DPID as a heuristic to decide
568 // which controller is responsible for maintaining the
569 // shortest path.
570 // NOTE: This heuristic is error-prone: if the switch
571 // goes away and no controller is responsible for that
572 // switch, then the original Flow Path is not cleaned-up
573 //
574 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
575 if (mySwitch == null)
576 continue; // Ignore: not my responsibility
577
578 counterMyFlowPaths++;
579
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700580 //
581 // NOTE: Using here the regular getShortestPath() method
582 // won't work here, because that method calls internally
583 // "conn.endTx(Transaction.COMMIT)", and that will
584 // invalidate all handlers to the Titan database.
585 // If we want to experiment with calling here
586 // getShortestPath(), we need to refactor that code
587 // to avoid closing the transaction.
588 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700589 DataPath dataPath =
590 topoRouteService.getTopoShortestPath(srcSwitchPort,
591 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000592 if (dataPath == null) {
593 // We need the DataPath to compare the paths
594 dataPath = new DataPath();
595 dataPath.setSrcPort(srcSwitchPort);
596 dataPath.setDstPort(dstSwitchPort);
597 }
598
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700599 String newDataPathSummaryStr = dataPath.dataPathSummary();
600 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
601 continue; // Nothing changed
602
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700603 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
604 flowId.toString());
605 flowObjSet.add(flowPathObj);
606 }
607 reconcileFlows(flowObjSet);
608 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700609
610
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800611 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700612
613 if (processed_measurement_flow) {
614 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
615 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
616 (double)estimatedTime / 1000000000 + " sec";
617 log.debug(logMsg);
618 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700619
620 long estimatedTime = System.nanoTime() - startTime;
621 double rate = (estimatedTime > 0)? ((double)counterAllFlowPaths * 1000000000) / estimatedTime: 0.0;
622 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " + counterAllFlowEntries + " MyNotUpdatedFlowEntries: " + counterMyNotUpdatedFlowEntries + " AllFlowPaths: " + counterAllFlowPaths + " MyFlowPaths: " + counterMyFlowPaths + " in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " paths/s";
623 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800624 }
625 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700626
627 /*
628 final ScheduledFuture<?> measureShortestPathHandle =
629 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
630 */
631
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700632 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700633 final ScheduledFuture<?> measureMapReaderHandle =
634 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700635 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700636
637 final ScheduledFuture<?> mapReaderHandle =
638 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800639
640 @Override
641 public void init(String conf) {
642 conn = GraphDBConnection.getInstance(conf);
643 }
644
645 public void finalize() {
646 close();
647 }
648
649 @Override
650 public void close() {
651 conn.close();
652 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800653
654 @Override
655 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
656 Collection<Class<? extends IFloodlightService>> l =
657 new ArrayList<Class<? extends IFloodlightService>>();
658 l.add(IFlowService.class);
659 return l;
660 }
661
662 @Override
663 public Map<Class<? extends IFloodlightService>, IFloodlightService>
664 getServiceImpls() {
665 Map<Class<? extends IFloodlightService>,
666 IFloodlightService> m =
667 new HashMap<Class<? extends IFloodlightService>,
668 IFloodlightService>();
669 m.put(IFlowService.class, this);
670 return m;
671 }
672
673 @Override
674 public Collection<Class<? extends IFloodlightService>>
675 getModuleDependencies() {
676 Collection<Class<? extends IFloodlightService>> l =
677 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800678 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700679 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800680 l.add(IRestApiService.class);
681 return l;
682 }
683
684 @Override
685 public void init(FloodlightModuleContext context)
686 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700687 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800688 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700689 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800690 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800691 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
692 EnumSet.of(OFType.FLOW_MOD),
693 OFMESSAGE_DAMPER_TIMEOUT);
694 // TODO: An ugly hack!
695 String conf = "/tmp/cassandra.titan";
696 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800697 }
698
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000699 private long getNextFlowEntryId() {
700 //
701 // Generate the next Flow Entry ID.
702 // NOTE: For now, the higher 32 bits are random, and
703 // the lower 32 bits are sequential.
704 // In the future, we need a better allocation mechanism.
705 //
706 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
707 nextFlowEntryIdPrefix = randomGenerator.nextInt();
708 nextFlowEntryIdSuffix = 0;
709 } else {
710 nextFlowEntryIdSuffix++;
711 }
712 long result = (long)nextFlowEntryIdPrefix << 32;
713 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
714 return result;
715 }
716
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800717 @Override
718 public void startUp(FloodlightModuleContext context) {
719 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700720
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000721 // Initialize the Flow Entry ID generator
722 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800723 }
724
725 /**
726 * Add a flow.
727 *
728 * Internally, ONOS will automatically register the installer for
729 * receiving Flow Path Notifications for that path.
730 *
731 * @param flowPath the Flow Path to install.
732 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700733 * @param dataPathSummaryStr the data path summary string if the added
734 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800735 * @return true on success, otherwise false.
736 */
737 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700738 public boolean addFlow(FlowPath flowPath, FlowId flowId,
739 String dataPathSummaryStr) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700740 if (flowPath.flowId().value() == measurementFlowId) {
741 modifiedMeasurementFlowTime = System.nanoTime();
742 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800743
744 //
745 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700746 // Right now every new flow entry gets a new flow entry ID
747 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800748 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800749 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000750 long id = getNextFlowEntryId();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800751 flowEntry.setFlowEntryId(new FlowEntryId(id));
752 }
753
754 IFlowPath flowObj = null;
755 try {
756 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
757 != null) {
758 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
759 flowPath.flowId().toString());
760 } else {
761 flowObj = conn.utils().newFlowPath(conn);
762 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
763 flowPath.flowId().toString());
764 }
765 } catch (Exception e) {
766 // TODO: handle exceptions
767 conn.endTx(Transaction.ROLLBACK);
768 log.error(":addFlow FlowId:{} failed",
769 flowPath.flowId().toString());
770 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700771 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000772 log.error(":addFlow FlowId:{} failed: Flow object not created",
773 flowPath.flowId().toString());
774 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800775 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700776 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800777
778 //
779 // Set the Flow key:
780 // - flowId
781 //
782 flowObj.setFlowId(flowPath.flowId().toString());
783 flowObj.setType("flow");
784
785 //
786 // Set the Flow attributes:
787 // - flowPath.installerId()
788 // - flowPath.dataPath().srcPort()
789 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700790 // - flowPath.matchEthernetFrameType()
791 // - flowPath.matchSrcIPv4Net()
792 // - flowPath.matchDstIPv4Net()
793 // - flowPath.matchSrcMac()
794 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800795 //
796 flowObj.setInstallerId(flowPath.installerId().toString());
797 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
798 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
799 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
800 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700801 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
802 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
803 }
804 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
805 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
806 }
807 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
808 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
809 }
810 if (flowPath.flowEntryMatch().matchSrcMac()) {
811 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
812 }
813 if (flowPath.flowEntryMatch().matchDstMac()) {
814 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
815 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800816
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700817 if (dataPathSummaryStr != null) {
818 flowObj.setDataPathSummary(dataPathSummaryStr);
819 } else {
820 flowObj.setDataPathSummary("");
821 }
822
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800823 // Flow edges:
824 // HeadFE
825
826
827 //
828 // Flow Entries:
829 // flowPath.dataPath().flowEntries()
830 //
831 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
832 IFlowEntry flowEntryObj = null;
833 boolean found = false;
834 try {
835 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
836 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
837 flowEntry.flowEntryId().toString());
838 found = true;
839 } else {
840 flowEntryObj = conn.utils().newFlowEntry(conn);
841 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
842 flowEntry.flowEntryId().toString());
843 }
844 } catch (Exception e) {
845 // TODO: handle exceptions
846 conn.endTx(Transaction.ROLLBACK);
847 log.error(":addFlow FlowEntryId:{} failed",
848 flowEntry.flowEntryId().toString());
849 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700850 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000851 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
852 flowEntry.flowEntryId().toString());
853 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800854 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700855 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800856
857 //
858 // Set the Flow Entry key:
859 // - flowEntry.flowEntryId()
860 //
861 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
862 flowEntryObj.setType("flow_entry");
863
864 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700865 // Set the Flow Entry Edges and attributes:
866 // - Switch edge
867 // - InPort edge
868 // - OutPort edge
869 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800870 // - flowEntry.flowEntryMatch()
871 // - flowEntry.flowEntryActions()
872 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800873 // - flowEntry.flowEntryUserState()
874 // - flowEntry.flowEntrySwitchState()
875 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700876 // - flowEntry.matchInPort()
877 // - flowEntry.matchEthernetFrameType()
878 // - flowEntry.matchSrcIPv4Net()
879 // - flowEntry.matchDstIPv4Net()
880 // - flowEntry.matchSrcMac()
881 // - flowEntry.matchDstMac()
882 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800883 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700884 ISwitchObject sw =
885 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800886 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700887 flowEntryObj.setSwitch(sw);
888 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700889 IPortObject inport =
890 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
891 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700892 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
893 flowEntryObj.setInPort(inport);
894 }
895 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
896 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
897 }
898 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
899 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
900 }
901 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
902 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
903 }
904 if (flowEntry.flowEntryMatch().matchSrcMac()) {
905 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
906 }
907 if (flowEntry.flowEntryMatch().matchDstMac()) {
908 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
909 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700910
911 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700912 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700913 IPortObject outport =
914 conn.utils().searchPort(conn,
915 flowEntry.dpid().toString(),
916 fa.actionOutput().port().value());
917 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
918 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700919 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700920 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800921 // TODO: Hacks with hard-coded state names!
922 if (found)
923 flowEntryObj.setUserState("FE_USER_MODIFY");
924 else
925 flowEntryObj.setUserState("FE_USER_ADD");
926 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
927 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700928 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800929 //
930
931 // Flow Entries edges:
932 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700933 // NextFE (TODO)
934 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800935 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700936 flowEntryObj.setFlow(flowObj);
937 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800938 }
939 conn.endTx(Transaction.COMMIT);
940
941 //
942 // TODO: We need a proper Flow ID allocation mechanism.
943 //
944 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700945
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800946 return true;
947 }
948
949 /**
950 * Delete a previously added flow.
951 *
952 * @param flowId the Flow ID of the flow to delete.
953 * @return true on success, otherwise false.
954 */
955 @Override
956 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700957 if (flowId.value() == measurementFlowId) {
958 modifiedMeasurementFlowTime = System.nanoTime();
959 }
960
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800961 IFlowPath flowObj = null;
962 //
963 // We just mark the entries for deletion,
964 // and let the switches remove each individual entry after
965 // it has been removed from the switches.
966 //
967 try {
968 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
969 != null) {
970 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
971 flowId.toString());
972 } else {
973 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
974 flowId.toString());
975 }
976 } catch (Exception e) {
977 // TODO: handle exceptions
978 conn.endTx(Transaction.ROLLBACK);
979 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
980 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700981 if (flowObj == null) {
982 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800983 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700984 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800985
986 //
987 // Find and mark for deletion all Flow Entries
988 //
989 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
990 boolean empty = true; // TODO: an ugly hack
991 for (IFlowEntry flowEntryObj : flowEntries) {
992 empty = false;
993 // flowObj.removeFlowEntry(flowEntryObj);
994 // conn.utils().removeFlowEntry(conn, flowEntryObj);
995 flowEntryObj.setUserState("FE_USER_DELETE");
996 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
997 }
998 // Remove from the database empty flows
999 if (empty)
1000 conn.utils().removeFlowPath(conn, flowObj);
1001 conn.endTx(Transaction.COMMIT);
1002
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001003 return true;
1004 }
1005
1006 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001007 * Clear the state for a previously added flow.
1008 *
1009 * @param flowId the Flow ID of the flow to clear.
1010 * @return true on success, otherwise false.
1011 */
1012 @Override
1013 public boolean clearFlow(FlowId flowId) {
1014 IFlowPath flowObj = null;
1015 try {
1016 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
1017 != null) {
1018 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1019 flowId.toString());
1020 } else {
1021 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1022 flowId.toString());
1023 }
1024 } catch (Exception e) {
1025 // TODO: handle exceptions
1026 conn.endTx(Transaction.ROLLBACK);
1027 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1028 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001029 if (flowObj == null) {
1030 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001031 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001032 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001033
1034 //
1035 // Remove all Flow Entries
1036 //
1037 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1038 for (IFlowEntry flowEntryObj : flowEntries) {
1039 flowObj.removeFlowEntry(flowEntryObj);
1040 conn.utils().removeFlowEntry(conn, flowEntryObj);
1041 }
1042 // Remove the Flow itself
1043 conn.utils().removeFlowPath(conn, flowObj);
1044 conn.endTx(Transaction.COMMIT);
1045
1046 return true;
1047 }
1048
1049 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001050 * Get a previously added flow.
1051 *
1052 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001053 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001054 */
1055 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001056 public FlowPath getFlow(FlowId flowId) {
1057 IFlowPath flowObj = null;
1058 try {
1059 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
1060 != null) {
1061 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1062 flowId.toString());
1063 } else {
1064 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1065 flowId.toString());
1066 }
1067 } catch (Exception e) {
1068 // TODO: handle exceptions
1069 conn.endTx(Transaction.ROLLBACK);
1070 log.error(":getFlow FlowId:{} failed", flowId.toString());
1071 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001072 if (flowObj == null) {
1073 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001074 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001075 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001076
1077 //
1078 // Extract the Flow state
1079 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001080 FlowPath flowPath = extractFlowPath(flowObj);
1081 conn.endTx(Transaction.COMMIT);
1082
1083 return flowPath;
1084 }
1085
1086 /**
1087 * Get all previously added flows by a specific installer for a given
1088 * data path endpoints.
1089 *
1090 * @param installerId the Caller ID of the installer of the flow to get.
1091 * @param dataPathEndpoints the data path endpoints of the flow to get.
1092 * @return the Flow Paths if found, otherwise null.
1093 */
1094 @Override
1095 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1096 DataPathEndpoints dataPathEndpoints) {
1097 //
1098 // TODO: The implementation below is not optimal:
1099 // We fetch all flows, and then return only the subset that match
1100 // the query conditions.
1101 // We should use the appropriate Titan/Gremlin query to filter-out
1102 // the flows as appropriate.
1103 //
1104 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001105 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001106
1107 if (allFlows == null) {
1108 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001109 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001110 }
1111
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001112 for (FlowPath flow : allFlows) {
1113 //
1114 // TODO: String-based comparison is sub-optimal.
1115 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001116 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001117 //
1118 if (! flow.installerId().toString().equals(installerId.toString()))
1119 continue;
1120 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1121 continue;
1122 }
1123 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1124 continue;
1125 }
1126 flowPaths.add(flow);
1127 }
1128
1129 if (flowPaths.isEmpty()) {
1130 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001131 } else {
1132 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1133 }
1134
1135 return flowPaths;
1136 }
1137
1138 /**
1139 * Get all installed flows by all installers for given data path endpoints.
1140 *
1141 * @param dataPathEndpoints the data path endpoints of the flows to get.
1142 * @return the Flow Paths if found, otherwise null.
1143 */
1144 @Override
1145 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1146 //
1147 // TODO: The implementation below is not optimal:
1148 // We fetch all flows, and then return only the subset that match
1149 // the query conditions.
1150 // We should use the appropriate Titan/Gremlin query to filter-out
1151 // the flows as appropriate.
1152 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001153 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1154 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001155
1156 if (allFlows == null) {
1157 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001158 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001159 }
1160
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001161 for (FlowPath flow : allFlows) {
1162 //
1163 // TODO: String-based comparison is sub-optimal.
1164 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001165 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001166 //
1167 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1168 continue;
1169 }
1170 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1171 continue;
1172 }
1173 flowPaths.add(flow);
1174 }
1175
1176 if (flowPaths.isEmpty()) {
1177 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001178 } else {
1179 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1180 }
1181
1182 return flowPaths;
1183 }
1184
1185 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001186 * Get summary of all installed flows by all installers in a given range
1187 *
1188 * @param flowId the data path endpoints of the flows to get.
1189 * @param maxFlows: the maximum number of flows to be returned
1190 * @return the Flow Paths if found, otherwise null.
1191 */
1192 @Override
1193 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1194 //
1195 // TODO: The implementation below is not optimal:
1196 // We fetch all flows, and then return only the subset that match
1197 // the query conditions.
1198 // We should use the appropriate Titan/Gremlin query to filter-out
1199 // the flows as appropriate.
1200 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001201 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1202
1203 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001204
1205 if (allFlows == null) {
1206 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001207 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001208 }
1209
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001210 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001211
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001212 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001213 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001214
1215 // start from desired flowId
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -07001216 //if (flow.flowId().value() < flowId.value()) {
1217 // continue;
1218 //}
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001219
1220 // Summarize by making null flow entry fields that are not relevant to report
1221 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1222 flowEntry.setFlowEntryActions(null);
1223 flowEntry.setFlowEntryMatch(null);
1224 }
1225
1226 flowPaths.add(flow);
1227 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1228 break;
1229 }
1230 }
1231
1232 if (flowPaths.isEmpty()) {
1233 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001234 } else {
1235 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1236 }
1237
1238 return flowPaths;
1239 }
1240
1241 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001242 * Get all installed flows by all installers.
1243 *
1244 * @return the Flow Paths if found, otherwise null.
1245 */
1246 @Override
1247 public ArrayList<FlowPath> getAllFlows() {
1248 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001249 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001250
1251 try {
1252 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1253 log.debug("Get all FlowPaths: found FlowPaths");
1254 } else {
1255 log.debug("Get all FlowPaths: no FlowPaths found");
1256 }
1257 } catch (Exception e) {
1258 // TODO: handle exceptions
1259 conn.endTx(Transaction.ROLLBACK);
1260 log.error(":getAllFlowPaths failed");
1261 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001262 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1263 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001264 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001265 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001266
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001267 for (IFlowPath flowObj : flowPathsObj) {
1268 //
1269 // Extract the Flow state
1270 //
1271 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001272 if (flowPath != null)
1273 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001274 }
1275
1276 conn.endTx(Transaction.COMMIT);
1277
1278 return flowPaths;
1279 }
1280
1281 /**
1282 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1283 *
1284 * @param flowObj the object to extract the Flow Path State from.
1285 * @return the extracted Flow Path State.
1286 */
1287 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001288 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001289
1290 //
1291 // Extract the Flow state
1292 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001293 String flowIdStr = flowObj.getFlowId();
1294 String installerIdStr = flowObj.getInstallerId();
1295 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001296 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001297 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001298 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001299
1300 if ((flowIdStr == null) ||
1301 (installerIdStr == null) ||
1302 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001303 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001304 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001305 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001306 // TODO: A work-around, becauuse of some bogus database objects
1307 return null;
1308 }
1309
1310 flowPath.setFlowId(new FlowId(flowIdStr));
1311 flowPath.setInstallerId(new CallerId(installerIdStr));
1312 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001313 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001314 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001315 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001316 //
1317 // Extract the match conditions common for all Flow Entries
1318 //
1319 {
1320 FlowEntryMatch match = new FlowEntryMatch();
1321 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1322 if (matchEthernetFrameType != null)
1323 match.enableEthernetFrameType(matchEthernetFrameType);
1324 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1325 if (matchSrcIPv4Net != null)
1326 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1327 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1328 if (matchDstIPv4Net != null)
1329 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1330 String matchSrcMac = flowObj.getMatchSrcMac();
1331 if (matchSrcMac != null)
1332 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1333 String matchDstMac = flowObj.getMatchDstMac();
1334 if (matchDstMac != null)
1335 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1336 flowPath.setFlowEntryMatch(match);
1337 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001338
1339 //
1340 // Extract all Flow Entries
1341 //
1342 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1343 for (IFlowEntry flowEntryObj : flowEntries) {
1344 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001345 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1346 String switchDpidStr = flowEntryObj.getSwitchDpid();
1347 String userState = flowEntryObj.getUserState();
1348 String switchState = flowEntryObj.getSwitchState();
1349
1350 if ((flowEntryIdStr == null) ||
1351 (switchDpidStr == null) ||
1352 (userState == null) ||
1353 (switchState == null)) {
1354 // TODO: A work-around, becauuse of some bogus database objects
1355 continue;
1356 }
1357 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1358 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001359
1360 //
1361 // Extract the match conditions
1362 //
1363 FlowEntryMatch match = new FlowEntryMatch();
1364 Short matchInPort = flowEntryObj.getMatchInPort();
1365 if (matchInPort != null)
1366 match.enableInPort(new Port(matchInPort));
1367 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1368 if (matchEthernetFrameType != null)
1369 match.enableEthernetFrameType(matchEthernetFrameType);
1370 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1371 if (matchSrcIPv4Net != null)
1372 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1373 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1374 if (matchDstIPv4Net != null)
1375 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1376 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1377 if (matchSrcMac != null)
1378 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1379 String matchDstMac = flowEntryObj.getMatchDstMac();
1380 if (matchDstMac != null)
1381 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1382 flowEntry.setFlowEntryMatch(match);
1383
1384 //
1385 // Extract the actions
1386 //
1387 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1388 Short actionOutputPort = flowEntryObj.getActionOutput();
1389 if (actionOutputPort != null) {
1390 FlowEntryAction action = new FlowEntryAction();
1391 action.setActionOutput(new Port(actionOutputPort));
1392 actions.add(action);
1393 }
1394 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001395 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001396 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1397 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001398 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001399 // and FlowEntryErrorState.
1400 //
1401 flowPath.dataPath().flowEntries().add(flowEntry);
1402 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001403
1404 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001405 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001406
1407 /**
1408 * Add and maintain a shortest-path flow.
1409 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001410 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001411 *
1412 * @param flowPath the Flow Path with the endpoints and the match
1413 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001414 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001415 */
1416 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001417 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001418 String dataPathSummaryStr = null;
1419
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001420 //
1421 // Do the shortest path computation
1422 //
1423 DataPath dataPath =
1424 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1425 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001426 if (dataPath == null) {
1427 // We need the DataPath to populate the Network MAP
1428 dataPath = new DataPath();
1429 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1430 dataPath.setDstPort(flowPath.dataPath().dstPort());
1431 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001432
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001433 // Compute the Data Path summary
1434 dataPathSummaryStr = dataPath.dataPathSummary();
1435
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001436 //
1437 // Set the incoming port matching and the outgoing port output
1438 // actions for each flow entry.
1439 //
1440 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1441 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001442 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001443 flowEntry.setFlowEntryMatch(flowEntryMatch);
1444 flowEntryMatch.enableInPort(flowEntry.inPort());
1445
1446 // Set the outgoing port output action
1447 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1448 if (flowEntryActions == null) {
1449 flowEntryActions = new ArrayList<FlowEntryAction>();
1450 flowEntry.setFlowEntryActions(flowEntryActions);
1451 }
1452 FlowEntryAction flowEntryAction = new FlowEntryAction();
1453 flowEntryAction.setActionOutput(flowEntry.outPort());
1454 flowEntryActions.add(flowEntryAction);
1455 }
1456
1457 //
1458 // Prepare the computed Flow Path
1459 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001460 FlowPath computedFlowPath = new FlowPath();
1461 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1462 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1463 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001464 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001465
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001466 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001467 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001468 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001469
1470 // TODO: Mark the flow for maintenance purpose
1471
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001472 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001473 }
1474
1475 /**
1476 * Create a Flow from port to port.
1477 *
1478 * TODO: We don't need it for now.
1479 *
1480 * @param src_port the source port.
1481 * @param dest_port the destination port.
1482 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001483 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001484 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1485 // TODO: We don't need it for now.
1486 }
1487
1488 /**
1489 * Get all Flows matching a source and a destination port.
1490 *
1491 * TODO: Pankaj might be implementing it later.
1492 *
1493 * @param src_port the source port to match.
1494 * @param dest_port the destination port to match.
1495 * @return all flows matching the source and the destination port.
1496 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001497 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001498 public Iterable<FlowPath> getFlows(IPortObject src_port,
1499 IPortObject dest_port) {
1500 // TODO: Pankaj might be implementing it later.
1501 return null;
1502 }
1503
1504 /**
1505 * Get all Flows going out from a port.
1506 *
1507 * TODO: We need it now: Pankaj
1508 *
1509 * @param port the port to match.
1510 * @return the list of flows that are going out from the port.
1511 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001512 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001513 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001514 // TODO: We need it now: Pankaj
1515 return null;
1516 }
1517
1518 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001519 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001520 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001521 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001522 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001523 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001524 public void reconcileFlows(IPortObject portObject) {
1525 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1526 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001527
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001528 //
1529 // Collect all affected Flow IDs from the affected flow entries
1530 //
1531 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1532 for (IFlowEntry flowEntryObj: inFlowEntries) {
1533 IFlowPath flowObj = flowEntryObj.getFlow();
1534 if (flowObj != null)
1535 flowObjSet.add(flowObj);
1536 }
1537 for (IFlowEntry flowEntryObj: outFlowEntries) {
1538 IFlowPath flowObj = flowEntryObj.getFlow();
1539 if (flowObj != null)
1540 flowObjSet.add(flowObj);
1541 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001542
1543 // Reconcile the affected flows
1544 reconcileFlows(flowObjSet);
1545 }
1546
1547 /**
1548 * Reconcile all flows in a set.
1549 *
1550 * @param flowObjSet the set of flows that need to be reconciliated.
1551 */
1552 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1553 if (! flowObjSet.iterator().hasNext())
1554 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001555
1556 //
1557 // Remove the old Flow Entries, and add the new Flow Entries
1558 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001559
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001560 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001561 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001562 for (IFlowPath flowObj : flowObjSet) {
1563 FlowPath flowPath = extractFlowPath(flowObj);
1564 if (flowPath == null)
1565 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001566 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001567
1568 //
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001569 // Remove the Flow Entries from the Network MAP
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001570 //
1571 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001572 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001573 for (IFlowEntry flowEntryObj : flowEntries) {
1574 String dpidStr = flowEntryObj.getSwitchDpid();
1575 if (dpidStr == null)
1576 continue;
1577 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001578 /*
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001579 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1580 if (mySwitch == null)
1581 continue; // Ignore the entry: not my switch
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001582 */
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001583 deleteFlowEntries.add(flowEntryObj);
1584 }
1585 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001586 flowObj.removeFlowEntry(flowEntryObj);
1587 conn.utils().removeFlowEntry(conn, flowEntryObj);
1588 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001589 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001590
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001591 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001592 //
1593 // Delete the flow entries from the switches
1594 //
1595 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1596 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001597 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1598 if (mySwitch == null) {
1599 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001600 installRemoteFlowEntry(flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001601 } else {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001602 installFlowEntry(mySwitch, flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001603 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001604 }
1605
1606 //
1607 // Calculate the new shortest path and install it in the
1608 // Network MAP.
1609 //
1610 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1611 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001612 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001613 flowPath.dataPath().srcPort().toString(),
1614 flowPath.dataPath().dstPort().toString());
1615 continue;
1616 }
1617
1618 //
1619 // Add the flow entries to the switches
1620 //
1621 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1622 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001623 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1624 if (mySwitch == null) {
1625 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001626 installRemoteFlowEntry(addedFlowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001627 continue;
1628 }
1629
1630 IFlowEntry flowEntryObj =
1631 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1632 if (flowEntryObj == null) {
1633 //
1634 // TODO: Remove the "new Object[] wrapper in the statement
1635 // below after the SLF4J logger is upgraded to
1636 // Version 1.7.5
1637 //
1638 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1639 new Object[] {
1640 flowEntry.dpid(),
1641 flowPath.dataPath().srcPort(),
1642 flowPath.dataPath().dstPort()
1643 });
1644 continue;
1645 }
1646 // Update the Flow Entry Switch State in the Network MAP
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001647 if (installFlowEntry(mySwitch, addedFlowPath, flowEntry)) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001648 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1649 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001650 }
1651 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001652 }
1653
1654 /**
1655 * Reconcile all flows between a source and a destination port.
1656 *
1657 * TODO: We don't need it for now.
1658 *
1659 * @param src_port the source port.
1660 * @param dest_port the destination port.
1661 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001662 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001663 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1664 // TODO: We don't need it for now.
1665 }
1666
1667 /**
1668 * Compute the shortest path between a source and a destination ports.
1669 *
1670 * @param src_port the source port.
1671 * @param dest_port the destination port.
1672 * @return the computed shortest path between the source and the
1673 * destination ports. The flow entries in the path itself would
1674 * contain the incoming port matching and the outgoing port output
1675 * actions set. However, the path itself will NOT have the Flow ID,
1676 * Installer ID, and any additional matching conditions for the
1677 * flow entries (e.g., source or destination MAC address, etc).
1678 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001679 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001680 public FlowPath computeFlowPath(IPortObject src_port,
1681 IPortObject dest_port) {
1682 //
1683 // Prepare the arguments
1684 //
1685 String dpidStr = src_port.getSwitch().getDPID();
1686 Dpid srcDpid = new Dpid(dpidStr);
1687 Port srcPort = new Port(src_port.getNumber());
1688
1689 dpidStr = dest_port.getSwitch().getDPID();
1690 Dpid dstDpid = new Dpid(dpidStr);
1691 Port dstPort = new Port(dest_port.getNumber());
1692
1693 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1694 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1695
1696 //
1697 // Do the shortest path computation
1698 //
1699 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1700 if (dataPath == null)
1701 return null;
1702
1703 //
1704 // Set the incoming port matching and the outgoing port output
1705 // actions for each flow entry.
1706 //
1707 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1708 // Set the incoming port matching
1709 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1710 if (flowEntryMatch == null) {
1711 flowEntryMatch = new FlowEntryMatch();
1712 flowEntry.setFlowEntryMatch(flowEntryMatch);
1713 }
1714 flowEntryMatch.enableInPort(flowEntry.inPort());
1715
1716 // Set the outgoing port output action
1717 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1718 if (flowEntryActions == null) {
1719 flowEntryActions = new ArrayList<FlowEntryAction>();
1720 flowEntry.setFlowEntryActions(flowEntryActions);
1721 }
1722 FlowEntryAction flowEntryAction = new FlowEntryAction();
1723 flowEntryAction.setActionOutput(flowEntry.outPort());
1724 flowEntryActions.add(flowEntryAction);
1725 }
1726
1727 //
1728 // Prepare the return result
1729 //
1730 FlowPath flowPath = new FlowPath();
1731 flowPath.setDataPath(dataPath);
1732
1733 return flowPath;
1734 }
1735
1736 /**
1737 * Get all Flow Entries of a Flow.
1738 *
1739 * @param flow the flow whose flow entries should be returned.
1740 * @return the flow entries of the flow.
1741 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001742 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001743 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1744 return flow.dataPath().flowEntries();
1745 }
1746
1747 /**
1748 * Install a Flow Entry on a switch.
1749 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001750 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001751 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001752 * @param flowEntry the flow entry to install.
1753 * @return true on success, otherwise false.
1754 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001755 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001756 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1757 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001758 //
1759 // Create the OpenFlow Flow Modification Entry to push
1760 //
1761 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1762 .getMessage(OFType.FLOW_MOD);
1763 long cookie = flowEntry.flowEntryId().value();
1764
1765 short flowModCommand = OFFlowMod.OFPFC_ADD;
1766 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1767 flowModCommand = OFFlowMod.OFPFC_ADD;
1768 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1769 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1770 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1771 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1772 } else {
1773 // Unknown user state. Ignore the entry
1774 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1775 flowEntry.flowEntryId().toString(),
1776 flowEntry.flowEntryUserState());
1777 return false;
1778 }
1779
1780 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001781 // Fetch the match conditions.
1782 //
1783 // NOTE: The Flow matching conditions common for all Flow Entries are
1784 // used ONLY if a Flow Entry does NOT have the corresponding matching
1785 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001786 //
1787 OFMatch match = new OFMatch();
1788 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001789 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1790 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1791
1792 // Match the Incoming Port
1793 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001794 if (matchInPort != null) {
1795 match.setInputPort(matchInPort.value());
1796 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1797 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001798
1799 // Match the Ethernet Frame Type
1800 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1801 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1802 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1803 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001804 if (matchEthernetFrameType != null) {
1805 match.setDataLayerType(matchEthernetFrameType);
1806 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1807 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001808
1809 // Match the Source IPv4 Network prefix
1810 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1811 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1812 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1813 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001814 if (matchSrcIPv4Net != null) {
1815 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1816 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001817
1818 // Natch the Destination IPv4 Network prefix
1819 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1820 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1821 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1822 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001823 if (matchDstIPv4Net != null) {
1824 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1825 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001826
1827 // Match the Source MAC address
1828 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1829 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1830 matchSrcMac = flowPathMatch.srcMac();
1831 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001832 if (matchSrcMac != null) {
1833 match.setDataLayerSource(matchSrcMac.toString());
1834 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1835 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001836
1837 // Match the Destination MAC address
1838 MACAddress matchDstMac = flowEntryMatch.dstMac();
1839 if ((matchDstMac == null) && (flowPathMatch != null)) {
1840 matchDstMac = flowPathMatch.dstMac();
1841 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001842 if (matchDstMac != null) {
1843 match.setDataLayerDestination(matchDstMac.toString());
1844 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1845 }
1846
1847 //
1848 // Fetch the actions
1849 //
1850 // TODO: For now we support only the "OUTPUT" actions.
1851 //
1852 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1853 List<OFAction> actions = new ArrayList<OFAction>();
1854 ArrayList<FlowEntryAction> flowEntryActions =
1855 flowEntry.flowEntryActions();
1856 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1857 FlowEntryAction.ActionOutput actionOutput =
1858 flowEntryAction.actionOutput();
1859 if (actionOutput != null) {
1860 short actionOutputPort = actionOutput.port().value();
1861 OFActionOutput action = new OFActionOutput();
1862 // XXX: The max length is hard-coded for now
1863 action.setMaxLength((short)0xffff);
1864 action.setPort(actionOutputPort);
1865 actions.add(action);
1866 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1867 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1868 fm.setOutPort(actionOutputPort);
1869 }
1870 }
1871 }
1872
1873 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1874 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1875 .setPriority(PRIORITY_DEFAULT)
1876 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1877 .setCookie(cookie)
1878 .setCommand(flowModCommand)
1879 .setMatch(match)
1880 .setActions(actions)
1881 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1882
1883 //
1884 // TODO: Set the following flag
1885 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1886 // See method ForwardingBase::pushRoute()
1887 //
1888
1889 //
1890 // Write the message to the switch
1891 //
1892 try {
1893 messageDamper.write(mySwitch, fm, null);
1894 mySwitch.flush();
1895 } catch (IOException e) {
1896 log.error("Failure writing flow mod from network map", e);
1897 return false;
1898 }
1899 return true;
1900 }
1901
1902 /**
1903 * Remove a Flow Entry from a switch.
1904 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001905 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001906 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001907 * @param flowEntry the flow entry to remove.
1908 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001909 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001910 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001911 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1912 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001913 //
1914 // The installFlowEntry() method implements both installation
1915 // and removal of flow entries.
1916 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001917 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001918 }
1919
1920 /**
1921 * Install a Flow Entry on a remote controller.
1922 *
1923 * TODO: We need it now: Jono
1924 * - For now it will make a REST call to the remote controller.
1925 * - Internally, it needs to know the name of the remote controller.
1926 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001927 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001928 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001929 * @return true on success, otherwise false.
1930 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001931 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001932 public boolean installRemoteFlowEntry(FlowPath flowPath,
1933 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001934 // TODO: We need it now: Jono
1935 // - For now it will make a REST call to the remote controller.
1936 // - Internally, it needs to know the name of the remote controller.
1937 return true;
1938 }
1939
1940 /**
1941 * Remove a flow entry on a remote controller.
1942 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001943 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001944 * @param flowEntry the flow entry to remove.
1945 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001946 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001947 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001948 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1949 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001950 //
1951 // The installRemoteFlowEntry() method implements both installation
1952 // and removal of flow entries.
1953 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001954 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001955 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001956}