blob: 7e46b540f4f28071b43b32e5e5107e926b690b02 [file] [log] [blame]
HIGUCHI Yuta60a10142013-06-14 15:50:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
3import java.util.ArrayList;
4import java.util.Collection;
Naoki Shiota1a37ca12013-11-18 10:55:23 -08005import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08006import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00007import java.util.LinkedList;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08008import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +00009import java.util.Random;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080010import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.concurrent.Executors;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080012import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080015
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080018import net.floodlightcontroller.core.module.FloodlightModuleContext;
19import net.floodlightcontroller.core.module.FloodlightModuleException;
20import net.floodlightcontroller.core.module.IFloodlightModule;
21import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080022import net.floodlightcontroller.restserver.IRestApiService;
Naoki Shiota1a37ca12013-11-18 10:55:23 -080023import net.floodlightcontroller.util.OFMessageDamper;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070024import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070025import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070026import net.onrc.onos.ofcontroller.core.INetMapStorage;
27import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
28import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070029import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070030import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080031import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070032import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070033import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070034import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080035
Naoki Shiota1a37ca12013-11-18 10:55:23 -080036import org.openflow.protocol.OFType;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
admin944ef4f2013-10-08 17:48:37 -070040/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070041 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070042 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070043public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080044
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -080045 //
46 // TODO: A temporary variable to switch between the poll-based and
47 // notification mechanism for the Flow Manager.
48 //
Pavlin Radoslavov38c1dfe2013-11-20 17:09:11 -080049 private final static boolean enableNotifications = true;
Naoki Shiota1a37ca12013-11-18 10:55:23 -080050
51 // flag to use FlowPusher instead of FlowSwitchOperation/MessageDamper
52 private final static boolean enableFlowPusher = false;
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -080053
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080054 protected GraphDBOperation dbHandlerApi;
55 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080056
Jonathan Hart50a94982013-04-10 14:49:51 -070057 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070058 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070059 protected volatile IDatagridService datagridService;
60 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070061 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070062 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080063
Brian O'Connor8c166a72013-11-14 18:41:48 -080064 protected IFlowPusherService pusher;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080065
Naoki Shiota1a37ca12013-11-18 10:55:23 -080066 protected OFMessageDamper messageDamper;
67
68 //
69 // TODO: Values copied from elsewhere (class LearningSwitch).
70 // The local copy should go away!
71 //
72 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
73 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080074
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000075 // Flow Entry ID generation state
76 private static Random randomGenerator = new Random();
77 private static int nextFlowEntryIdPrefix = 0;
78 private static int nextFlowEntryIdSuffix = 0;
79 private static long nextFlowEntryId = 0;
80
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080081 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070082 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080083
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080084 // The queue to write Flow Entries to the database
85 private BlockingQueue<FlowPathEntryPair> flowEntriesToDatabaseQueue =
86 new LinkedBlockingQueue<FlowPathEntryPair>();
87 FlowDatabaseWriter flowDatabaseWriter;
88
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080089 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070090 private ScheduledExecutorService mapReaderScheduler;
91 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -070092
admin944ef4f2013-10-08 17:48:37 -070093 /**
94 * Periodic task for reading the Flow Entries and pushing changes
95 * into the switches.
96 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070097 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080098 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070099 try {
100 runImpl();
101 } catch (Exception e) {
102 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800103 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700104 return;
105 }
106 }
107
108 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700109 long startTime = System.nanoTime();
110 int counterAllFlowEntries = 0;
111 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700112
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800113 if (floodlightProvider == null) {
114 log.debug("FloodlightProvider service not found!");
115 return;
116 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000117 Map<Long, IOFSwitch> mySwitches =
118 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700119 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700120 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700121 return;
122 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700123 LinkedList<IFlowEntry> addFlowEntries =
124 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000125 LinkedList<IFlowEntry> deleteFlowEntries =
126 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700127
128 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700129 // Fetch all Flow Entries which need to be updated and select
130 // only my Flow Entries that need to be updated into the
131 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700132 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000133 Iterable<IFlowEntry> allFlowEntries =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800134 dbHandlerInner.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700135 for (IFlowEntry flowEntryObj : allFlowEntries) {
Naoki Shiota4e77de92013-11-18 17:29:54 -0800136 log.debug("flowEntryobj : {}", flowEntryObj);
137
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700138 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000139
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000140 String dpidStr = flowEntryObj.getSwitchDpid();
141 if (dpidStr == null)
142 continue;
143 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800144 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000145 if (mySwitch == null)
146 continue; // Ignore the entry: not my switch
147
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700148 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800149 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700150 if (flowObj == null)
151 continue; // Should NOT happen
152 if (flowObj.getFlowId() == null)
153 continue; // Invalid entry
154
155 //
156 // NOTE: For now we process the DELETE before the ADD
157 // to cover the more common scenario.
158 // TODO: This is error prone and needs to be fixed!
159 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000160 String userState = flowEntryObj.getUserState();
161 if (userState == null)
162 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700163 if (userState.equals("FE_USER_DELETE")) {
164 // An entry that needs to be deleted.
165 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700166 installFlowEntry(mySwitch, flowObj, flowEntryObj);
167 } else {
168 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700169 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700170 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700171 }
Naoki Shiota4e77de92013-11-18 17:29:54 -0800172
173 log.debug("addFlowEntries : {}", addFlowEntries);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700174
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700175 //
176 // Process the Flow Entries that need to be added
177 //
178 for (IFlowEntry flowEntryObj : addFlowEntries) {
179 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800180 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700181 if (flowObj == null)
182 continue; // Should NOT happen
183 if (flowObj.getFlowId() == null)
184 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700185
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700186 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700187 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000188 if (mySwitch == null)
189 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700190 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800191 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000192
193 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000194 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700195 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000196 //
197 // TODO: We should use the OpenFlow Barrier mechanism
198 // to check for errors, and delete the Flow Entries after the
199 // Barrier message is received.
200 //
201 while (! deleteFlowEntries.isEmpty()) {
202 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
203 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800204 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000205 if (flowObj == null) {
206 log.debug("Did not find FlowPath to be deleted");
207 continue;
208 }
209 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800210 dbHandlerInner.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000211 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700212
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800213 dbHandlerInner.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700214
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700215 long estimatedTime = System.nanoTime() - startTime;
216 double rate = 0.0;
217 if (estimatedTime > 0)
218 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
219 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
220 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
221 counterMyNotUpdatedFlowEntries + " in " +
222 (double)estimatedTime / 1000000000 + " sec: " +
223 rate + " paths/s";
224 log.debug(logMsg);
225 }
226 };
227
admin944ef4f2013-10-08 17:48:37 -0700228 /**
229 * Periodic task for reading the Flow Paths and recomputing the
230 * shortest paths.
231 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700232 final Runnable shortestPathReconcile = new Runnable() {
233 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700234 try {
235 runImpl();
236 } catch (Exception e) {
237 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800238 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700239 return;
240 }
241 }
242
243 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700244 long startTime = System.nanoTime();
245 int counterAllFlowPaths = 0;
246 int counterMyFlowPaths = 0;
247
248 if (floodlightProvider == null) {
249 log.debug("FloodlightProvider service not found!");
250 return;
251 }
252 Map<Long, IOFSwitch> mySwitches =
253 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700254 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700255 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700256 return;
257 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700258 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
259
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700260 //
261 // Fetch and recompute the Shortest Path for those
262 // Flow Paths this controller is responsible for.
263 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700264 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800265 Iterable<IFlowPath> allFlowPaths = dbHandlerInner.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700266 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700267 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700268 if (flowPathObj == null)
269 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700270
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700271 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000272 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700273 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700274 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700275 //
276 // Use the source DPID as a heuristic to decide
277 // which controller is responsible for maintaining the
278 // shortest path.
279 // NOTE: This heuristic is error-prone: if the switch
280 // goes away and no controller is responsible for that
281 // switch, then the original Flow Path is not cleaned-up
282 //
283 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
284 if (mySwitch == null)
285 continue; // Ignore: not my responsibility
286
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700287 // Test whether we need to maintain this flow
288 String flowPathTypeStr = flowPathObj.getFlowPathType();
289 if (flowPathTypeStr == null)
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700290 continue; // Could be invalid entry?
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700291 if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700292 continue; // No need to maintain this flow
293
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000294 //
295 // Test whether we need to complete the Flow cleanup,
296 // if the Flow has been deleted by the user.
297 //
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700298 String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
299 if ((flowPathUserStateStr != null)
300 && flowPathUserStateStr.equals("FP_USER_DELETE")) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000301 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700302 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000303 if (empty)
304 deleteFlows.add(flowPathObj);
305 }
306
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000307 // Fetch the fields needed to recompute the shortest path
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700308 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000309 Short srcPortShort = flowPathObj.getSrcPort();
310 String dstDpidStr = flowPathObj.getDstSwitch();
311 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700312 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700313 if ((dataPathSummaryStr == null) ||
314 (srcPortShort == null) ||
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000315 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700316 (dstPortShort == null) ||
317 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000318 continue;
319 }
320
321 Port srcPort = new Port(srcPortShort);
322 Dpid dstDpid = new Dpid(dstDpidStr);
323 Port dstPort = new Port(dstPortShort);
324 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
325 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700326 FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700327 FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700328 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000329
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700330 counterMyFlowPaths++;
331
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700332 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700333 // NOTE: Using here the regular getDatabaseShortestPath()
334 // method won't work here, because that method calls
335 // internally "conn.endTx(Transaction.COMMIT)", and that
336 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700337 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700338 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700339 // to avoid closing the transaction.
340 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700341 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700342 topologyNetService.getTopologyShortestPath(
343 topology,
344 srcSwitchPort,
345 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000346 if (dataPath == null) {
347 // We need the DataPath to compare the paths
348 dataPath = new DataPath();
349 dataPath.setSrcPort(srcSwitchPort);
350 dataPath.setDstPort(dstSwitchPort);
351 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700352 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000353
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700354 String newDataPathSummaryStr = dataPath.dataPathSummary();
355 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
356 continue; // Nothing changed
357
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700358 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700359 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000360
361 //
362 // Delete all leftover Flows marked for deletion from the
363 // Network MAP.
364 //
365 while (! deleteFlows.isEmpty()) {
366 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800367 dbHandlerInner.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000368 }
369
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700370 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700371
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800372 dbHandlerInner.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700373
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700374 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700375 double rate = 0.0;
376 if (estimatedTime > 0)
377 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700378 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700379 counterAllFlowPaths + " MyFlowPaths: " +
380 counterMyFlowPaths + " in " +
381 (double)estimatedTime / 1000000000 + " sec: " +
382 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700383 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800384 }
385 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700386
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800387
admin944ef4f2013-10-08 17:48:37 -0700388 /**
389 * Initialize the Flow Manager.
390 *
391 * @param conf the Graph Database configuration string.
392 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800393 @Override
394 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800395 dbHandlerApi = new GraphDBOperation(conf);
396 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800397 }
398
admin944ef4f2013-10-08 17:48:37 -0700399 /**
400 * Shutdown the Flow Manager operation.
401 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800402 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700403 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800404 }
405
admin944ef4f2013-10-08 17:48:37 -0700406 /**
407 * Shutdown the Flow Manager operation.
408 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800409 @Override
410 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700411 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800412 dbHandlerApi.close();
413 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800414 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800415
admin944ef4f2013-10-08 17:48:37 -0700416 /**
417 * Get the collection of offered module services.
418 *
419 * @return the collection of offered module services.
420 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800421 @Override
422 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
423 Collection<Class<? extends IFloodlightService>> l =
424 new ArrayList<Class<? extends IFloodlightService>>();
425 l.add(IFlowService.class);
426 return l;
427 }
428
admin944ef4f2013-10-08 17:48:37 -0700429 /**
430 * Get the collection of implemented services.
431 *
432 * @return the collection of implemented services.
433 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800434 @Override
435 public Map<Class<? extends IFloodlightService>, IFloodlightService>
436 getServiceImpls() {
437 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700438 IFloodlightService> m =
439 new HashMap<Class<? extends IFloodlightService>,
440 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800441 m.put(IFlowService.class, this);
442 return m;
443 }
444
admin944ef4f2013-10-08 17:48:37 -0700445 /**
446 * Get the collection of modules this module depends on.
447 *
448 * @return the collection of modules this module depends on.
449 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800450 @Override
451 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700452 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800453 Collection<Class<? extends IFloodlightService>> l =
454 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800455 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700456 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700457 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800458 l.add(IRestApiService.class);
459 return l;
460 }
461
admin944ef4f2013-10-08 17:48:37 -0700462 /**
463 * Initialize the module.
464 *
465 * @param context the module context to use for the initialization.
466 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800467 @Override
468 public void init(FloodlightModuleContext context)
469 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700470 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800471 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700472 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
473 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800474 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700475
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800476 if (enableFlowPusher) {
477 pusher = context.getServiceImpl(IFlowPusherService.class);
478 } else {
479 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
480 EnumSet.of(OFType.FLOW_MOD),
481 OFMESSAGE_DAMPER_TIMEOUT);
482 }
Brian O'Connor8c166a72013-11-14 18:41:48 -0800483
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700484 this.init("");
485
admin944ef4f2013-10-08 17:48:37 -0700486 mapReaderScheduler = Executors.newScheduledThreadPool(1);
487 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800488 }
489
admin944ef4f2013-10-08 17:48:37 -0700490 /**
491 * Get the next Flow Entry ID to use.
492 *
493 * @return the next Flow Entry ID to use.
494 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800495 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700496 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000497 //
498 // Generate the next Flow Entry ID.
499 // NOTE: For now, the higher 32 bits are random, and
500 // the lower 32 bits are sequential.
501 // In the future, we need a better allocation mechanism.
502 //
503 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
504 nextFlowEntryIdPrefix = randomGenerator.nextInt();
505 nextFlowEntryIdSuffix = 0;
506 } else {
507 nextFlowEntryIdSuffix++;
508 }
509 long result = (long)nextFlowEntryIdPrefix << 32;
510 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
511 return result;
512 }
513
admin944ef4f2013-10-08 17:48:37 -0700514 /**
515 * Startup module operation.
516 *
517 * @param context the module context to use for the startup.
518 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800519 @Override
520 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700521 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700522
admin944ef4f2013-10-08 17:48:37 -0700523 // Initialize the Flow Entry ID generator
524 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800525
526 //
527 // The thread to write to the database
528 //
529 flowDatabaseWriter = new FlowDatabaseWriter(this,
530 flowEntriesToDatabaseQueue);
531 flowDatabaseWriter.start();
532
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700533 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700534 // Create the Flow Event Handler thread and register it with the
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700535 // Datagrid Service
536 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700537 flowEventHandler = new FlowEventHandler(this, datagridService);
538 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -0700539
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700540 // Schedule the threads and periodic tasks
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700541 flowEventHandler.start();
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800542 if (! enableNotifications) {
543 mapReaderScheduler.scheduleAtFixedRate(
admin944ef4f2013-10-08 17:48:37 -0700544 mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800545 shortestPathReconcileScheduler.scheduleAtFixedRate(
admin944ef4f2013-10-08 17:48:37 -0700546 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800547 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800548 }
549
550 /**
551 * Add a flow.
552 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800553 * @param flowPath the Flow Path to install.
554 * @param flowId the return-by-reference Flow ID as assigned internally.
555 * @return true on success, otherwise false.
556 */
557 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700558 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700559 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700560 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700561 // in case the application didn't do it.
562 //
563 for (FlowEntry flowEntry : flowPath.flowEntries()) {
564 if (flowEntry.flowEntrySwitchState() ==
565 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
566 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
567 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700568 if (! flowEntry.isValidFlowId())
569 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700570 }
571
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800572 if (FlowDatabaseOperation.addFlow(this, dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700573 datagridService.notificationSendFlowAdded(flowPath);
574 return true;
575 }
576 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800577 }
578
579 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700580 * Add a flow entry to the Network MAP.
581 *
582 * @param flowObj the corresponding Flow Path object for the Flow Entry.
583 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700584 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700585 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700586 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800587 return FlowDatabaseOperation.addFlowEntry(this, dbHandlerInner,
588 flowObj, flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700589 }
590
591 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700592 * Delete a flow entry from the Network MAP.
593 *
594 * @param flowObj the corresponding Flow Path object for the Flow Entry.
595 * @param flowEntry the Flow Entry to delete.
596 * @return true on success, otherwise false.
597 */
598 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800599 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
600 flowObj, flowEntry);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800601 }
602
603 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000604 * Delete all previously added flows.
605 *
606 * @return true on success, otherwise false.
607 */
608 @Override
609 public boolean deleteAllFlows() {
Pavlin Radoslavovff43b562013-11-20 17:13:48 -0800610 //
611 // TODO: In the notification-based implementation,
612 // deleteFlow() is implemented by using clearFlow()
613 //
614 return clearAllFlows();
615
616 /*
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800617 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700618 datagridService.notificationSendAllFlowsRemoved();
619 return true;
620 }
621 return false;
Pavlin Radoslavovff43b562013-11-20 17:13:48 -0800622 */
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000623 }
624
625 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800626 * Delete a previously added flow.
627 *
628 * @param flowId the Flow ID of the flow to delete.
629 * @return true on success, otherwise false.
630 */
631 @Override
632 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovff43b562013-11-20 17:13:48 -0800633 //
634 // TODO: In the notification-based implementation,
635 // deleteFlow() is implemented by using clearFlow()
636 //
637 return clearFlow(flowId);
638 /*
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800639 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700640 datagridService.notificationSendFlowRemoved(flowId);
641 return true;
642 }
643 return false;
Pavlin Radoslavovff43b562013-11-20 17:13:48 -0800644 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800645 }
646
647 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000648 * Clear the state for all previously added flows.
649 *
650 * @return true on success, otherwise false.
651 */
652 @Override
653 public boolean clearAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800654 if (FlowDatabaseOperation.clearAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700655 datagridService.notificationSendAllFlowsRemoved();
656 return true;
657 }
658 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000659 }
660
661 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700662 * Clear the state for a previously added flow.
663 *
664 * @param flowId the Flow ID of the flow to clear.
665 * @return true on success, otherwise false.
666 */
667 @Override
668 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800669 if (FlowDatabaseOperation.clearFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700670 datagridService.notificationSendFlowRemoved(flowId);
671 return true;
672 }
673 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700674 }
675
676 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800677 * Get a previously added flow.
678 *
679 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800680 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800681 */
682 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800683 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800684 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700685 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800686
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700687 /**
688 * Get all installed flows by all installers.
689 *
690 * @return the Flow Paths if found, otherwise null.
691 */
692 @Override
693 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800694 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800695 }
696
697 /**
698 * Get all previously added flows by a specific installer for a given
699 * data path endpoints.
700 *
701 * @param installerId the Caller ID of the installer of the flow to get.
702 * @param dataPathEndpoints the data path endpoints of the flow to get.
703 * @return the Flow Paths if found, otherwise null.
704 */
705 @Override
706 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
707 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800708 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700709 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800710 }
711
712 /**
713 * Get all installed flows by all installers for given data path endpoints.
714 *
715 * @param dataPathEndpoints the data path endpoints of the flows to get.
716 * @return the Flow Paths if found, otherwise null.
717 */
718 @Override
719 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800720 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
721 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800722 }
723
724 /**
admin944ef4f2013-10-08 17:48:37 -0700725 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700726 *
admin944ef4f2013-10-08 17:48:37 -0700727 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700728 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700729 * @return the Flow Paths if found, otherwise null.
730 */
731 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700732 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
733 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800734 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700735 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700736 }
737
738 /**
admin944ef4f2013-10-08 17:48:37 -0700739 * Get all Flows information, without the associated Flow Entries.
740 *
741 * @return all Flows information, without the associated Flow Entries.
742 */
743 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800744 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandlerApi);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700745 }
746
747 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700748 * Add and maintain a shortest-path flow.
749 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700750 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700751 *
752 * @param flowPath the Flow Path with the endpoints and the match
753 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700754 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700755 */
756 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700757 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700758 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000759 // Don't do the shortest path computation here.
760 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700761 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700762
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700763 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700764 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700765 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700766
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700767 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700768 }
769
770 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800771 * Get the collection of my switches.
772 *
773 * @return the collection of my switches.
774 */
775 public Map<Long, IOFSwitch> getMySwitches() {
776 return floodlightProvider.getSwitches();
777 }
778
779 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800780 * Get the network topology.
781 *
782 * @return the network topology.
783 */
784 public Topology getTopology() {
785 return flowEventHandler.getTopology();
786 }
787
788 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700789 * Reconcile a flow.
790 *
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800791 * @param flowObj the flow that needs to be reconciled.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700792 * @param newDataPath the new data path to use.
793 * @return true on success, otherwise false.
794 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700795 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700796 String flowIdStr = flowObj.getFlowId();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700797
798 //
799 // Set the incoming port matching and the outgoing port output
800 // actions for each flow entry.
801 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700802 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700803 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700804 flowEntry.setFlowId(new FlowId(flowIdStr));
805
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700806 // Mark the Flow Entry as not updated in the switch
807 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700808 // Set the incoming port matching
809 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
810 flowEntry.setFlowEntryMatch(flowEntryMatch);
811 flowEntryMatch.enableInPort(flowEntry.inPort());
812
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700813 //
814 // Set the actions
815 //
816 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
817 //
818 // If the first Flow Entry, copy the Flow Path actions to it
819 //
820 if (idx == 0) {
821 String actionsStr = flowObj.getActions();
822 if (actionsStr != null) {
823 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
824 for (FlowEntryAction action : flowActions.actions())
825 flowEntryActions.addAction(action);
826 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700827 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700828 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700829 //
830 // Add the outgoing port output action
831 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700832 FlowEntryAction flowEntryAction = new FlowEntryAction();
833 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700834 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700835 }
836
837 //
838 // Remove the old Flow Entries, and add the new Flow Entries
839 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700840 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700841 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700842 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700843 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700844 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700845 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700846 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700847 }
848
849 //
850 // Set the Data Path Summary
851 //
852 String dataPathSummaryStr = newDataPath.dataPathSummary();
853 flowObj.setDataPathSummary(dataPathSummaryStr);
854
855 return true;
856 }
857
858 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700859 * Reconcile all flows in a set.
860 *
861 * @param flowObjSet the set of flows that need to be reconciliated.
862 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700863 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700864 if (! flowObjSet.iterator().hasNext())
865 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700866 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700867 }
868
869 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700870 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700871 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700872 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700873 * @param flowObj the flow path object for the flow entry to install.
874 * @param flowEntryObj the flow entry object to install.
875 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700876 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700877 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700878 IFlowEntry flowEntryObj) {
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800879 if (enableFlowPusher) {
880 return pusher.add(mySwitch, flowObj, flowEntryObj);
881 } else {
882 return FlowSwitchOperation.installFlowEntry(
883 floodlightProvider.getOFMessageFactory(),
884 messageDamper, mySwitch, flowObj, flowEntryObj);
885 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700886 }
887
888 /**
889 * Install a Flow Entry on a switch.
890 *
891 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700892 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700893 * @param flowEntry the flow entry to install.
894 * @return true on success, otherwise false.
895 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700896 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700897 FlowEntry flowEntry) {
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800898 if (enableFlowPusher) {
899 return pusher.add(mySwitch, flowPath, flowEntry);
900 } else {
901 return FlowSwitchOperation.installFlowEntry(
902 floodlightProvider.getOFMessageFactory(),
903 messageDamper, mySwitch, flowPath, flowEntry);
904 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700905 }
906
907 /**
908 * Remove a Flow Entry from a switch.
909 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700910 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700911 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700912 * @param flowEntry the flow entry to remove.
913 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700914 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700915 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700916 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700917 //
918 // The installFlowEntry() method implements both installation
919 // and removal of flow entries.
920 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700921 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700922 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700923
924 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800925 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700926 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800927 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700928 * are pushed.
929 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800930 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700931 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800932 public void pushModifiedFlowEntriesToSwitches(
933 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700934 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800935 if (! enableNotifications)
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700936 return;
937
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800938 if (modifiedFlowEntries.isEmpty())
939 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700940
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800941 Map<Long, IOFSwitch> mySwitches = getMySwitches();
942
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800943 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
944 FlowPath flowPath = flowPair.flowPath;
945 FlowEntry flowEntry = flowPair.flowEntry;
946
947 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
948 if (mySwitch == null)
949 continue;
950
951 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
952
953 //
954 // Install the Flow Entry into the switch
955 //
956 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
957 String logMsg = "Cannot install Flow Entry " +
958 flowEntry.flowEntryId() +
959 " from Flow Path " + flowPath.flowId() +
960 " on switch " + flowEntry.dpid();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700961 log.error(logMsg);
962 continue;
963 }
964
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800965 //
966 // NOTE: Here we assume that the switch has been
967 // successfully updated.
968 //
969 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
970 }
971 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700972
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800973 /**
974 * Push modified Flow Entries to the datagrid.
975 *
976 * @param modifiedFlowEntries the collection of modified Flow Entries.
977 */
978 public void pushModifiedFlowEntriesToDatagrid(
979 Collection<FlowPathEntryPair> modifiedFlowEntries) {
980 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800981 if (! enableNotifications)
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800982 return;
983
984 if (modifiedFlowEntries.isEmpty())
985 return;
986
987 Map<Long, IOFSwitch> mySwitches = getMySwitches();
988
989 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
990 FlowEntry flowEntry = flowPair.flowEntry;
991
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800992 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
993
994 //
995 // TODO: For now Flow Entries are removed by all instances,
996 // even if this Flow Entry is not for our switches.
997 //
998 // This is needed to handle the case a switch going down:
999 // it has no Master controller instance, hence no
1000 // controller instance will cleanup its flow entries.
1001 // This is sub-optimal: we need to elect a controller
1002 // instance to handle the cleanup of such orphaned flow
1003 // entries.
1004 //
1005 if (mySwitch == null) {
1006 if (flowEntry.flowEntryUserState() !=
1007 FlowEntryUserState.FE_USER_DELETE) {
1008 continue;
1009 }
1010 if (! flowEntry.isValidFlowEntryId())
1011 continue;
1012 }
1013
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001014 log.debug("Pushing Flow Entry To Datagrid: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001015 //
1016 // Write the Flow Entry to the Datagrid
1017 //
1018 switch (flowEntry.flowEntryUserState()) {
1019 case FE_USER_ADD:
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001020 if (mySwitch == null)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001021 break; // Install only flow entries for my switches
1022 datagridService.notificationSendFlowEntryAdded(flowEntry);
1023 break;
1024 case FE_USER_MODIFY:
1025 if (mySwitch == null)
1026 break; // Install only flow entries for my switches
1027 datagridService.notificationSendFlowEntryUpdated(flowEntry);
1028 break;
1029 case FE_USER_DELETE:
1030 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
1031 break;
1032 }
1033 }
1034 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001035
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001036 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -08001037 * Class to implement writing to the database in a separate thread.
1038 */
1039 class FlowDatabaseWriter extends Thread {
1040 private FlowManager flowManager;
1041 private BlockingQueue<FlowPathEntryPair> blockingQueue;
1042
1043 /**
1044 * Constructor.
1045 *
1046 * @param flowManager the Flow Manager to use.
1047 * @param blockingQueue the blocking queue to use.
1048 */
1049 FlowDatabaseWriter(FlowManager flowManager,
1050 BlockingQueue<FlowPathEntryPair> blockingQueue) {
1051 this.flowManager = flowManager;
1052 this.blockingQueue = blockingQueue;
1053 }
1054
1055 /**
1056 * Run the thread.
1057 */
1058 @Override
1059 public void run() {
1060 //
1061 // The main loop
1062 //
1063 Collection<FlowPathEntryPair> collection =
1064 new LinkedList<FlowPathEntryPair>();
1065 try {
1066 while (true) {
1067 FlowPathEntryPair entryPair = blockingQueue.take();
1068 collection.add(entryPair);
1069 blockingQueue.drainTo(collection);
1070 flowManager.writeModifiedFlowEntriesToDatabase(collection);
1071 collection.clear();
1072 }
1073 } catch (Exception exception) {
1074 log.debug("Exception writing to the Database: ", exception);
1075 }
1076 }
1077 }
1078
1079 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001080 * Push Flow Entries to the Network MAP.
1081 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001082 * NOTE: The Flow Entries are pushed only on the instance responsible
1083 * for the first switch. This is to avoid database errors when multiple
1084 * instances are writing Flow Entries for the same Flow Path.
1085 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001086 * @param modifiedFlowEntries the collection of Flow Entries to push.
1087 */
Pavlin Radoslavov584bd112013-11-21 20:59:33 -08001088 void pushModifiedFlowEntriesToDatabase(
1089 Collection<FlowPathEntryPair> modifiedFlowEntries) {
1090 // TODO: For now, the pushing of Flow Entries is disabled
1091 if (! enableNotifications)
1092 return;
1093
1094 //
1095 // We only add the Flow Entries to the Database Queue.
1096 // The FlowDatabaseWriter thread is responsible for the actual writing.
1097 //
1098 flowEntriesToDatabaseQueue.addAll(modifiedFlowEntries);
1099 }
1100
1101 /**
1102 * Write Flow Entries to the Network MAP.
1103 *
1104 * NOTE: The Flow Entries are written only on the instance responsible
1105 * for the first switch. This is to avoid database errors when multiple
1106 * instances are writing Flow Entries for the same Flow Path.
1107 *
1108 * @param modifiedFlowEntries the collection of Flow Entries to write.
1109 */
1110 private void writeModifiedFlowEntriesToDatabase(
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001111 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001112 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -08001113 if (! enableNotifications)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001114 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001115
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001116 if (modifiedFlowEntries.isEmpty())
1117 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001118
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001119 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001120
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001121 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
1122 FlowPath flowPath = flowPair.flowPath;
1123 FlowEntry flowEntry = flowPair.flowEntry;
1124
1125 if (! flowEntry.isValidFlowEntryId())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001126 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001127
1128 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001129 // Push the changes only on the instance responsible for the
1130 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001131 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001132 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
1133 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
1134 if (mySrcSwitch == null)
1135 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001136
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001137 log.debug("Pushing Flow Entry To Database: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001138 //
1139 // Write the Flow Entry to the Network Map
1140 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001141 // NOTE: We try a number of times, in case somehow some other
1142 // instances are writing at the same time.
1143 // Apparently, if other instances are writing at the same time
1144 // this will trigger an error.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001145 //
1146 for (int i = 0; i < 6; i++) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001147 try {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001148 //
1149 // Find the Flow Path in the Network MAP.
1150 //
1151 // NOTE: The Flow Path might not be found if the Flow was
1152 // just removed by some other controller instance.
1153 //
1154 IFlowPath flowObj =
1155 dbHandlerInner.searchFlowPath(flowEntry.flowId());
1156 if (flowObj == null) {
1157 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001158 log.error(logMsg);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001159 break;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001160 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001161
1162 // Write the Flow Entry
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001163 switch (flowEntry.flowEntryUserState()) {
1164 case FE_USER_ADD:
1165 // FALLTHROUGH
1166 case FE_USER_MODIFY:
1167 if (addFlowEntry(flowObj, flowEntry) == null) {
1168 String logMsg = "Cannot write to Network MAP Flow Entry " +
1169 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001170 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001171 " on switch " + flowEntry.dpid();
1172 log.error(logMsg);
1173 }
1174 break;
1175 case FE_USER_DELETE:
1176 if (deleteFlowEntry(flowObj, flowEntry) == false) {
1177 String logMsg = "Cannot remove from Network MAP Flow Entry " +
1178 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001179 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001180 " on switch " + flowEntry.dpid();
1181 log.error(logMsg);
1182 }
1183 break;
1184 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001185
1186 // Commit to the database
1187 dbHandlerInner.commit();
1188 break; // Success
1189
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001190 } catch (Exception e) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -08001191 log.debug("Exception writing Flow Entry to Network MAP: ", e);
1192 dbHandlerInner.rollback();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001193 // Wait a bit (random value [1ms, 20ms] and try again
1194 int delay = 1 + randomGenerator.nextInt() % 20;
1195 try {
1196 Thread.sleep(delay);
1197 } catch (Exception e0) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001198 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001199 }
1200 }
1201 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001202 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001203}