blob: c464b8999911409401ef3b1e782f72bb0679b6cd [file] [log] [blame]
HIGUCHI Yutaedf81d72013-06-12 12:06:57 -07001package net.onrc.onos.ofcontroller.flowcache;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00004import java.io.PrintWriter;
5import java.io.StringWriter;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08006import java.util.ArrayList;
7import java.util.Collection;
Jonathan Hartf5315fb2013-04-05 11:41:56 -07008import java.util.Collections;
9import java.util.Comparator;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080011import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000012import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080014import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000015import java.util.Random;
Pavlin Radoslavov759772f2013-05-20 20:50:00 +000016import java.util.concurrent.ConcurrentLinkedQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import java.util.concurrent.Executors;
18import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080022import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080027import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070028import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080029import net.floodlightcontroller.util.OFMessageDamper;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070030import net.onrc.onos.ofcontroller.core.INetMapStorage;
31import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
32import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
33import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
34import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
35import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
HIGUCHI Yutaefa54882013-06-12 13:13:02 -070036import net.onrc.onos.ofcontroller.flowcache.web.FlowWebRoutable;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070037import net.onrc.onos.ofcontroller.util.CallerId;
38import net.onrc.onos.ofcontroller.util.DataPath;
39import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
40import net.onrc.onos.ofcontroller.util.Dpid;
41import net.onrc.onos.ofcontroller.util.FlowEntry;
42import net.onrc.onos.ofcontroller.util.FlowEntryAction;
43import net.onrc.onos.ofcontroller.util.FlowEntryId;
44import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
45import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
46import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
47import net.onrc.onos.ofcontroller.util.FlowId;
48import net.onrc.onos.ofcontroller.util.FlowPath;
49import net.onrc.onos.ofcontroller.util.IPv4Net;
50import net.onrc.onos.ofcontroller.util.Port;
51import net.onrc.onos.ofcontroller.util.SwitchPort;
Toshio Koide9fe1cb22013-06-13 13:51:11 -070052import net.onrc.onos.util.GraphDBOperation;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080053
54import org.openflow.protocol.OFFlowMod;
55import org.openflow.protocol.OFMatch;
56import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070057import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080058import org.openflow.protocol.OFType;
59import org.openflow.protocol.action.OFAction;
60import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080061import org.slf4j.Logger;
62import org.slf4j.LoggerFactory;
63
Jonathan Hartf5315fb2013-04-05 11:41:56 -070064
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070065public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080066
Toshio Koide9fe1cb22013-06-13 13:51:11 -070067 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080068
69 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070070 protected volatile IFloodlightProviderService floodlightProvider;
71 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070072 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080073
74 protected OFMessageDamper messageDamper;
75
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070076 //
77 // TODO: Values copied from elsewhere (class LearningSwitch).
78 // The local copy should go away!
79 //
80 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
81 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
82 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
83 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
84 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080085
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000086 // Flow Entry ID generation state
87 private static Random randomGenerator = new Random();
88 private static int nextFlowEntryIdPrefix = 0;
89 private static int nextFlowEntryIdSuffix = 0;
90 private static long nextFlowEntryId = 0;
91
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070092 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070093 private static long measurementFlowId = 100000;
94 private static String measurementFlowIdStr = "0x186a0"; // 100000
95 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070096 //
97 private LinkedList<FlowPath> measurementStoredPaths = new LinkedList<FlowPath>();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070098 private long measurementStartTimeProcessingPaths = 0;
99 private long measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000100 Map<Long, ?> measurementShortestPathTopo = null;
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000101 private String measurementPerFlowStr = new String();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700102
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800103 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800104 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
105
106 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700107 private ScheduledExecutorService mapReaderScheduler;
108 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700109
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700110 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800111 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700112 try {
113 runImpl();
114 } catch (Exception e) {
115 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700116 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700117 return;
118 }
119 }
120
121 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700122 long startTime = System.nanoTime();
123 int counterAllFlowEntries = 0;
124 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700125
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800126 if (floodlightProvider == null) {
127 log.debug("FloodlightProvider service not found!");
128 return;
129 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000130 Map<Long, IOFSwitch> mySwitches =
131 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700132 LinkedList<IFlowEntry> addFlowEntries =
133 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000134 LinkedList<IFlowEntry> deleteFlowEntries =
135 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700136
137 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700138 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700139 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700140 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700141 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000142 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700143 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700144 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700145 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000146
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000147 String dpidStr = flowEntryObj.getSwitchDpid();
148 if (dpidStr == null)
149 continue;
150 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800151 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000152 if (mySwitch == null)
153 continue; // Ignore the entry: not my switch
154
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700155 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700156 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700157 if (flowObj == null)
158 continue; // Should NOT happen
159 if (flowObj.getFlowId() == null)
160 continue; // Invalid entry
161
162 //
163 // NOTE: For now we process the DELETE before the ADD
164 // to cover the more common scenario.
165 // TODO: This is error prone and needs to be fixed!
166 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000167 String userState = flowEntryObj.getUserState();
168 if (userState == null)
169 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700170 if (userState.equals("FE_USER_DELETE")) {
171 // An entry that needs to be deleted.
172 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700173 installFlowEntry(mySwitch, flowObj, flowEntryObj);
174 } else {
175 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700176 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700177 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700178 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700179 // TODO: Commented-out for now
180 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700181 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700182 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700183 processed_measurement_flow = true;
184 }
185 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700186 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700187 }
188
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700189 //
190 // Process the Flow Entries that need to be added
191 //
192 for (IFlowEntry flowEntryObj : addFlowEntries) {
193 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700194 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700195 if (flowObj == null)
196 continue; // Should NOT happen
197 if (flowObj.getFlowId() == null)
198 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700199
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700200 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700201 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000202 if (mySwitch == null)
203 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700204 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800205 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000206
207 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000208 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700209 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000210 //
211 // TODO: We should use the OpenFlow Barrier mechanism
212 // to check for errors, and delete the Flow Entries after the
213 // Barrier message is received.
214 //
215 while (! deleteFlowEntries.isEmpty()) {
216 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
217 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700218 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000219 if (flowObj == null) {
220 log.debug("Did not find FlowPath to be deleted");
221 continue;
222 }
223 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700224 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000225 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700226
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700227 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700228
229 if (processed_measurement_flow) {
230 long estimatedTime =
231 System.nanoTime() - modifiedMeasurementFlowTime;
232 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
233 (double)estimatedTime / 1000000000 + " sec";
234 log.debug(logMsg);
235 }
236
237 long estimatedTime = System.nanoTime() - startTime;
238 double rate = 0.0;
239 if (estimatedTime > 0)
240 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
241 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
242 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
243 counterMyNotUpdatedFlowEntries + " in " +
244 (double)estimatedTime / 1000000000 + " sec: " +
245 rate + " paths/s";
246 log.debug(logMsg);
247 }
248 };
249
250 final Runnable shortestPathReconcile = new Runnable() {
251 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700252 try {
253 runImpl();
254 } catch (Exception e) {
255 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700256 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700257 return;
258 }
259 }
260
261 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700262 long startTime = System.nanoTime();
263 int counterAllFlowPaths = 0;
264 int counterMyFlowPaths = 0;
265
266 if (floodlightProvider == null) {
267 log.debug("FloodlightProvider service not found!");
268 return;
269 }
270 Map<Long, IOFSwitch> mySwitches =
271 floodlightProvider.getSwitches();
272 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
273
274 boolean processed_measurement_flow = false;
275
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700276 //
277 // Fetch and recompute the Shortest Path for those
278 // Flow Paths this controller is responsible for.
279 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000280 Map<Long, ?> shortestPathTopo =
281 topoRouteService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700282 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700283 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700284 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700285 if (flowPathObj == null)
286 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700287
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700288 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000289 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700290 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700291 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700292 //
293 // Use the source DPID as a heuristic to decide
294 // which controller is responsible for maintaining the
295 // shortest path.
296 // NOTE: This heuristic is error-prone: if the switch
297 // goes away and no controller is responsible for that
298 // switch, then the original Flow Path is not cleaned-up
299 //
300 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
301 if (mySwitch == null)
302 continue; // Ignore: not my responsibility
303
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700304 // Test the Data Path Summary string
305 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
306 if (dataPathSummaryStr == null)
307 continue; // Could be invalid entry?
308 if (dataPathSummaryStr.isEmpty())
309 continue; // No need to maintain this flow
310
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000311 //
312 // Test whether we need to complete the Flow cleanup,
313 // if the Flow has been deleted by the user.
314 //
315 String flowUserState = flowPathObj.getUserState();
316 if ((flowUserState != null)
317 && flowUserState.equals("FE_USER_DELETE")) {
318 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
319 boolean empty = true; // TODO: an ugly hack
320 for (IFlowEntry flowEntryObj : flowEntries) {
321 empty = false;
322 break;
323 }
324 if (empty)
325 deleteFlows.add(flowPathObj);
326 }
327
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000328 // Fetch the fields needed to recompute the shortest path
329 Short srcPortShort = flowPathObj.getSrcPort();
330 String dstDpidStr = flowPathObj.getDstSwitch();
331 Short dstPortShort = flowPathObj.getDstPort();
332 if ((srcPortShort == null) ||
333 (dstDpidStr == null) ||
334 (dstPortShort == null)) {
335 continue;
336 }
337
338 Port srcPort = new Port(srcPortShort);
339 Dpid dstDpid = new Dpid(dstDpidStr);
340 Port dstPort = new Port(dstPortShort);
341 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
342 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
343
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700344 counterMyFlowPaths++;
345
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700346 //
347 // NOTE: Using here the regular getShortestPath() method
348 // won't work here, because that method calls internally
349 // "conn.endTx(Transaction.COMMIT)", and that will
350 // invalidate all handlers to the Titan database.
351 // If we want to experiment with calling here
352 // getShortestPath(), we need to refactor that code
353 // to avoid closing the transaction.
354 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700355 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000356 topoRouteService.getTopoShortestPath(shortestPathTopo,
357 srcSwitchPort,
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700358 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000359 if (dataPath == null) {
360 // We need the DataPath to compare the paths
361 dataPath = new DataPath();
362 dataPath.setSrcPort(srcSwitchPort);
363 dataPath.setDstPort(dstSwitchPort);
364 }
365
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700366 String newDataPathSummaryStr = dataPath.dataPathSummary();
367 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
368 continue; // Nothing changed
369
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700370 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700371 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000372
373 //
374 // Delete all leftover Flows marked for deletion from the
375 // Network MAP.
376 //
377 while (! deleteFlows.isEmpty()) {
378 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700379 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000380 }
381
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000382 topoRouteService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700383
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700384 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700385
386 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700387 long estimatedTime =
388 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700389 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
390 (double)estimatedTime / 1000000000 + " sec";
391 log.debug(logMsg);
392 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700393
394 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700395 double rate = 0.0;
396 if (estimatedTime > 0)
397 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700398 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700399 counterAllFlowPaths + " MyFlowPaths: " +
400 counterMyFlowPaths + " in " +
401 (double)estimatedTime / 1000000000 + " sec: " +
402 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700403 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800404 }
405 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700406
Jonathan Hart50a94982013-04-10 14:49:51 -0700407 //final ScheduledFuture<?> mapReaderHandle =
408 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800409
Jonathan Hart50a94982013-04-10 14:49:51 -0700410 //final ScheduledFuture<?> shortestPathReconcileHandle =
411 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700412
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800413 @Override
414 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700415 op = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800416 }
417
418 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700419 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800420 }
421
422 @Override
423 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700424 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800425 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800426
427 @Override
428 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
429 Collection<Class<? extends IFloodlightService>> l =
430 new ArrayList<Class<? extends IFloodlightService>>();
431 l.add(IFlowService.class);
432 return l;
433 }
434
435 @Override
436 public Map<Class<? extends IFloodlightService>, IFloodlightService>
437 getServiceImpls() {
438 Map<Class<? extends IFloodlightService>,
439 IFloodlightService> m =
440 new HashMap<Class<? extends IFloodlightService>,
441 IFloodlightService>();
442 m.put(IFlowService.class, this);
443 return m;
444 }
445
446 @Override
447 public Collection<Class<? extends IFloodlightService>>
448 getModuleDependencies() {
449 Collection<Class<? extends IFloodlightService>> l =
450 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800451 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700452 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800453 l.add(IRestApiService.class);
454 return l;
455 }
456
457 @Override
458 public void init(FloodlightModuleContext context)
459 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700460 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800461 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700462 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800463 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800464 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
465 EnumSet.of(OFType.FLOW_MOD),
466 OFMESSAGE_DAMPER_TIMEOUT);
467 // TODO: An ugly hack!
468 String conf = "/tmp/cassandra.titan";
469 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700470
471 mapReaderScheduler = Executors.newScheduledThreadPool(1);
472 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800473 }
474
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700475 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000476 //
477 // Generate the next Flow Entry ID.
478 // NOTE: For now, the higher 32 bits are random, and
479 // the lower 32 bits are sequential.
480 // In the future, we need a better allocation mechanism.
481 //
482 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
483 nextFlowEntryIdPrefix = randomGenerator.nextInt();
484 nextFlowEntryIdSuffix = 0;
485 } else {
486 nextFlowEntryIdSuffix++;
487 }
488 long result = (long)nextFlowEntryIdPrefix << 32;
489 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
490 return result;
491 }
492
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800493 @Override
494 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700495 restApi.addRestletRoutable(new FlowWebRoutable());
496
497 // Initialize the Flow Entry ID generator
498 nextFlowEntryIdPrefix = randomGenerator.nextInt();
499
500 mapReaderScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200501 mapReader, 3, 3, TimeUnit.SECONDS);
Jonathan Hart50a94982013-04-10 14:49:51 -0700502 shortestPathReconcileScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200503 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800504 }
505
506 /**
507 * Add a flow.
508 *
509 * Internally, ONOS will automatically register the installer for
510 * receiving Flow Path Notifications for that path.
511 *
512 * @param flowPath the Flow Path to install.
513 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700514 * @param dataPathSummaryStr the data path summary string if the added
515 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800516 * @return true on success, otherwise false.
517 */
518 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700519 public boolean addFlow(FlowPath flowPath, FlowId flowId,
520 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700521 /*
522 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700523 if (flowPath.flowId().value() == measurementFlowId) {
524 modifiedMeasurementFlowTime = System.nanoTime();
525 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700526 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800527
528 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000529 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800530 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700531 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800532 != null) {
533 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
534 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000535 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800536 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700537 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800538 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
539 flowPath.flowId().toString());
540 }
541 } catch (Exception e) {
542 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700543 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000544
545 StringWriter sw = new StringWriter();
546 e.printStackTrace(new PrintWriter(sw));
547 String stacktrace = sw.toString();
548
549 log.error(":addFlow FlowId:{} failed: {}",
550 flowPath.flowId().toString(),
551 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800552 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700553 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000554 log.error(":addFlow FlowId:{} failed: Flow object not created",
555 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700556 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800557 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700558 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800559
560 //
561 // Set the Flow key:
562 // - flowId
563 //
564 flowObj.setFlowId(flowPath.flowId().toString());
565 flowObj.setType("flow");
566
567 //
568 // Set the Flow attributes:
569 // - flowPath.installerId()
570 // - flowPath.dataPath().srcPort()
571 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700572 // - flowPath.matchEthernetFrameType()
573 // - flowPath.matchSrcIPv4Net()
574 // - flowPath.matchDstIPv4Net()
575 // - flowPath.matchSrcMac()
576 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800577 //
578 flowObj.setInstallerId(flowPath.installerId().toString());
579 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
580 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
581 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
582 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700583 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
584 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
585 }
586 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
587 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
588 }
589 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
590 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
591 }
592 if (flowPath.flowEntryMatch().matchSrcMac()) {
593 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
594 }
595 if (flowPath.flowEntryMatch().matchDstMac()) {
596 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
597 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800598
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700599 if (dataPathSummaryStr != null) {
600 flowObj.setDataPathSummary(dataPathSummaryStr);
601 } else {
602 flowObj.setDataPathSummary("");
603 }
604
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000605 if (found)
606 flowObj.setUserState("FE_USER_MODIFY");
607 else
608 flowObj.setUserState("FE_USER_ADD");
609
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800610 // Flow edges:
611 // HeadFE
612
613
614 //
615 // Flow Entries:
616 // flowPath.dataPath().flowEntries()
617 //
618 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700619 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700620 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800621 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700622 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800623 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700624 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800625
626 //
627 // TODO: We need a proper Flow ID allocation mechanism.
628 //
629 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700630
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800631 return true;
632 }
633
634 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700635 * Add a flow entry to the Network MAP.
636 *
637 * @param flowObj the corresponding Flow Path object for the Flow Entry.
638 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700639 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700640 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700641 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700642 // Flow edges
643 // HeadFE (TODO)
644
645 //
646 // Assign the FlowEntry ID.
647 //
648 if ((flowEntry.flowEntryId() == null) ||
649 (flowEntry.flowEntryId().value() == 0)) {
650 long id = getNextFlowEntryId();
651 flowEntry.setFlowEntryId(new FlowEntryId(id));
652 }
653
654 IFlowEntry flowEntryObj = null;
655 boolean found = false;
656 try {
657 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700658 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700659 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
660 flowEntry.flowEntryId().toString());
661 found = true;
662 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700663 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700664 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
665 flowEntry.flowEntryId().toString());
666 }
667 } catch (Exception e) {
668 log.error(":addFlow FlowEntryId:{} failed",
669 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700670 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700671 }
672 if (flowEntryObj == null) {
673 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
674 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700675 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700676 }
677
678 //
679 // Set the Flow Entry key:
680 // - flowEntry.flowEntryId()
681 //
682 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
683 flowEntryObj.setType("flow_entry");
684
685 //
686 // Set the Flow Entry Edges and attributes:
687 // - Switch edge
688 // - InPort edge
689 // - OutPort edge
690 //
691 // - flowEntry.flowEntryMatch()
692 // - flowEntry.flowEntryActions()
693 // - flowEntry.dpid()
694 // - flowEntry.flowEntryUserState()
695 // - flowEntry.flowEntrySwitchState()
696 // - flowEntry.flowEntryErrorState()
697 // - flowEntry.matchInPort()
698 // - flowEntry.matchEthernetFrameType()
699 // - flowEntry.matchSrcIPv4Net()
700 // - flowEntry.matchDstIPv4Net()
701 // - flowEntry.matchSrcMac()
702 // - flowEntry.matchDstMac()
703 // - flowEntry.actionOutput()
704 //
705 ISwitchObject sw =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700706 op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700707 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
708 flowEntryObj.setSwitch(sw);
709 if (flowEntry.flowEntryMatch().matchInPort()) {
710 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700711 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700712 flowEntry.flowEntryMatch().inPort().value());
713 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
714 flowEntryObj.setInPort(inport);
715 }
716 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
717 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
718 }
719 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
720 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
721 }
722 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
723 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
724 }
725 if (flowEntry.flowEntryMatch().matchSrcMac()) {
726 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
727 }
728 if (flowEntry.flowEntryMatch().matchDstMac()) {
729 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
730 }
731
732 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
733 if (fa.actionOutput() != null) {
734 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700735 op.searchPort(flowEntry.dpid().toString(),
736 fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700737 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
738 flowEntryObj.setOutPort(outport);
739 }
740 }
741 // TODO: Hacks with hard-coded state names!
742 if (found)
743 flowEntryObj.setUserState("FE_USER_MODIFY");
744 else
745 flowEntryObj.setUserState("FE_USER_ADD");
746 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
747 //
748 // TODO: Take care of the FlowEntryErrorState.
749 //
750
751 // Flow Entries edges:
752 // Flow
753 // NextFE (TODO)
754 if (! found) {
755 flowObj.addFlowEntry(flowEntryObj);
756 flowEntryObj.setFlow(flowObj);
757 }
758
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700759 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700760 }
761
762 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000763 * Delete all previously added flows.
764 *
765 * @return true on success, otherwise false.
766 */
767 @Override
768 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000769 List<Thread> threads = new LinkedList<Thread>();
770 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
771 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000772
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000773 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700774 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000775 for (IFlowPath flowPathObj : allFlowPaths) {
776 if (flowPathObj == null)
777 continue;
778 String flowIdStr = flowPathObj.getFlowId();
779 if (flowIdStr == null)
780 continue;
781 FlowId flowId = new FlowId(flowIdStr);
782 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000783 }
784
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000785 // Delete all flows one-by-one
786 for (FlowId flowId : concurrentAllFlowIds)
787 deleteFlow(flowId);
788
789 /*
790 * TODO: A faster mechanism to delete the Flow Paths by using
791 * a number of threads. Commented-out for now.
792 */
793 /*
794 //
795 // Create the threads to delete the Flow Paths
796 //
797 for (int i = 0; i < 10; i++) {
798 Thread thread = new Thread(new Runnable() {
799 @Override
800 public void run() {
801 while (true) {
802 FlowId flowId = concurrentAllFlowIds.poll();
803 if (flowId == null)
804 return;
805 deleteFlow(flowId);
806 }
807 }}, "Delete All Flow Paths");
808 threads.add(thread);
809 }
810
811 // Start processing
812 for (Thread thread : threads) {
813 thread.start();
814 }
815
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000816 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000817 for (Thread thread : threads) {
818 try {
819 thread.join();
820 } catch (InterruptedException e) {
821 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
822 }
823 }
824 */
825
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000826 return true;
827 }
828
829 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800830 * Delete a previously added flow.
831 *
832 * @param flowId the Flow ID of the flow to delete.
833 * @return true on success, otherwise false.
834 */
835 @Override
836 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700837 /*
838 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700839 if (flowId.value() == measurementFlowId) {
840 modifiedMeasurementFlowTime = System.nanoTime();
841 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700842 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700843
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800844 IFlowPath flowObj = null;
845 //
846 // We just mark the entries for deletion,
847 // and let the switches remove each individual entry after
848 // it has been removed from the switches.
849 //
850 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700851 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800852 != null) {
853 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
854 flowId.toString());
855 } else {
856 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
857 flowId.toString());
858 }
859 } catch (Exception e) {
860 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700861 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800862 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
863 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700864 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700865 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800866 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700867 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800868
869 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000870 // Find and mark for deletion all Flow Entries,
871 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800872 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000873 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800874 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
875 boolean empty = true; // TODO: an ugly hack
876 for (IFlowEntry flowEntryObj : flowEntries) {
877 empty = false;
878 // flowObj.removeFlowEntry(flowEntryObj);
879 // conn.utils().removeFlowEntry(conn, flowEntryObj);
880 flowEntryObj.setUserState("FE_USER_DELETE");
881 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
882 }
883 // Remove from the database empty flows
884 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700885 op.removeFlowPath(flowObj);
886 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800887
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800888 return true;
889 }
890
891 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000892 * Clear the state for all previously added flows.
893 *
894 * @return true on success, otherwise false.
895 */
896 @Override
897 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000898 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000899
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000900 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700901 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000902 for (IFlowPath flowPathObj : allFlowPaths) {
903 if (flowPathObj == null)
904 continue;
905 String flowIdStr = flowPathObj.getFlowId();
906 if (flowIdStr == null)
907 continue;
908 FlowId flowId = new FlowId(flowIdStr);
909 allFlowIds.add(flowId);
910 }
911
912 // Clear all flows one-by-one
913 for (FlowId flowId : allFlowIds) {
914 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000915 }
916
917 return true;
918 }
919
920 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700921 * Clear the state for a previously added flow.
922 *
923 * @param flowId the Flow ID of the flow to clear.
924 * @return true on success, otherwise false.
925 */
926 @Override
927 public boolean clearFlow(FlowId flowId) {
928 IFlowPath flowObj = null;
929 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700930 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700931 != null) {
932 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
933 flowId.toString());
934 } else {
935 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
936 flowId.toString());
937 }
938 } catch (Exception e) {
939 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700940 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700941 log.error(":clearFlow FlowId:{} failed", flowId.toString());
942 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700943 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700944 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700945 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700946 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700947
948 //
949 // Remove all Flow Entries
950 //
951 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
952 for (IFlowEntry flowEntryObj : flowEntries) {
953 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700954 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700955 }
956 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700957 op.removeFlowPath(flowObj);
958 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700959
960 return true;
961 }
962
963 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800964 * Get a previously added flow.
965 *
966 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800967 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800968 */
969 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800970 public FlowPath getFlow(FlowId flowId) {
971 IFlowPath flowObj = null;
972 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700973 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800974 != null) {
975 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
976 flowId.toString());
977 } else {
978 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
979 flowId.toString());
980 }
981 } catch (Exception e) {
982 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700983 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800984 log.error(":getFlow FlowId:{} failed", flowId.toString());
985 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700986 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700987 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800988 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700989 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800990
991 //
992 // Extract the Flow state
993 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800994 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700995 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800996
997 return flowPath;
998 }
999
1000 /**
1001 * Get all previously added flows by a specific installer for a given
1002 * data path endpoints.
1003 *
1004 * @param installerId the Caller ID of the installer of the flow to get.
1005 * @param dataPathEndpoints the data path endpoints of the flow to get.
1006 * @return the Flow Paths if found, otherwise null.
1007 */
1008 @Override
1009 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1010 DataPathEndpoints dataPathEndpoints) {
1011 //
1012 // TODO: The implementation below is not optimal:
1013 // We fetch all flows, and then return only the subset that match
1014 // the query conditions.
1015 // We should use the appropriate Titan/Gremlin query to filter-out
1016 // the flows as appropriate.
1017 //
1018 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001019 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001020
1021 if (allFlows == null) {
1022 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001023 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001024 }
1025
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001026 for (FlowPath flow : allFlows) {
1027 //
1028 // TODO: String-based comparison is sub-optimal.
1029 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001030 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001031 //
1032 if (! flow.installerId().toString().equals(installerId.toString()))
1033 continue;
1034 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1035 continue;
1036 }
1037 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1038 continue;
1039 }
1040 flowPaths.add(flow);
1041 }
1042
1043 if (flowPaths.isEmpty()) {
1044 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001045 } else {
1046 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1047 }
1048
1049 return flowPaths;
1050 }
1051
1052 /**
1053 * Get all installed flows by all installers for given data path endpoints.
1054 *
1055 * @param dataPathEndpoints the data path endpoints of the flows to get.
1056 * @return the Flow Paths if found, otherwise null.
1057 */
1058 @Override
1059 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1060 //
1061 // TODO: The implementation below is not optimal:
1062 // We fetch all flows, and then return only the subset that match
1063 // the query conditions.
1064 // We should use the appropriate Titan/Gremlin query to filter-out
1065 // the flows as appropriate.
1066 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001067 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1068 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001069
1070 if (allFlows == null) {
1071 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001072 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001073 }
1074
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001075 for (FlowPath flow : allFlows) {
1076 //
1077 // TODO: String-based comparison is sub-optimal.
1078 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001079 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001080 //
1081 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1082 continue;
1083 }
1084 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1085 continue;
1086 }
1087 flowPaths.add(flow);
1088 }
1089
1090 if (flowPaths.isEmpty()) {
1091 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001092 } else {
1093 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1094 }
1095
1096 return flowPaths;
1097 }
1098
1099 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001100 * Get summary of all installed flows by all installers in a given range
1101 *
1102 * @param flowId the data path endpoints of the flows to get.
1103 * @param maxFlows: the maximum number of flows to be returned
1104 * @return the Flow Paths if found, otherwise null.
1105 */
1106 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001107 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001108
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001109 // TODO: The implementation below is not optimal:
1110 // We fetch all flows, and then return only the subset that match
1111 // the query conditions.
1112 // We should use the appropriate Titan/Gremlin query to filter-out
1113 // the flows as appropriate.
1114 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001115 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001116
Jonathan Hart01f2d272013-04-04 20:03:46 -07001117 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1118
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001119 Collections.sort(flowPathsWithoutFlowEntries,
1120 new Comparator<IFlowPath>(){
1121 @Override
1122 public int compare(IFlowPath first, IFlowPath second) {
1123 // TODO Auto-generated method stub
1124 long result = new FlowId(first.getFlowId()).value()
1125 - new FlowId(second.getFlowId()).value();
1126 if (result > 0) return 1;
1127 else if (result < 0) return -1;
1128 else return 0;
1129 }
1130 }
1131 );
1132
Jonathan Hart01f2d272013-04-04 20:03:46 -07001133 return flowPathsWithoutFlowEntries;
1134
1135 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001136 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001137
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001138 if (allFlows == null) {
1139 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001140 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001141 }
1142
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001143 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001144
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001145 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001146 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001147
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001148 // start from desired flowId
1149 if (flow.flowId().value() < flowId.value()) {
1150 continue;
1151 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001152
1153 // Summarize by making null flow entry fields that are not relevant to report
1154 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1155 flowEntry.setFlowEntryActions(null);
1156 flowEntry.setFlowEntryMatch(null);
1157 }
1158
1159 flowPaths.add(flow);
1160 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1161 break;
1162 }
1163 }
1164
1165 if (flowPaths.isEmpty()) {
1166 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001167 } else {
1168 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1169 }
1170
1171 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001172 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001173 }
1174
1175 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001176 * Get all installed flows by all installers.
1177 *
1178 * @return the Flow Paths if found, otherwise null.
1179 */
1180 @Override
1181 public ArrayList<FlowPath> getAllFlows() {
1182 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001183 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001184
1185 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001186 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001187 log.debug("Get all FlowPaths: found FlowPaths");
1188 } else {
1189 log.debug("Get all FlowPaths: no FlowPaths found");
1190 }
1191 } catch (Exception e) {
1192 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001193 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001194 log.error(":getAllFlowPaths failed");
1195 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001196 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001197 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001198 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001199 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001200
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001201 for (IFlowPath flowObj : flowPathsObj) {
1202 //
1203 // Extract the Flow state
1204 //
1205 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001206 if (flowPath != null)
1207 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001208 }
1209
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001210 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001211
1212 return flowPaths;
1213 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001214
1215 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1216 Iterable<IFlowPath> flowPathsObj = null;
1217 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1218 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1219
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001220 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001221
Jonathan Hart01f2d272013-04-04 20:03:46 -07001222 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001223 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001224 log.debug("Get all FlowPaths: found FlowPaths");
1225 } else {
1226 log.debug("Get all FlowPaths: no FlowPaths found");
1227 }
1228 } catch (Exception e) {
1229 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001230 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001231 log.error(":getAllFlowPaths failed");
1232 }
1233 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1234 return new ArrayList<IFlowPath>(); // No Flows found
1235 }
1236
1237 for (IFlowPath flowObj : flowPathsObj){
1238 flowPathsObjArray.add(flowObj);
1239 }
1240 /*
1241 for (IFlowPath flowObj : flowPathsObj) {
1242 //
1243 // Extract the Flow state
1244 //
1245 FlowPath flowPath = extractFlowPath(flowObj);
1246 if (flowPath != null)
1247 flowPaths.add(flowPath);
1248 }
1249 */
1250
1251 //conn.endTx(Transaction.COMMIT);
1252
1253 return flowPathsObjArray;
1254 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001255
1256 /**
1257 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1258 *
1259 * @param flowObj the object to extract the Flow Path State from.
1260 * @return the extracted Flow Path State.
1261 */
1262 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001263 //
1264 // Extract the Flow state
1265 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001266 String flowIdStr = flowObj.getFlowId();
1267 String installerIdStr = flowObj.getInstallerId();
1268 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001269 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001270 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001271 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001272
1273 if ((flowIdStr == null) ||
1274 (installerIdStr == null) ||
1275 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001276 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001277 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001278 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001279 // TODO: A work-around, becauuse of some bogus database objects
1280 return null;
1281 }
1282
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001283 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001284 flowPath.setFlowId(new FlowId(flowIdStr));
1285 flowPath.setInstallerId(new CallerId(installerIdStr));
1286 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001287 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001288 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001289 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001290 //
1291 // Extract the match conditions common for all Flow Entries
1292 //
1293 {
1294 FlowEntryMatch match = new FlowEntryMatch();
1295 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1296 if (matchEthernetFrameType != null)
1297 match.enableEthernetFrameType(matchEthernetFrameType);
1298 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1299 if (matchSrcIPv4Net != null)
1300 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1301 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1302 if (matchDstIPv4Net != null)
1303 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1304 String matchSrcMac = flowObj.getMatchSrcMac();
1305 if (matchSrcMac != null)
1306 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1307 String matchDstMac = flowObj.getMatchDstMac();
1308 if (matchDstMac != null)
1309 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1310 flowPath.setFlowEntryMatch(match);
1311 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001312
1313 //
1314 // Extract all Flow Entries
1315 //
1316 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1317 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001318 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1319 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001320 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001321 flowPath.dataPath().flowEntries().add(flowEntry);
1322 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001323
1324 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001325 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001326
1327 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001328 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1329 *
1330 * @param flowEntryObj the object to extract the Flow Entry State from.
1331 * @return the extracted Flow Entry State.
1332 */
1333 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1334 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1335 String switchDpidStr = flowEntryObj.getSwitchDpid();
1336 String userState = flowEntryObj.getUserState();
1337 String switchState = flowEntryObj.getSwitchState();
1338
1339 if ((flowEntryIdStr == null) ||
1340 (switchDpidStr == null) ||
1341 (userState == null) ||
1342 (switchState == null)) {
1343 // TODO: A work-around, becauuse of some bogus database objects
1344 return null;
1345 }
1346
1347 FlowEntry flowEntry = new FlowEntry();
1348 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1349 flowEntry.setDpid(new Dpid(switchDpidStr));
1350
1351 //
1352 // Extract the match conditions
1353 //
1354 FlowEntryMatch match = new FlowEntryMatch();
1355 Short matchInPort = flowEntryObj.getMatchInPort();
1356 if (matchInPort != null)
1357 match.enableInPort(new Port(matchInPort));
1358 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1359 if (matchEthernetFrameType != null)
1360 match.enableEthernetFrameType(matchEthernetFrameType);
1361 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1362 if (matchSrcIPv4Net != null)
1363 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1364 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1365 if (matchDstIPv4Net != null)
1366 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1367 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1368 if (matchSrcMac != null)
1369 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1370 String matchDstMac = flowEntryObj.getMatchDstMac();
1371 if (matchDstMac != null)
1372 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1373 flowEntry.setFlowEntryMatch(match);
1374
1375 //
1376 // Extract the actions
1377 //
1378 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1379 Short actionOutputPort = flowEntryObj.getActionOutput();
1380 if (actionOutputPort != null) {
1381 FlowEntryAction action = new FlowEntryAction();
1382 action.setActionOutput(new Port(actionOutputPort));
1383 actions.add(action);
1384 }
1385 flowEntry.setFlowEntryActions(actions);
1386 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1387 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1388 //
1389 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1390 // and FlowEntryErrorState.
1391 //
1392 return flowEntry;
1393 }
1394
1395 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001396 * Add and maintain a shortest-path flow.
1397 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001398 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001399 *
1400 * @param flowPath the Flow Path with the endpoints and the match
1401 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001402 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001403 */
1404 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001405 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001406 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001407 // Don't do the shortest path computation here.
1408 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001409 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001410
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001411 // We need the DataPath to populate the Network MAP
1412 DataPath dataPath = new DataPath();
1413 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1414 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001415
1416 //
1417 // Prepare the computed Flow Path
1418 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001419 FlowPath computedFlowPath = new FlowPath();
1420 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1421 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1422 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001423 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001424
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001425 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001426 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001427 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001428 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001429
1430 // TODO: Mark the flow for maintenance purpose
1431
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001432 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001433 }
1434
1435 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001436 * Reconcile a flow.
1437 *
1438 * @param flowObj the flow that needs to be reconciliated.
1439 * @param newDataPath the new data path to use.
1440 * @return true on success, otherwise false.
1441 */
1442 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1443 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1444
1445 //
1446 // Set the incoming port matching and the outgoing port output
1447 // actions for each flow entry.
1448 //
1449 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1450 // Set the incoming port matching
1451 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1452 flowEntry.setFlowEntryMatch(flowEntryMatch);
1453 flowEntryMatch.enableInPort(flowEntry.inPort());
1454
1455 // Set the outgoing port output action
1456 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1457 if (flowEntryActions == null) {
1458 flowEntryActions = new ArrayList<FlowEntryAction>();
1459 flowEntry.setFlowEntryActions(flowEntryActions);
1460 }
1461 FlowEntryAction flowEntryAction = new FlowEntryAction();
1462 flowEntryAction.setActionOutput(flowEntry.outPort());
1463 flowEntryActions.add(flowEntryAction);
1464 }
1465
1466 //
1467 // Remove the old Flow Entries, and add the new Flow Entries
1468 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001469 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1470 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1471 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001472 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001473 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001474 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001475 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001476 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001477 }
1478
1479 //
1480 // Set the Data Path Summary
1481 //
1482 String dataPathSummaryStr = newDataPath.dataPathSummary();
1483 flowObj.setDataPathSummary(dataPathSummaryStr);
1484
1485 return true;
1486 }
1487
1488 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001489 * Reconcile all flows in a set.
1490 *
1491 * @param flowObjSet the set of flows that need to be reconciliated.
1492 */
1493 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1494 if (! flowObjSet.iterator().hasNext())
1495 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001496 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001497 }
1498
1499 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001500 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001501 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001502 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001503 * @param flowObj the flow path object for the flow entry to install.
1504 * @param flowEntryObj the flow entry object to install.
1505 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001506 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001507 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1508 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001509 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1510 if (flowEntryIdStr == null)
1511 return false;
1512 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001513 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001514 if (userState == null)
1515 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001516
1517 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001518 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001519 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001520 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1521 .getMessage(OFType.FLOW_MOD);
1522 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001523
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001524 short flowModCommand = OFFlowMod.OFPFC_ADD;
1525 if (userState.equals("FE_USER_ADD")) {
1526 flowModCommand = OFFlowMod.OFPFC_ADD;
1527 } else if (userState.equals("FE_USER_MODIFY")) {
1528 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1529 } else if (userState.equals("FE_USER_DELETE")) {
1530 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1531 } else {
1532 // Unknown user state. Ignore the entry
1533 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1534 flowEntryId.toString(), userState);
1535 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001536 }
1537
1538 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001539 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001540 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001541 // NOTE: The Flow matching conditions common for all Flow Entries are
1542 // used ONLY if a Flow Entry does NOT have the corresponding matching
1543 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001544 //
1545 OFMatch match = new OFMatch();
1546 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001547
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001548 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001549 Short matchInPort = flowEntryObj.getMatchInPort();
1550 if (matchInPort != null) {
1551 match.setInputPort(matchInPort);
1552 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1553 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001554
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001555 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001556 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1557 if (matchEthernetFrameType == null)
1558 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1559 if (matchEthernetFrameType != null) {
1560 match.setDataLayerType(matchEthernetFrameType);
1561 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1562 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001563
1564 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001565 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1566 if (matchSrcIPv4Net == null)
1567 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1568 if (matchSrcIPv4Net != null) {
1569 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1570 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001571
1572 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001573 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1574 if (matchDstIPv4Net == null)
1575 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1576 if (matchDstIPv4Net != null) {
1577 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1578 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001579
1580 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001581 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1582 if (matchSrcMac == null)
1583 matchSrcMac = flowObj.getMatchSrcMac();
1584 if (matchSrcMac != null) {
1585 match.setDataLayerSource(matchSrcMac);
1586 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1587 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001588
1589 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001590 String matchDstMac = flowEntryObj.getMatchDstMac();
1591 if (matchDstMac == null)
1592 matchDstMac = flowObj.getMatchDstMac();
1593 if (matchDstMac != null) {
1594 match.setDataLayerDestination(matchDstMac);
1595 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1596 }
1597
1598 //
1599 // Fetch the actions
1600 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001601 // TODO: For now we support only the "OUTPUT" actions.
1602 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001603 List<OFAction> actions = new ArrayList<OFAction>();
1604 Short actionOutputPort = flowEntryObj.getActionOutput();
1605 if (actionOutputPort != null) {
1606 OFActionOutput action = new OFActionOutput();
1607 // XXX: The max length is hard-coded for now
1608 action.setMaxLength((short)0xffff);
1609 action.setPort(actionOutputPort);
1610 actions.add(action);
1611 }
1612
1613 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1614 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1615 .setPriority(PRIORITY_DEFAULT)
1616 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1617 .setCookie(cookie)
1618 .setCommand(flowModCommand)
1619 .setMatch(match)
1620 .setActions(actions)
1621 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1622 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1623 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1624 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1625 if (actionOutputPort != null)
1626 fm.setOutPort(actionOutputPort);
1627 }
1628
1629 //
1630 // TODO: Set the following flag
1631 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1632 // See method ForwardingBase::pushRoute()
1633 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001634
1635 //
1636 // Write the message to the switch
1637 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001638 log.debug("MEASUREMENT: Installing flow entry " + userState +
1639 " into switch DPID: " +
1640 mySwitch.getStringId() +
1641 " flowEntryId: " + flowEntryId.toString() +
1642 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1643 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1644 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001645 try {
1646 messageDamper.write(mySwitch, fm, null);
1647 mySwitch.flush();
1648 //
1649 // TODO: We should use the OpenFlow Barrier mechanism
1650 // to check for errors, and update the SwitchState
1651 // for a flow entry after the Barrier message is
1652 // is received.
1653 //
1654 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1655 } catch (IOException e) {
1656 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001657 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001658 }
1659
1660 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001661 }
1662
1663 /**
1664 * Install a Flow Entry on a switch.
1665 *
1666 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001667 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001668 * @param flowEntry the flow entry to install.
1669 * @return true on success, otherwise false.
1670 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001671 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1672 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001673 //
1674 // Create the OpenFlow Flow Modification Entry to push
1675 //
1676 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1677 .getMessage(OFType.FLOW_MOD);
1678 long cookie = flowEntry.flowEntryId().value();
1679
1680 short flowModCommand = OFFlowMod.OFPFC_ADD;
1681 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1682 flowModCommand = OFFlowMod.OFPFC_ADD;
1683 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1684 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1685 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1686 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1687 } else {
1688 // Unknown user state. Ignore the entry
1689 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1690 flowEntry.flowEntryId().toString(),
1691 flowEntry.flowEntryUserState());
1692 return false;
1693 }
1694
1695 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001696 // Fetch the match conditions.
1697 //
1698 // NOTE: The Flow matching conditions common for all Flow Entries are
1699 // used ONLY if a Flow Entry does NOT have the corresponding matching
1700 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001701 //
1702 OFMatch match = new OFMatch();
1703 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001704 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1705 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1706
1707 // Match the Incoming Port
1708 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001709 if (matchInPort != null) {
1710 match.setInputPort(matchInPort.value());
1711 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1712 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001713
1714 // Match the Ethernet Frame Type
1715 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1716 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1717 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1718 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001719 if (matchEthernetFrameType != null) {
1720 match.setDataLayerType(matchEthernetFrameType);
1721 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1722 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001723
1724 // Match the Source IPv4 Network prefix
1725 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1726 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1727 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1728 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001729 if (matchSrcIPv4Net != null) {
1730 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1731 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001732
1733 // Natch the Destination IPv4 Network prefix
1734 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1735 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1736 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1737 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001738 if (matchDstIPv4Net != null) {
1739 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1740 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001741
1742 // Match the Source MAC address
1743 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1744 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1745 matchSrcMac = flowPathMatch.srcMac();
1746 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001747 if (matchSrcMac != null) {
1748 match.setDataLayerSource(matchSrcMac.toString());
1749 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1750 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001751
1752 // Match the Destination MAC address
1753 MACAddress matchDstMac = flowEntryMatch.dstMac();
1754 if ((matchDstMac == null) && (flowPathMatch != null)) {
1755 matchDstMac = flowPathMatch.dstMac();
1756 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001757 if (matchDstMac != null) {
1758 match.setDataLayerDestination(matchDstMac.toString());
1759 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1760 }
1761
1762 //
1763 // Fetch the actions
1764 //
1765 // TODO: For now we support only the "OUTPUT" actions.
1766 //
1767 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1768 List<OFAction> actions = new ArrayList<OFAction>();
1769 ArrayList<FlowEntryAction> flowEntryActions =
1770 flowEntry.flowEntryActions();
1771 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1772 FlowEntryAction.ActionOutput actionOutput =
1773 flowEntryAction.actionOutput();
1774 if (actionOutput != null) {
1775 short actionOutputPort = actionOutput.port().value();
1776 OFActionOutput action = new OFActionOutput();
1777 // XXX: The max length is hard-coded for now
1778 action.setMaxLength((short)0xffff);
1779 action.setPort(actionOutputPort);
1780 actions.add(action);
1781 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1782 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1783 fm.setOutPort(actionOutputPort);
1784 }
1785 }
1786 }
1787
1788 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1789 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1790 .setPriority(PRIORITY_DEFAULT)
1791 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1792 .setCookie(cookie)
1793 .setCommand(flowModCommand)
1794 .setMatch(match)
1795 .setActions(actions)
1796 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1797
1798 //
1799 // TODO: Set the following flag
1800 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1801 // See method ForwardingBase::pushRoute()
1802 //
1803
1804 //
1805 // Write the message to the switch
1806 //
1807 try {
1808 messageDamper.write(mySwitch, fm, null);
1809 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001810 //
1811 // TODO: We should use the OpenFlow Barrier mechanism
1812 // to check for errors, and update the SwitchState
1813 // for a flow entry after the Barrier message is
1814 // is received.
1815 //
1816 // TODO: The FlowEntry Object in Titan should be set
1817 // to FE_SWITCH_UPDATED.
1818 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001819 } catch (IOException e) {
1820 log.error("Failure writing flow mod from network map", e);
1821 return false;
1822 }
1823 return true;
1824 }
1825
1826 /**
1827 * Remove a Flow Entry from a switch.
1828 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001829 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001830 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001831 * @param flowEntry the flow entry to remove.
1832 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001833 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001834 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1835 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001836 //
1837 // The installFlowEntry() method implements both installation
1838 // and removal of flow entries.
1839 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001840 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001841 }
1842
1843 /**
1844 * Install a Flow Entry on a remote controller.
1845 *
1846 * TODO: We need it now: Jono
1847 * - For now it will make a REST call to the remote controller.
1848 * - Internally, it needs to know the name of the remote controller.
1849 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001850 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001851 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001852 * @return true on success, otherwise false.
1853 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001854 public boolean installRemoteFlowEntry(FlowPath flowPath,
1855 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001856 // TODO: We need it now: Jono
1857 // - For now it will make a REST call to the remote controller.
1858 // - Internally, it needs to know the name of the remote controller.
1859 return true;
1860 }
1861
1862 /**
1863 * Remove a flow entry on a remote controller.
1864 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001865 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001866 * @param flowEntry the flow entry to remove.
1867 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001868 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001869 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1870 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001871 //
1872 // The installRemoteFlowEntry() method implements both installation
1873 // and removal of flow entries.
1874 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001875 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001876 }
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001877
1878 /**
1879 * Store a path flow for measurement purpose.
1880 *
1881 * NOTE: The Flow Path argument does NOT contain flow entries.
1882 * The Shortest Path is computed, and the corresponding Flow Entries
1883 * are stored in the Flow Path.
1884 *
1885 * @param flowPath the Flow Path with the endpoints and the match
1886 * conditions to store.
1887 * @return the stored shortest-path flow on success, otherwise null.
1888 */
1889 @Override
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001890 public synchronized FlowPath measurementStorePathFlow(FlowPath flowPath) {
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001891 //
1892 // Prepare the Shortest Path computation if the first Flow Path
1893 //
1894 if (measurementStoredPaths.isEmpty())
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00001895 measurementShortestPathTopo = topoRouteService.prepareShortestPathTopo();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001896
1897 //
1898 // Compute the Shortest Path
1899 //
1900 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00001901 topoRouteService.getTopoShortestPath(measurementShortestPathTopo,
1902 flowPath.dataPath().srcPort(),
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001903 flowPath.dataPath().dstPort());
1904 if (dataPath == null) {
1905 // We need the DataPath to populate the Network MAP
1906 dataPath = new DataPath();
1907 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1908 dataPath.setDstPort(flowPath.dataPath().dstPort());
1909 }
1910
1911 //
1912 // Set the incoming port matching and the outgoing port output
1913 // actions for each flow entry.
1914 //
1915 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1916 // Set the incoming port matching
1917 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1918 flowEntry.setFlowEntryMatch(flowEntryMatch);
1919 flowEntryMatch.enableInPort(flowEntry.inPort());
1920
1921 // Set the outgoing port output action
1922 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1923 if (flowEntryActions == null) {
1924 flowEntryActions = new ArrayList<FlowEntryAction>();
1925 flowEntry.setFlowEntryActions(flowEntryActions);
1926 }
1927 FlowEntryAction flowEntryAction = new FlowEntryAction();
1928 flowEntryAction.setActionOutput(flowEntry.outPort());
1929 flowEntryActions.add(flowEntryAction);
1930 }
1931
1932 //
1933 // Prepare the computed Flow Path
1934 //
1935 FlowPath computedFlowPath = new FlowPath();
1936 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1937 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1938 computedFlowPath.setDataPath(dataPath);
1939 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
1940
1941 //
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001942 // Add the computed Flow Path to the internal storage
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001943 //
1944 measurementStoredPaths.add(computedFlowPath);
1945
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001946 log.debug("Measurement storing path {}",
1947 computedFlowPath.flowId().toString());
1948
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001949 return (computedFlowPath);
1950 }
1951
1952 /**
1953 * Install path flows for measurement purpose.
1954 *
1955 * @param numThreads the number of threads to use to install the path
1956 * flows.
1957 * @return true on success, otherwise false.
1958 */
1959 @Override
1960 public boolean measurementInstallPaths(Integer numThreads) {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001961 // Create a copy of the Flow Paths to install
1962 final ConcurrentLinkedQueue<FlowPath> measurementProcessingPaths =
1963 new ConcurrentLinkedQueue<FlowPath>(measurementStoredPaths);
1964
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00001965 /**
1966 * A Thread-wrapper class for executing the threads and collecting
1967 * the measurement data.
1968 */
1969 class MyThread extends Thread {
1970 public long[] execTime = new long[2000];
1971 public int samples = 0;
1972 public int threadId = -1;
1973 @Override
1974 public void run() {
1975 while (true) {
1976 FlowPath flowPath = measurementProcessingPaths.poll();
1977 if (flowPath == null)
1978 return;
1979 // Install the Flow Path
1980 FlowId flowId = new FlowId();
1981 String dataPathSummaryStr =
1982 flowPath.dataPath().dataPathSummary();
1983 long startTime = System.nanoTime();
1984 addFlow(flowPath, flowId, dataPathSummaryStr);
1985 long endTime = System.nanoTime();
1986 execTime[samples] = endTime - startTime;
1987 samples++;
1988 }
1989 }
1990 };
1991
1992 List<MyThread> threads = new LinkedList<MyThread>();
1993
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001994 log.debug("Measurement Installing {} flows",
1995 measurementProcessingPaths.size());
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00001996
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001997 //
1998 // Create the threads to install the Flow Paths
1999 //
2000 for (int i = 0; i < numThreads; i++) {
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002001 MyThread thread = new MyThread();
2002 thread.threadId = i;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002003 threads.add(thread);
2004 }
2005
2006 //
2007 // Start processing
2008 //
2009 measurementEndTimeProcessingPaths = 0;
2010 measurementStartTimeProcessingPaths = System.nanoTime();
2011 for (Thread thread : threads) {
2012 thread.start();
2013 }
2014
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002015 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002016 for (Thread thread : threads) {
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002017 try {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002018 thread.join();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002019 } catch (InterruptedException e) {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002020 log.debug("Exception waiting for a thread to install a Flow Path: ", e);
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002021 }
2022 }
2023
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002024 // Record the end of processing
2025 measurementEndTimeProcessingPaths = System.nanoTime();
2026
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002027 //
2028 // Prepare the string with measurement data per each Flow Path
2029 // installation.
2030 // The string is multiple lines: one line per Flow Path installation:
2031 // ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
2032 //
2033 measurementPerFlowStr = new String();
2034 String eol = System.getProperty("line.separator");
2035 for (MyThread thread : threads) {
2036 for (int i = 0; i < thread.samples; i++) {
2037 measurementPerFlowStr += "ThreadAndTimePerFlow " + thread.threadId + " " + numThreads + " " + thread.execTime[i] + eol;
2038 }
2039 }
2040
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002041 return true;
2042 }
2043
2044 /**
2045 * Get the measurement time that took to install the path flows.
2046 *
2047 * @return the measurement time (in nanoseconds) it took to install
2048 * the path flows.
2049 */
2050 @Override
2051 public Long measurementGetInstallPathsTimeNsec() {
2052 return new Long(measurementEndTimeProcessingPaths -
2053 measurementStartTimeProcessingPaths);
2054 }
2055
2056 /**
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002057 * Get the measurement install time per Flow.
2058 *
2059 * @return a multi-line string with the following format per line:
2060 * ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
2061 */
2062 @Override
2063 public String measurementGetPerFlowInstallTime() {
2064 return new String(measurementPerFlowStr);
2065 }
2066
2067 /**
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002068 * Clear the path flows stored for measurement purpose.
2069 *
2070 * @return true on success, otherwise false.
2071 */
2072 @Override
2073 public boolean measurementClearAllPaths() {
2074 measurementStoredPaths.clear();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002075 topoRouteService.dropShortestPathTopo(measurementShortestPathTopo);
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00002076 measurementStartTimeProcessingPaths = 0;
2077 measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002078 measurementPerFlowStr = new String();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002079
2080 return true;
2081 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002082}