blob: 0a6e945150e28806af46ca56538042803edd15a4 [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
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700326 log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
327 myFlowEntries.size());
328
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700329 //
330 // Process my Flow Entries
331 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700332 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700333 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700334 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700335 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700336 IFlowPath flowObj =
337 conn.utils().getFlowPathByFlowEntry(conn,
338 flowEntryObj);
339 if (flowObj == null)
340 continue; // Should NOT happen
341
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700342 // Code for measurement purpose
343 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700344 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700345 processed_measurement_flow = true;
346 }
347 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700348
349 //
350 // TODO: Eliminate the re-fetching of flowEntryId,
351 // userState, switchState, and dpid from the flowEntryObj.
352 //
353 FlowEntryId flowEntryId =
354 new FlowEntryId(flowEntryObj.getFlowEntryId());
355 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
356 String userState = flowEntryObj.getUserState();
357 String switchState = flowEntryObj.getSwitchState();
358 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000359 if (mySwitch == null)
360 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800361
362 //
363 // Create the Open Flow Flow Modification Entry to push
364 //
365 OFFlowMod fm =
366 (OFFlowMod) floodlightProvider.getOFMessageFactory()
367 .getMessage(OFType.FLOW_MOD);
368 long cookie = flowEntryId.value();
369
370 short flowModCommand = OFFlowMod.OFPFC_ADD;
371 if (userState.equals("FE_USER_ADD")) {
372 flowModCommand = OFFlowMod.OFPFC_ADD;
373 } else if (userState.equals("FE_USER_MODIFY")) {
374 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
375 } else if (userState.equals("FE_USER_DELETE")) {
376 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
377 } else {
378 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700379 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
380 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800381 continue;
382 }
383
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700384 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700385 // Fetch the match conditions.
386 //
387 // NOTE: The Flow matching conditions common for all
388 // Flow Entries are used ONLY if a Flow Entry does NOT
389 // have the corresponding matching condition set.
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700390 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800391 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700392 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700393 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700394 Short matchInPort = flowEntryObj.getMatchInPort();
395 if (matchInPort != null) {
396 match.setInputPort(matchInPort);
397 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
398 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700399 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700400 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700401 if (matchEthernetFrameType == null)
402 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700403 if (matchEthernetFrameType != null) {
404 match.setDataLayerType(matchEthernetFrameType);
405 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
406 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700407 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700408 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700409 if (matchSrcIPv4Net == null)
410 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700411 if (matchSrcIPv4Net != null) {
412 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
413 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700414 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700415 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700416 if (matchDstIPv4Net == null)
417 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700418 if (matchDstIPv4Net != null) {
419 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
420 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700421 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700422 String matchSrcMac = flowEntryObj.getMatchSrcMac();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700423 if (matchSrcMac == null)
424 matchSrcMac = flowObj.getMatchSrcMac();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700425 if (matchSrcMac != null) {
426 match.setDataLayerSource(matchSrcMac);
427 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
428 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700429 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700430 String matchDstMac = flowEntryObj.getMatchDstMac();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700431 if (matchDstMac == null)
432 matchDstMac = flowObj.getMatchDstMac();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700433 if (matchDstMac != null) {
434 match.setDataLayerDestination(matchDstMac);
435 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
436 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700437
438 //
439 // Fetch the actions
440 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800441 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700442 Short actionOutputPort = flowEntryObj.getActionOutput();
443 if (actionOutputPort != null) {
444 OFActionOutput action = new OFActionOutput();
445 // XXX: The max length is hard-coded for now
446 action.setMaxLength((short)0xffff);
447 action.setPort(actionOutputPort);
448 actions.add(action);
449 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800450
451 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
452 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700453 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800454 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
455 .setCookie(cookie)
456 .setCommand(flowModCommand)
457 .setMatch(match)
458 .setActions(actions)
459 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700460 fm.setOutPort(OFPort.OFPP_NONE.getValue());
461 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
462 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
463 if (actionOutputPort != null)
464 fm.setOutPort(actionOutputPort);
465 }
466
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800467 //
468 // TODO: Set the following flag
469 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
470 // See method ForwardingBase::pushRoute()
471 //
472 try {
473 messageDamper.write(mySwitch, fm, null);
474 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000475 //
476 // TODO: We should use the OpenFlow Barrier mechanism
477 // to check for errors, and update the SwitchState
478 // for a flow entry after the Barrier message is
479 // is received.
480 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800481 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
482 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000483 // An entry that needs to be deleted.
484 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800485 }
486 } catch (IOException e) {
487 log.error("Failure writing flow mod from network map", e);
488 }
489 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000490
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700491 log.debug("MEASUREMENT: Found {} Flow Entries to delete",
492 deleteFlowEntries.size());
493
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000494 //
495 // Delete all entries marked for deletion
496 //
497 // TODO: We should use the OpenFlow Barrier mechanism
498 // to check for errors, and delete the Flow Entries after the
499 // Barrier message is received.
500 //
501 while (! deleteFlowEntries.isEmpty()) {
502 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
503 IFlowPath flowObj =
504 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
505 if (flowObj == null) {
506 log.debug("Did not find FlowPath to be deleted");
507 continue;
508 }
509 flowObj.removeFlowEntry(flowEntryObj);
510 conn.utils().removeFlowEntry(conn, flowEntryObj);
511
512 // Test whether the last flow entry
513 Iterable<IFlowEntry> tmpflowEntries =
514 flowObj.getFlowEntries();
515 boolean found = false;
516 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
517 found = true;
518 break;
519 }
520 if (! found) {
521 // Remove the Flow Path as well
522 conn.utils().removeFlowPath(conn, flowObj);
523 }
524 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700525
526
527 //
528 // Fetch and recompute the Shortest Path for those
529 // Flow Paths this controller is responsible for.
530 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700531 topoRouteService.prepareShortestPathTopo();
532 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
533 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
534 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700535 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700536 if (flowPathObj == null)
537 continue;
538 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
539 if (dataPathSummaryStr == null)
540 continue; // Could be invalid entry?
541 if (dataPathSummaryStr.isEmpty())
542 continue; // No need to maintain this flow
543
544 // Fetch the fields needed to recompute the shortest path
545 String flowIdStr = flowPathObj.getFlowId();
546 String srcDpidStr = flowPathObj.getSrcSwitch();
547 Short srcPortShort = flowPathObj.getSrcPort();
548 String dstDpidStr = flowPathObj.getDstSwitch();
549 Short dstPortShort = flowPathObj.getDstPort();
550 if ((flowIdStr == null) ||
551 (srcDpidStr == null) ||
552 (srcPortShort == null) ||
553 (dstDpidStr == null) ||
554 (dstPortShort == null)) {
555 log.debug("IGNORING Flow Path entry with null fields");
556 continue;
557 }
558
559 FlowId flowId = new FlowId(flowIdStr);
560 Dpid srcDpid = new Dpid(srcDpidStr);
561 Port srcPort = new Port(srcPortShort);
562 Dpid dstDpid = new Dpid(dstDpidStr);
563 Port dstPort = new Port(dstPortShort);
564 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
565 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700566
567 //
568 // Use the source DPID as a heuristic to decide
569 // which controller is responsible for maintaining the
570 // shortest path.
571 // NOTE: This heuristic is error-prone: if the switch
572 // goes away and no controller is responsible for that
573 // switch, then the original Flow Path is not cleaned-up
574 //
575 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
576 if (mySwitch == null)
577 continue; // Ignore: not my responsibility
578
579 counterMyFlowPaths++;
580
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700581 //
582 // NOTE: Using here the regular getShortestPath() method
583 // won't work here, because that method calls internally
584 // "conn.endTx(Transaction.COMMIT)", and that will
585 // invalidate all handlers to the Titan database.
586 // If we want to experiment with calling here
587 // getShortestPath(), we need to refactor that code
588 // to avoid closing the transaction.
589 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700590 DataPath dataPath =
591 topoRouteService.getTopoShortestPath(srcSwitchPort,
592 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000593 if (dataPath == null) {
594 // We need the DataPath to compare the paths
595 dataPath = new DataPath();
596 dataPath.setSrcPort(srcSwitchPort);
597 dataPath.setDstPort(dstSwitchPort);
598 }
599
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700600 String newDataPathSummaryStr = dataPath.dataPathSummary();
601 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
602 continue; // Nothing changed
603
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700604 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
605 flowId.toString());
606 flowObjSet.add(flowPathObj);
607 }
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700608 log.debug("MEASUREMENT: Found {} Flow Entries to reconcile",
609 flowObjSet.size());
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700610 reconcileFlows(flowObjSet);
611 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700612
613
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800614 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700615
616 if (processed_measurement_flow) {
617 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
618 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
619 (double)estimatedTime / 1000000000 + " sec";
620 log.debug(logMsg);
621 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700622
623 long estimatedTime = System.nanoTime() - startTime;
624 double rate = (estimatedTime > 0)? ((double)counterAllFlowPaths * 1000000000) / estimatedTime: 0.0;
625 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " + counterAllFlowEntries + " MyNotUpdatedFlowEntries: " + counterMyNotUpdatedFlowEntries + " AllFlowPaths: " + counterAllFlowPaths + " MyFlowPaths: " + counterMyFlowPaths + " in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " paths/s";
626 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800627 }
628 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700629
630 /*
631 final ScheduledFuture<?> measureShortestPathHandle =
632 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
633 */
634
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700635 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700636 final ScheduledFuture<?> measureMapReaderHandle =
637 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700638 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700639
640 final ScheduledFuture<?> mapReaderHandle =
641 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800642
643 @Override
644 public void init(String conf) {
645 conn = GraphDBConnection.getInstance(conf);
646 }
647
648 public void finalize() {
649 close();
650 }
651
652 @Override
653 public void close() {
654 conn.close();
655 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800656
657 @Override
658 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
659 Collection<Class<? extends IFloodlightService>> l =
660 new ArrayList<Class<? extends IFloodlightService>>();
661 l.add(IFlowService.class);
662 return l;
663 }
664
665 @Override
666 public Map<Class<? extends IFloodlightService>, IFloodlightService>
667 getServiceImpls() {
668 Map<Class<? extends IFloodlightService>,
669 IFloodlightService> m =
670 new HashMap<Class<? extends IFloodlightService>,
671 IFloodlightService>();
672 m.put(IFlowService.class, this);
673 return m;
674 }
675
676 @Override
677 public Collection<Class<? extends IFloodlightService>>
678 getModuleDependencies() {
679 Collection<Class<? extends IFloodlightService>> l =
680 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800681 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700682 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800683 l.add(IRestApiService.class);
684 return l;
685 }
686
687 @Override
688 public void init(FloodlightModuleContext context)
689 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700690 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800691 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700692 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800693 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800694 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
695 EnumSet.of(OFType.FLOW_MOD),
696 OFMESSAGE_DAMPER_TIMEOUT);
697 // TODO: An ugly hack!
698 String conf = "/tmp/cassandra.titan";
699 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800700 }
701
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000702 private long getNextFlowEntryId() {
703 //
704 // Generate the next Flow Entry ID.
705 // NOTE: For now, the higher 32 bits are random, and
706 // the lower 32 bits are sequential.
707 // In the future, we need a better allocation mechanism.
708 //
709 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
710 nextFlowEntryIdPrefix = randomGenerator.nextInt();
711 nextFlowEntryIdSuffix = 0;
712 } else {
713 nextFlowEntryIdSuffix++;
714 }
715 long result = (long)nextFlowEntryIdPrefix << 32;
716 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
717 return result;
718 }
719
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800720 @Override
721 public void startUp(FloodlightModuleContext context) {
722 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700723
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000724 // Initialize the Flow Entry ID generator
725 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800726 }
727
728 /**
729 * Add a flow.
730 *
731 * Internally, ONOS will automatically register the installer for
732 * receiving Flow Path Notifications for that path.
733 *
734 * @param flowPath the Flow Path to install.
735 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700736 * @param dataPathSummaryStr the data path summary string if the added
737 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800738 * @return true on success, otherwise false.
739 */
740 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700741 public boolean addFlow(FlowPath flowPath, FlowId flowId,
742 String dataPathSummaryStr) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700743 if (flowPath.flowId().value() == measurementFlowId) {
744 modifiedMeasurementFlowTime = System.nanoTime();
745 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800746
747 //
748 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700749 // Right now every new flow entry gets a new flow entry ID
750 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800751 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800752 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000753 long id = getNextFlowEntryId();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800754 flowEntry.setFlowEntryId(new FlowEntryId(id));
755 }
756
757 IFlowPath flowObj = null;
758 try {
759 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
760 != null) {
761 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
762 flowPath.flowId().toString());
763 } else {
764 flowObj = conn.utils().newFlowPath(conn);
765 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
766 flowPath.flowId().toString());
767 }
768 } catch (Exception e) {
769 // TODO: handle exceptions
770 conn.endTx(Transaction.ROLLBACK);
771 log.error(":addFlow FlowId:{} failed",
772 flowPath.flowId().toString());
773 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700774 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000775 log.error(":addFlow FlowId:{} failed: Flow object not created",
776 flowPath.flowId().toString());
777 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800778 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700779 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800780
781 //
782 // Set the Flow key:
783 // - flowId
784 //
785 flowObj.setFlowId(flowPath.flowId().toString());
786 flowObj.setType("flow");
787
788 //
789 // Set the Flow attributes:
790 // - flowPath.installerId()
791 // - flowPath.dataPath().srcPort()
792 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700793 // - flowPath.matchEthernetFrameType()
794 // - flowPath.matchSrcIPv4Net()
795 // - flowPath.matchDstIPv4Net()
796 // - flowPath.matchSrcMac()
797 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800798 //
799 flowObj.setInstallerId(flowPath.installerId().toString());
800 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
801 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
802 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
803 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700804 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
805 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
806 }
807 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
808 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
809 }
810 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
811 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
812 }
813 if (flowPath.flowEntryMatch().matchSrcMac()) {
814 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
815 }
816 if (flowPath.flowEntryMatch().matchDstMac()) {
817 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
818 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800819
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700820 if (dataPathSummaryStr != null) {
821 flowObj.setDataPathSummary(dataPathSummaryStr);
822 } else {
823 flowObj.setDataPathSummary("");
824 }
825
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800826 // Flow edges:
827 // HeadFE
828
829
830 //
831 // Flow Entries:
832 // flowPath.dataPath().flowEntries()
833 //
834 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
835 IFlowEntry flowEntryObj = null;
836 boolean found = false;
837 try {
838 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
839 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
840 flowEntry.flowEntryId().toString());
841 found = true;
842 } else {
843 flowEntryObj = conn.utils().newFlowEntry(conn);
844 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
845 flowEntry.flowEntryId().toString());
846 }
847 } catch (Exception e) {
848 // TODO: handle exceptions
849 conn.endTx(Transaction.ROLLBACK);
850 log.error(":addFlow FlowEntryId:{} failed",
851 flowEntry.flowEntryId().toString());
852 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700853 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000854 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
855 flowEntry.flowEntryId().toString());
856 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800857 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700858 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800859
860 //
861 // Set the Flow Entry key:
862 // - flowEntry.flowEntryId()
863 //
864 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
865 flowEntryObj.setType("flow_entry");
866
867 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700868 // Set the Flow Entry Edges and attributes:
869 // - Switch edge
870 // - InPort edge
871 // - OutPort edge
872 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800873 // - flowEntry.flowEntryMatch()
874 // - flowEntry.flowEntryActions()
875 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800876 // - flowEntry.flowEntryUserState()
877 // - flowEntry.flowEntrySwitchState()
878 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700879 // - flowEntry.matchInPort()
880 // - flowEntry.matchEthernetFrameType()
881 // - flowEntry.matchSrcIPv4Net()
882 // - flowEntry.matchDstIPv4Net()
883 // - flowEntry.matchSrcMac()
884 // - flowEntry.matchDstMac()
885 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800886 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700887 ISwitchObject sw =
888 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800889 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700890 flowEntryObj.setSwitch(sw);
891 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700892 IPortObject inport =
893 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
894 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700895 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
896 flowEntryObj.setInPort(inport);
897 }
898 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
899 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
900 }
901 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
902 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
903 }
904 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
905 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
906 }
907 if (flowEntry.flowEntryMatch().matchSrcMac()) {
908 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
909 }
910 if (flowEntry.flowEntryMatch().matchDstMac()) {
911 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
912 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700913
914 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700915 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700916 IPortObject outport =
917 conn.utils().searchPort(conn,
918 flowEntry.dpid().toString(),
919 fa.actionOutput().port().value());
920 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
921 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700922 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700923 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800924 // TODO: Hacks with hard-coded state names!
925 if (found)
926 flowEntryObj.setUserState("FE_USER_MODIFY");
927 else
928 flowEntryObj.setUserState("FE_USER_ADD");
929 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
930 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700931 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800932 //
933
934 // Flow Entries edges:
935 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700936 // NextFE (TODO)
937 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800938 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700939 flowEntryObj.setFlow(flowObj);
940 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800941 }
942 conn.endTx(Transaction.COMMIT);
943
944 //
945 // TODO: We need a proper Flow ID allocation mechanism.
946 //
947 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700948
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800949 return true;
950 }
951
952 /**
953 * Delete a previously added flow.
954 *
955 * @param flowId the Flow ID of the flow to delete.
956 * @return true on success, otherwise false.
957 */
958 @Override
959 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700960 if (flowId.value() == measurementFlowId) {
961 modifiedMeasurementFlowTime = System.nanoTime();
962 }
963
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800964 IFlowPath flowObj = null;
965 //
966 // We just mark the entries for deletion,
967 // and let the switches remove each individual entry after
968 // it has been removed from the switches.
969 //
970 try {
971 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
972 != null) {
973 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
974 flowId.toString());
975 } else {
976 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
977 flowId.toString());
978 }
979 } catch (Exception e) {
980 // TODO: handle exceptions
981 conn.endTx(Transaction.ROLLBACK);
982 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
983 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700984 if (flowObj == null) {
985 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800986 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700987 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800988
989 //
990 // Find and mark for deletion all Flow Entries
991 //
992 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
993 boolean empty = true; // TODO: an ugly hack
994 for (IFlowEntry flowEntryObj : flowEntries) {
995 empty = false;
996 // flowObj.removeFlowEntry(flowEntryObj);
997 // conn.utils().removeFlowEntry(conn, flowEntryObj);
998 flowEntryObj.setUserState("FE_USER_DELETE");
999 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1000 }
1001 // Remove from the database empty flows
1002 if (empty)
1003 conn.utils().removeFlowPath(conn, flowObj);
1004 conn.endTx(Transaction.COMMIT);
1005
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001006 return true;
1007 }
1008
1009 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001010 * Clear the state for a previously added flow.
1011 *
1012 * @param flowId the Flow ID of the flow to clear.
1013 * @return true on success, otherwise false.
1014 */
1015 @Override
1016 public boolean clearFlow(FlowId flowId) {
1017 IFlowPath flowObj = null;
1018 try {
1019 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
1020 != null) {
1021 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1022 flowId.toString());
1023 } else {
1024 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1025 flowId.toString());
1026 }
1027 } catch (Exception e) {
1028 // TODO: handle exceptions
1029 conn.endTx(Transaction.ROLLBACK);
1030 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1031 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001032 if (flowObj == null) {
1033 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001034 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001035 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001036
1037 //
1038 // Remove all Flow Entries
1039 //
1040 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1041 for (IFlowEntry flowEntryObj : flowEntries) {
1042 flowObj.removeFlowEntry(flowEntryObj);
1043 conn.utils().removeFlowEntry(conn, flowEntryObj);
1044 }
1045 // Remove the Flow itself
1046 conn.utils().removeFlowPath(conn, flowObj);
1047 conn.endTx(Transaction.COMMIT);
1048
1049 return true;
1050 }
1051
1052 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001053 * Get a previously added flow.
1054 *
1055 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001056 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001057 */
1058 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001059 public FlowPath getFlow(FlowId flowId) {
1060 IFlowPath flowObj = null;
1061 try {
1062 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
1063 != null) {
1064 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1065 flowId.toString());
1066 } else {
1067 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1068 flowId.toString());
1069 }
1070 } catch (Exception e) {
1071 // TODO: handle exceptions
1072 conn.endTx(Transaction.ROLLBACK);
1073 log.error(":getFlow FlowId:{} failed", flowId.toString());
1074 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001075 if (flowObj == null) {
1076 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001077 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001078 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001079
1080 //
1081 // Extract the Flow state
1082 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001083 FlowPath flowPath = extractFlowPath(flowObj);
1084 conn.endTx(Transaction.COMMIT);
1085
1086 return flowPath;
1087 }
1088
1089 /**
1090 * Get all previously added flows by a specific installer for a given
1091 * data path endpoints.
1092 *
1093 * @param installerId the Caller ID of the installer of the flow to get.
1094 * @param dataPathEndpoints the data path endpoints of the flow to get.
1095 * @return the Flow Paths if found, otherwise null.
1096 */
1097 @Override
1098 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1099 DataPathEndpoints dataPathEndpoints) {
1100 //
1101 // TODO: The implementation below is not optimal:
1102 // We fetch all flows, and then return only the subset that match
1103 // the query conditions.
1104 // We should use the appropriate Titan/Gremlin query to filter-out
1105 // the flows as appropriate.
1106 //
1107 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001108 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001109
1110 if (allFlows == null) {
1111 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001112 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001113 }
1114
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001115 for (FlowPath flow : allFlows) {
1116 //
1117 // TODO: String-based comparison is sub-optimal.
1118 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001119 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001120 //
1121 if (! flow.installerId().toString().equals(installerId.toString()))
1122 continue;
1123 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1124 continue;
1125 }
1126 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1127 continue;
1128 }
1129 flowPaths.add(flow);
1130 }
1131
1132 if (flowPaths.isEmpty()) {
1133 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001134 } else {
1135 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1136 }
1137
1138 return flowPaths;
1139 }
1140
1141 /**
1142 * Get all installed flows by all installers for given data path endpoints.
1143 *
1144 * @param dataPathEndpoints the data path endpoints of the flows to get.
1145 * @return the Flow Paths if found, otherwise null.
1146 */
1147 @Override
1148 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1149 //
1150 // TODO: The implementation below is not optimal:
1151 // We fetch all flows, and then return only the subset that match
1152 // the query conditions.
1153 // We should use the appropriate Titan/Gremlin query to filter-out
1154 // the flows as appropriate.
1155 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001156 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1157 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001158
1159 if (allFlows == null) {
1160 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001161 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001162 }
1163
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001164 for (FlowPath flow : allFlows) {
1165 //
1166 // TODO: String-based comparison is sub-optimal.
1167 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001168 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001169 //
1170 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1171 continue;
1172 }
1173 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1174 continue;
1175 }
1176 flowPaths.add(flow);
1177 }
1178
1179 if (flowPaths.isEmpty()) {
1180 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001181 } else {
1182 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1183 }
1184
1185 return flowPaths;
1186 }
1187
1188 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001189 * Get summary of all installed flows by all installers in a given range
1190 *
1191 * @param flowId the data path endpoints of the flows to get.
1192 * @param maxFlows: the maximum number of flows to be returned
1193 * @return the Flow Paths if found, otherwise null.
1194 */
1195 @Override
1196 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1197 //
1198 // TODO: The implementation below is not optimal:
1199 // We fetch all flows, and then return only the subset that match
1200 // the query conditions.
1201 // We should use the appropriate Titan/Gremlin query to filter-out
1202 // the flows as appropriate.
1203 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001204 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1205
1206 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001207
1208 if (allFlows == null) {
1209 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001210 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001211 }
1212
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001213 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001214
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001215 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001216 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001217
1218 // start from desired flowId
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -07001219 //if (flow.flowId().value() < flowId.value()) {
1220 // continue;
1221 //}
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001222
1223 // Summarize by making null flow entry fields that are not relevant to report
1224 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1225 flowEntry.setFlowEntryActions(null);
1226 flowEntry.setFlowEntryMatch(null);
1227 }
1228
1229 flowPaths.add(flow);
1230 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1231 break;
1232 }
1233 }
1234
1235 if (flowPaths.isEmpty()) {
1236 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001237 } else {
1238 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1239 }
1240
1241 return flowPaths;
1242 }
1243
1244 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001245 * Get all installed flows by all installers.
1246 *
1247 * @return the Flow Paths if found, otherwise null.
1248 */
1249 @Override
1250 public ArrayList<FlowPath> getAllFlows() {
1251 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001252 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001253
1254 try {
1255 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1256 log.debug("Get all FlowPaths: found FlowPaths");
1257 } else {
1258 log.debug("Get all FlowPaths: no FlowPaths found");
1259 }
1260 } catch (Exception e) {
1261 // TODO: handle exceptions
1262 conn.endTx(Transaction.ROLLBACK);
1263 log.error(":getAllFlowPaths failed");
1264 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001265 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1266 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001267 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001268 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001269
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001270 for (IFlowPath flowObj : flowPathsObj) {
1271 //
1272 // Extract the Flow state
1273 //
1274 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001275 if (flowPath != null)
1276 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001277 }
1278
1279 conn.endTx(Transaction.COMMIT);
1280
1281 return flowPaths;
1282 }
1283
1284 /**
1285 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1286 *
1287 * @param flowObj the object to extract the Flow Path State from.
1288 * @return the extracted Flow Path State.
1289 */
1290 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001291 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001292
1293 //
1294 // Extract the Flow state
1295 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001296 String flowIdStr = flowObj.getFlowId();
1297 String installerIdStr = flowObj.getInstallerId();
1298 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001299 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001300 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001301 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001302
1303 if ((flowIdStr == null) ||
1304 (installerIdStr == null) ||
1305 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001306 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001307 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001308 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001309 // TODO: A work-around, becauuse of some bogus database objects
1310 return null;
1311 }
1312
1313 flowPath.setFlowId(new FlowId(flowIdStr));
1314 flowPath.setInstallerId(new CallerId(installerIdStr));
1315 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001316 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001317 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001318 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001319 //
1320 // Extract the match conditions common for all Flow Entries
1321 //
1322 {
1323 FlowEntryMatch match = new FlowEntryMatch();
1324 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1325 if (matchEthernetFrameType != null)
1326 match.enableEthernetFrameType(matchEthernetFrameType);
1327 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1328 if (matchSrcIPv4Net != null)
1329 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1330 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1331 if (matchDstIPv4Net != null)
1332 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1333 String matchSrcMac = flowObj.getMatchSrcMac();
1334 if (matchSrcMac != null)
1335 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1336 String matchDstMac = flowObj.getMatchDstMac();
1337 if (matchDstMac != null)
1338 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1339 flowPath.setFlowEntryMatch(match);
1340 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001341
1342 //
1343 // Extract all Flow Entries
1344 //
1345 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1346 for (IFlowEntry flowEntryObj : flowEntries) {
1347 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001348 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1349 String switchDpidStr = flowEntryObj.getSwitchDpid();
1350 String userState = flowEntryObj.getUserState();
1351 String switchState = flowEntryObj.getSwitchState();
1352
1353 if ((flowEntryIdStr == null) ||
1354 (switchDpidStr == null) ||
1355 (userState == null) ||
1356 (switchState == null)) {
1357 // TODO: A work-around, becauuse of some bogus database objects
1358 continue;
1359 }
1360 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1361 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001362
1363 //
1364 // Extract the match conditions
1365 //
1366 FlowEntryMatch match = new FlowEntryMatch();
1367 Short matchInPort = flowEntryObj.getMatchInPort();
1368 if (matchInPort != null)
1369 match.enableInPort(new Port(matchInPort));
1370 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1371 if (matchEthernetFrameType != null)
1372 match.enableEthernetFrameType(matchEthernetFrameType);
1373 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1374 if (matchSrcIPv4Net != null)
1375 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1376 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1377 if (matchDstIPv4Net != null)
1378 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1379 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1380 if (matchSrcMac != null)
1381 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1382 String matchDstMac = flowEntryObj.getMatchDstMac();
1383 if (matchDstMac != null)
1384 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1385 flowEntry.setFlowEntryMatch(match);
1386
1387 //
1388 // Extract the actions
1389 //
1390 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1391 Short actionOutputPort = flowEntryObj.getActionOutput();
1392 if (actionOutputPort != null) {
1393 FlowEntryAction action = new FlowEntryAction();
1394 action.setActionOutput(new Port(actionOutputPort));
1395 actions.add(action);
1396 }
1397 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001398 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001399 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1400 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001401 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001402 // and FlowEntryErrorState.
1403 //
1404 flowPath.dataPath().flowEntries().add(flowEntry);
1405 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001406
1407 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001408 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001409
1410 /**
1411 * Add and maintain a shortest-path flow.
1412 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001413 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001414 *
1415 * @param flowPath the Flow Path with the endpoints and the match
1416 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001417 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001418 */
1419 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001420 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001421 String dataPathSummaryStr = null;
1422
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001423 //
1424 // Do the shortest path computation
1425 //
1426 DataPath dataPath =
1427 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1428 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001429 if (dataPath == null) {
1430 // We need the DataPath to populate the Network MAP
1431 dataPath = new DataPath();
1432 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1433 dataPath.setDstPort(flowPath.dataPath().dstPort());
1434 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001435
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001436 // Compute the Data Path summary
1437 dataPathSummaryStr = dataPath.dataPathSummary();
1438
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001439 //
1440 // Set the incoming port matching and the outgoing port output
1441 // actions for each flow entry.
1442 //
1443 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1444 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001445 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001446 flowEntry.setFlowEntryMatch(flowEntryMatch);
1447 flowEntryMatch.enableInPort(flowEntry.inPort());
1448
1449 // Set the outgoing port output action
1450 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1451 if (flowEntryActions == null) {
1452 flowEntryActions = new ArrayList<FlowEntryAction>();
1453 flowEntry.setFlowEntryActions(flowEntryActions);
1454 }
1455 FlowEntryAction flowEntryAction = new FlowEntryAction();
1456 flowEntryAction.setActionOutput(flowEntry.outPort());
1457 flowEntryActions.add(flowEntryAction);
1458 }
1459
1460 //
1461 // Prepare the computed Flow Path
1462 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001463 FlowPath computedFlowPath = new FlowPath();
1464 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1465 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1466 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001467 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001468
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001469 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001470 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001471 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001472
1473 // TODO: Mark the flow for maintenance purpose
1474
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001475 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001476 }
1477
1478 /**
1479 * Create a Flow from port to port.
1480 *
1481 * TODO: We don't need it for now.
1482 *
1483 * @param src_port the source port.
1484 * @param dest_port the destination port.
1485 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001486 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001487 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1488 // TODO: We don't need it for now.
1489 }
1490
1491 /**
1492 * Get all Flows matching a source and a destination port.
1493 *
1494 * TODO: Pankaj might be implementing it later.
1495 *
1496 * @param src_port the source port to match.
1497 * @param dest_port the destination port to match.
1498 * @return all flows matching the source and the destination port.
1499 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001500 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001501 public Iterable<FlowPath> getFlows(IPortObject src_port,
1502 IPortObject dest_port) {
1503 // TODO: Pankaj might be implementing it later.
1504 return null;
1505 }
1506
1507 /**
1508 * Get all Flows going out from a port.
1509 *
1510 * TODO: We need it now: Pankaj
1511 *
1512 * @param port the port to match.
1513 * @return the list of flows that are going out from the port.
1514 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001515 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001516 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001517 // TODO: We need it now: Pankaj
1518 return null;
1519 }
1520
1521 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001522 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001523 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001524 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001525 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001526 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001527 public void reconcileFlows(IPortObject portObject) {
1528 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1529 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001530
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001531 //
1532 // Collect all affected Flow IDs from the affected flow entries
1533 //
1534 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1535 for (IFlowEntry flowEntryObj: inFlowEntries) {
1536 IFlowPath flowObj = flowEntryObj.getFlow();
1537 if (flowObj != null)
1538 flowObjSet.add(flowObj);
1539 }
1540 for (IFlowEntry flowEntryObj: outFlowEntries) {
1541 IFlowPath flowObj = flowEntryObj.getFlow();
1542 if (flowObj != null)
1543 flowObjSet.add(flowObj);
1544 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001545
1546 // Reconcile the affected flows
1547 reconcileFlows(flowObjSet);
1548 }
1549
1550 /**
1551 * Reconcile all flows in a set.
1552 *
1553 * @param flowObjSet the set of flows that need to be reconciliated.
1554 */
1555 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1556 if (! flowObjSet.iterator().hasNext())
1557 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001558
1559 //
1560 // Remove the old Flow Entries, and add the new Flow Entries
1561 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001562
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001563 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001564 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001565 for (IFlowPath flowObj : flowObjSet) {
1566 FlowPath flowPath = extractFlowPath(flowObj);
1567 if (flowPath == null)
1568 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001569 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001570
1571 //
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001572 // Remove the Flow Entries from the Network MAP
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001573 //
1574 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001575 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001576 for (IFlowEntry flowEntryObj : flowEntries) {
1577 String dpidStr = flowEntryObj.getSwitchDpid();
1578 if (dpidStr == null)
1579 continue;
1580 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001581 /*
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001582 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1583 if (mySwitch == null)
1584 continue; // Ignore the entry: not my switch
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001585 */
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001586 deleteFlowEntries.add(flowEntryObj);
1587 }
1588 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001589 flowObj.removeFlowEntry(flowEntryObj);
1590 conn.utils().removeFlowEntry(conn, flowEntryObj);
1591 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001592 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001593
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001594 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001595 //
1596 // Delete the flow entries from the switches
1597 //
1598 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1599 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001600 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1601 if (mySwitch == null) {
1602 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001603 installRemoteFlowEntry(flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001604 } else {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001605 installFlowEntry(mySwitch, flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001606 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001607 }
1608
1609 //
1610 // Calculate the new shortest path and install it in the
1611 // Network MAP.
1612 //
1613 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1614 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001615 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001616 flowPath.dataPath().srcPort().toString(),
1617 flowPath.dataPath().dstPort().toString());
1618 continue;
1619 }
1620
1621 //
1622 // Add the flow entries to the switches
1623 //
1624 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1625 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001626 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1627 if (mySwitch == null) {
1628 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001629 installRemoteFlowEntry(addedFlowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001630 continue;
1631 }
1632
1633 IFlowEntry flowEntryObj =
1634 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1635 if (flowEntryObj == null) {
1636 //
1637 // TODO: Remove the "new Object[] wrapper in the statement
1638 // below after the SLF4J logger is upgraded to
1639 // Version 1.7.5
1640 //
1641 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1642 new Object[] {
1643 flowEntry.dpid(),
1644 flowPath.dataPath().srcPort(),
1645 flowPath.dataPath().dstPort()
1646 });
1647 continue;
1648 }
1649 // Update the Flow Entry Switch State in the Network MAP
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001650 if (installFlowEntry(mySwitch, addedFlowPath, flowEntry)) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001651 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1652 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001653 }
1654 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001655 }
1656
1657 /**
1658 * Reconcile all flows between a source and a destination port.
1659 *
1660 * TODO: We don't need it for now.
1661 *
1662 * @param src_port the source port.
1663 * @param dest_port the destination port.
1664 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001665 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001666 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1667 // TODO: We don't need it for now.
1668 }
1669
1670 /**
1671 * Compute the shortest path between a source and a destination ports.
1672 *
1673 * @param src_port the source port.
1674 * @param dest_port the destination port.
1675 * @return the computed shortest path between the source and the
1676 * destination ports. The flow entries in the path itself would
1677 * contain the incoming port matching and the outgoing port output
1678 * actions set. However, the path itself will NOT have the Flow ID,
1679 * Installer ID, and any additional matching conditions for the
1680 * flow entries (e.g., source or destination MAC address, etc).
1681 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001682 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001683 public FlowPath computeFlowPath(IPortObject src_port,
1684 IPortObject dest_port) {
1685 //
1686 // Prepare the arguments
1687 //
1688 String dpidStr = src_port.getSwitch().getDPID();
1689 Dpid srcDpid = new Dpid(dpidStr);
1690 Port srcPort = new Port(src_port.getNumber());
1691
1692 dpidStr = dest_port.getSwitch().getDPID();
1693 Dpid dstDpid = new Dpid(dpidStr);
1694 Port dstPort = new Port(dest_port.getNumber());
1695
1696 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1697 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1698
1699 //
1700 // Do the shortest path computation
1701 //
1702 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1703 if (dataPath == null)
1704 return null;
1705
1706 //
1707 // Set the incoming port matching and the outgoing port output
1708 // actions for each flow entry.
1709 //
1710 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1711 // Set the incoming port matching
1712 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1713 if (flowEntryMatch == null) {
1714 flowEntryMatch = new FlowEntryMatch();
1715 flowEntry.setFlowEntryMatch(flowEntryMatch);
1716 }
1717 flowEntryMatch.enableInPort(flowEntry.inPort());
1718
1719 // Set the outgoing port output action
1720 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1721 if (flowEntryActions == null) {
1722 flowEntryActions = new ArrayList<FlowEntryAction>();
1723 flowEntry.setFlowEntryActions(flowEntryActions);
1724 }
1725 FlowEntryAction flowEntryAction = new FlowEntryAction();
1726 flowEntryAction.setActionOutput(flowEntry.outPort());
1727 flowEntryActions.add(flowEntryAction);
1728 }
1729
1730 //
1731 // Prepare the return result
1732 //
1733 FlowPath flowPath = new FlowPath();
1734 flowPath.setDataPath(dataPath);
1735
1736 return flowPath;
1737 }
1738
1739 /**
1740 * Get all Flow Entries of a Flow.
1741 *
1742 * @param flow the flow whose flow entries should be returned.
1743 * @return the flow entries of the flow.
1744 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001745 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001746 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1747 return flow.dataPath().flowEntries();
1748 }
1749
1750 /**
1751 * Install a Flow Entry on a switch.
1752 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001753 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001754 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001755 * @param flowEntry the flow entry to install.
1756 * @return true on success, otherwise false.
1757 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001758 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001759 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1760 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001761 //
1762 // Create the OpenFlow Flow Modification Entry to push
1763 //
1764 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1765 .getMessage(OFType.FLOW_MOD);
1766 long cookie = flowEntry.flowEntryId().value();
1767
1768 short flowModCommand = OFFlowMod.OFPFC_ADD;
1769 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1770 flowModCommand = OFFlowMod.OFPFC_ADD;
1771 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1772 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1773 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1774 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1775 } else {
1776 // Unknown user state. Ignore the entry
1777 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1778 flowEntry.flowEntryId().toString(),
1779 flowEntry.flowEntryUserState());
1780 return false;
1781 }
1782
1783 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001784 // Fetch the match conditions.
1785 //
1786 // NOTE: The Flow matching conditions common for all Flow Entries are
1787 // used ONLY if a Flow Entry does NOT have the corresponding matching
1788 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001789 //
1790 OFMatch match = new OFMatch();
1791 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001792 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1793 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1794
1795 // Match the Incoming Port
1796 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001797 if (matchInPort != null) {
1798 match.setInputPort(matchInPort.value());
1799 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1800 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001801
1802 // Match the Ethernet Frame Type
1803 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1804 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1805 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1806 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001807 if (matchEthernetFrameType != null) {
1808 match.setDataLayerType(matchEthernetFrameType);
1809 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1810 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001811
1812 // Match the Source IPv4 Network prefix
1813 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1814 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1815 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1816 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001817 if (matchSrcIPv4Net != null) {
1818 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1819 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001820
1821 // Natch the Destination IPv4 Network prefix
1822 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1823 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1824 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1825 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001826 if (matchDstIPv4Net != null) {
1827 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1828 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001829
1830 // Match the Source MAC address
1831 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1832 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1833 matchSrcMac = flowPathMatch.srcMac();
1834 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001835 if (matchSrcMac != null) {
1836 match.setDataLayerSource(matchSrcMac.toString());
1837 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1838 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001839
1840 // Match the Destination MAC address
1841 MACAddress matchDstMac = flowEntryMatch.dstMac();
1842 if ((matchDstMac == null) && (flowPathMatch != null)) {
1843 matchDstMac = flowPathMatch.dstMac();
1844 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001845 if (matchDstMac != null) {
1846 match.setDataLayerDestination(matchDstMac.toString());
1847 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1848 }
1849
1850 //
1851 // Fetch the actions
1852 //
1853 // TODO: For now we support only the "OUTPUT" actions.
1854 //
1855 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1856 List<OFAction> actions = new ArrayList<OFAction>();
1857 ArrayList<FlowEntryAction> flowEntryActions =
1858 flowEntry.flowEntryActions();
1859 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1860 FlowEntryAction.ActionOutput actionOutput =
1861 flowEntryAction.actionOutput();
1862 if (actionOutput != null) {
1863 short actionOutputPort = actionOutput.port().value();
1864 OFActionOutput action = new OFActionOutput();
1865 // XXX: The max length is hard-coded for now
1866 action.setMaxLength((short)0xffff);
1867 action.setPort(actionOutputPort);
1868 actions.add(action);
1869 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1870 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1871 fm.setOutPort(actionOutputPort);
1872 }
1873 }
1874 }
1875
1876 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1877 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1878 .setPriority(PRIORITY_DEFAULT)
1879 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1880 .setCookie(cookie)
1881 .setCommand(flowModCommand)
1882 .setMatch(match)
1883 .setActions(actions)
1884 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1885
1886 //
1887 // TODO: Set the following flag
1888 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1889 // See method ForwardingBase::pushRoute()
1890 //
1891
1892 //
1893 // Write the message to the switch
1894 //
1895 try {
1896 messageDamper.write(mySwitch, fm, null);
1897 mySwitch.flush();
1898 } catch (IOException e) {
1899 log.error("Failure writing flow mod from network map", e);
1900 return false;
1901 }
1902 return true;
1903 }
1904
1905 /**
1906 * Remove a Flow Entry from a switch.
1907 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001908 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001909 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001910 * @param flowEntry the flow entry to remove.
1911 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001912 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001913 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001914 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1915 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001916 //
1917 // The installFlowEntry() method implements both installation
1918 // and removal of flow entries.
1919 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001920 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001921 }
1922
1923 /**
1924 * Install a Flow Entry on a remote controller.
1925 *
1926 * TODO: We need it now: Jono
1927 * - For now it will make a REST call to the remote controller.
1928 * - Internally, it needs to know the name of the remote controller.
1929 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001930 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001931 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001932 * @return true on success, otherwise false.
1933 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001934 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001935 public boolean installRemoteFlowEntry(FlowPath flowPath,
1936 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001937 // TODO: We need it now: Jono
1938 // - For now it will make a REST call to the remote controller.
1939 // - Internally, it needs to know the name of the remote controller.
1940 return true;
1941 }
1942
1943 /**
1944 * Remove a flow entry on a remote controller.
1945 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001946 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001947 * @param flowEntry the flow entry to remove.
1948 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001949 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001950 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001951 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1952 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001953 //
1954 // The installRemoteFlowEntry() method implements both installation
1955 // and removal of flow entries.
1956 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001957 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001958 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001959}