blob: bd5ba437474644456425408ee008f20d5ffebeda [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;
5import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00006import java.util.LinkedList;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08007import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +00008import java.util.Random;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08009import java.util.concurrent.Executors;
10import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080012
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080015import net.floodlightcontroller.core.module.FloodlightModuleContext;
16import net.floodlightcontroller.core.module.FloodlightModuleException;
17import net.floodlightcontroller.core.module.IFloodlightModule;
18import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080019import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070020import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070021import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070022import net.onrc.onos.ofcontroller.core.INetMapStorage;
23import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
24import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070025import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070026import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080027import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070028import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070029import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070030import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080031
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080032import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
34
admin944ef4f2013-10-08 17:48:37 -070035/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070036 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070037 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070038public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -080040 //
41 // TODO: A temporary variable to switch between the poll-based and
42 // notification mechanism for the Flow Manager.
43 //
44 private final static boolean enableNotifications = false;
45
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080046 protected GraphDBOperation dbHandlerApi;
47 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080048
Jonathan Hart50a94982013-04-10 14:49:51 -070049 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070050 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070051 protected volatile IDatagridService datagridService;
52 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070053 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070054 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080055
Brian O'Connor8c166a72013-11-14 18:41:48 -080056 protected IFlowPusherService pusher;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080057
Naoki Shiota36e89432013-11-13 11:11:43 -080058// LEGACY
59// protected OFMessageDamper messageDamper;
60//
61// //
62// // TODO: Values copied from elsewhere (class LearningSwitch).
63// // The local copy should go away!
64// //
65// protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
66// protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080067
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000068 // Flow Entry ID generation state
69 private static Random randomGenerator = new Random();
70 private static int nextFlowEntryIdPrefix = 0;
71 private static int nextFlowEntryIdSuffix = 0;
72 private static long nextFlowEntryId = 0;
73
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080074 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070075 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080076
77 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070078 private ScheduledExecutorService mapReaderScheduler;
79 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -070080
admin944ef4f2013-10-08 17:48:37 -070081 /**
82 * Periodic task for reading the Flow Entries and pushing changes
83 * into the switches.
84 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070085 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080086 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070087 try {
88 runImpl();
89 } catch (Exception e) {
90 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080091 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070092 return;
93 }
94 }
95
96 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070097 long startTime = System.nanoTime();
98 int counterAllFlowEntries = 0;
99 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700100
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800101 if (floodlightProvider == null) {
102 log.debug("FloodlightProvider service not found!");
103 return;
104 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000105 Map<Long, IOFSwitch> mySwitches =
106 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700107 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700108 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700109 return;
110 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700111 LinkedList<IFlowEntry> addFlowEntries =
112 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000113 LinkedList<IFlowEntry> deleteFlowEntries =
114 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700115
116 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700117 // Fetch all Flow Entries which need to be updated and select
118 // only my Flow Entries that need to be updated into the
119 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700120 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000121 Iterable<IFlowEntry> allFlowEntries =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800122 dbHandlerInner.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700123 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700124 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000125
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000126 String dpidStr = flowEntryObj.getSwitchDpid();
127 if (dpidStr == null)
128 continue;
129 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800130 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000131 if (mySwitch == null)
132 continue; // Ignore the entry: not my switch
133
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700134 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800135 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700136 if (flowObj == null)
137 continue; // Should NOT happen
138 if (flowObj.getFlowId() == null)
139 continue; // Invalid entry
140
141 //
142 // NOTE: For now we process the DELETE before the ADD
143 // to cover the more common scenario.
144 // TODO: This is error prone and needs to be fixed!
145 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000146 String userState = flowEntryObj.getUserState();
147 if (userState == null)
148 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700149 if (userState.equals("FE_USER_DELETE")) {
150 // An entry that needs to be deleted.
151 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700152 installFlowEntry(mySwitch, flowObj, flowEntryObj);
153 } else {
154 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700155 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700156 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700157 }
158
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700159 //
160 // Process the Flow Entries that need to be added
161 //
162 for (IFlowEntry flowEntryObj : addFlowEntries) {
163 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800164 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700165 if (flowObj == null)
166 continue; // Should NOT happen
167 if (flowObj.getFlowId() == null)
168 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700169
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700170 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700171 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000172 if (mySwitch == null)
173 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700174 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800175 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000176
177 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000178 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700179 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000180 //
181 // TODO: We should use the OpenFlow Barrier mechanism
182 // to check for errors, and delete the Flow Entries after the
183 // Barrier message is received.
184 //
185 while (! deleteFlowEntries.isEmpty()) {
186 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
187 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800188 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000189 if (flowObj == null) {
190 log.debug("Did not find FlowPath to be deleted");
191 continue;
192 }
193 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800194 dbHandlerInner.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000195 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700196
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800197 dbHandlerInner.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700198
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700199 long estimatedTime = System.nanoTime() - startTime;
200 double rate = 0.0;
201 if (estimatedTime > 0)
202 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
203 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
204 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
205 counterMyNotUpdatedFlowEntries + " in " +
206 (double)estimatedTime / 1000000000 + " sec: " +
207 rate + " paths/s";
208 log.debug(logMsg);
209 }
210 };
211
admin944ef4f2013-10-08 17:48:37 -0700212 /**
213 * Periodic task for reading the Flow Paths and recomputing the
214 * shortest paths.
215 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700216 final Runnable shortestPathReconcile = new Runnable() {
217 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700218 try {
219 runImpl();
220 } catch (Exception e) {
221 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800222 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700223 return;
224 }
225 }
226
227 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700228 long startTime = System.nanoTime();
229 int counterAllFlowPaths = 0;
230 int counterMyFlowPaths = 0;
231
232 if (floodlightProvider == null) {
233 log.debug("FloodlightProvider service not found!");
234 return;
235 }
236 Map<Long, IOFSwitch> mySwitches =
237 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700238 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700239 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700240 return;
241 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700242 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
243
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700244 //
245 // Fetch and recompute the Shortest Path for those
246 // Flow Paths this controller is responsible for.
247 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700248 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800249 Iterable<IFlowPath> allFlowPaths = dbHandlerInner.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700250 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700251 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700252 if (flowPathObj == null)
253 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700254
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700255 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000256 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700257 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700258 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700259 //
260 // Use the source DPID as a heuristic to decide
261 // which controller is responsible for maintaining the
262 // shortest path.
263 // NOTE: This heuristic is error-prone: if the switch
264 // goes away and no controller is responsible for that
265 // switch, then the original Flow Path is not cleaned-up
266 //
267 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
268 if (mySwitch == null)
269 continue; // Ignore: not my responsibility
270
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700271 // Test whether we need to maintain this flow
272 String flowPathTypeStr = flowPathObj.getFlowPathType();
273 if (flowPathTypeStr == null)
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700274 continue; // Could be invalid entry?
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700275 if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700276 continue; // No need to maintain this flow
277
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000278 //
279 // Test whether we need to complete the Flow cleanup,
280 // if the Flow has been deleted by the user.
281 //
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700282 String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
283 if ((flowPathUserStateStr != null)
284 && flowPathUserStateStr.equals("FP_USER_DELETE")) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000285 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700286 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000287 if (empty)
288 deleteFlows.add(flowPathObj);
289 }
290
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000291 // Fetch the fields needed to recompute the shortest path
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700292 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000293 Short srcPortShort = flowPathObj.getSrcPort();
294 String dstDpidStr = flowPathObj.getDstSwitch();
295 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700296 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700297 if ((dataPathSummaryStr == null) ||
298 (srcPortShort == null) ||
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000299 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700300 (dstPortShort == null) ||
301 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000302 continue;
303 }
304
305 Port srcPort = new Port(srcPortShort);
306 Dpid dstDpid = new Dpid(dstDpidStr);
307 Port dstPort = new Port(dstPortShort);
308 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
309 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700310 FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700311 FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700312 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000313
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700314 counterMyFlowPaths++;
315
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700316 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700317 // NOTE: Using here the regular getDatabaseShortestPath()
318 // method won't work here, because that method calls
319 // internally "conn.endTx(Transaction.COMMIT)", and that
320 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700321 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700322 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700323 // to avoid closing the transaction.
324 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700325 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700326 topologyNetService.getTopologyShortestPath(
327 topology,
328 srcSwitchPort,
329 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000330 if (dataPath == null) {
331 // We need the DataPath to compare the paths
332 dataPath = new DataPath();
333 dataPath.setSrcPort(srcSwitchPort);
334 dataPath.setDstPort(dstSwitchPort);
335 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700336 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000337
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700338 String newDataPathSummaryStr = dataPath.dataPathSummary();
339 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
340 continue; // Nothing changed
341
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700342 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700343 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000344
345 //
346 // Delete all leftover Flows marked for deletion from the
347 // Network MAP.
348 //
349 while (! deleteFlows.isEmpty()) {
350 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800351 dbHandlerInner.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000352 }
353
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700354 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700355
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800356 dbHandlerInner.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700357
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700358 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700359 double rate = 0.0;
360 if (estimatedTime > 0)
361 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700362 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700363 counterAllFlowPaths + " MyFlowPaths: " +
364 counterMyFlowPaths + " in " +
365 (double)estimatedTime / 1000000000 + " sec: " +
366 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700367 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800368 }
369 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700370
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800371
admin944ef4f2013-10-08 17:48:37 -0700372 /**
373 * Initialize the Flow Manager.
374 *
375 * @param conf the Graph Database configuration string.
376 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800377 @Override
378 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800379 dbHandlerApi = new GraphDBOperation(conf);
380 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800381 }
382
admin944ef4f2013-10-08 17:48:37 -0700383 /**
384 * Shutdown the Flow Manager operation.
385 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800386 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700387 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800388 }
389
admin944ef4f2013-10-08 17:48:37 -0700390 /**
391 * Shutdown the Flow Manager operation.
392 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800393 @Override
394 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700395 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800396 dbHandlerApi.close();
397 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800398 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800399
admin944ef4f2013-10-08 17:48:37 -0700400 /**
401 * Get the collection of offered module services.
402 *
403 * @return the collection of offered module services.
404 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800405 @Override
406 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
407 Collection<Class<? extends IFloodlightService>> l =
408 new ArrayList<Class<? extends IFloodlightService>>();
409 l.add(IFlowService.class);
410 return l;
411 }
412
admin944ef4f2013-10-08 17:48:37 -0700413 /**
414 * Get the collection of implemented services.
415 *
416 * @return the collection of implemented services.
417 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800418 @Override
419 public Map<Class<? extends IFloodlightService>, IFloodlightService>
420 getServiceImpls() {
421 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700422 IFloodlightService> m =
423 new HashMap<Class<? extends IFloodlightService>,
424 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800425 m.put(IFlowService.class, this);
426 return m;
427 }
428
admin944ef4f2013-10-08 17:48:37 -0700429 /**
430 * Get the collection of modules this module depends on.
431 *
432 * @return the collection of modules this module depends on.
433 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800434 @Override
435 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700436 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800437 Collection<Class<? extends IFloodlightService>> l =
438 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800439 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700440 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700441 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800442 l.add(IRestApiService.class);
443 return l;
444 }
445
admin944ef4f2013-10-08 17:48:37 -0700446 /**
447 * Initialize the module.
448 *
449 * @param context the module context to use for the initialization.
450 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800451 @Override
452 public void init(FloodlightModuleContext context)
453 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700454 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800455 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700456 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
457 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800458 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700459
Naoki Shiota36e89432013-11-13 11:11:43 -0800460// LEGACY
461// messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
462// EnumSet.of(OFType.FLOW_MOD),
463// OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700464
Brian O'Connor8c166a72013-11-14 18:41:48 -0800465 pusher = context.getServiceImpl(IFlowPusherService.class);
466
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700467 this.init("");
468
admin944ef4f2013-10-08 17:48:37 -0700469 mapReaderScheduler = Executors.newScheduledThreadPool(1);
470 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800471 }
472
admin944ef4f2013-10-08 17:48:37 -0700473 /**
474 * Get the next Flow Entry ID to use.
475 *
476 * @return the next Flow Entry ID to use.
477 */
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700478 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000479 //
480 // Generate the next Flow Entry ID.
481 // NOTE: For now, the higher 32 bits are random, and
482 // the lower 32 bits are sequential.
483 // In the future, we need a better allocation mechanism.
484 //
485 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
486 nextFlowEntryIdPrefix = randomGenerator.nextInt();
487 nextFlowEntryIdSuffix = 0;
488 } else {
489 nextFlowEntryIdSuffix++;
490 }
491 long result = (long)nextFlowEntryIdPrefix << 32;
492 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
493 return result;
494 }
495
admin944ef4f2013-10-08 17:48:37 -0700496 /**
497 * Startup module operation.
498 *
499 * @param context the module context to use for the startup.
500 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800501 @Override
502 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700503 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700504
admin944ef4f2013-10-08 17:48:37 -0700505 // Initialize the Flow Entry ID generator
506 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Naoki Shiota36e89432013-11-13 11:11:43 -0800507
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700508 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700509 // Create the Flow Event Handler thread and register it with the
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700510 // Datagrid Service
511 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700512 flowEventHandler = new FlowEventHandler(this, datagridService);
513 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -0700514
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700515 // Schedule the threads and periodic tasks
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700516 flowEventHandler.start();
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800517 if (! enableNotifications) {
518 mapReaderScheduler.scheduleAtFixedRate(
admin944ef4f2013-10-08 17:48:37 -0700519 mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800520 shortestPathReconcileScheduler.scheduleAtFixedRate(
admin944ef4f2013-10-08 17:48:37 -0700521 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800522 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800523 }
524
525 /**
526 * Add a flow.
527 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800528 * @param flowPath the Flow Path to install.
529 * @param flowId the return-by-reference Flow ID as assigned internally.
530 * @return true on success, otherwise false.
531 */
532 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700533 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700534 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700535 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700536 // in case the application didn't do it.
537 //
538 for (FlowEntry flowEntry : flowPath.flowEntries()) {
539 if (flowEntry.flowEntrySwitchState() ==
540 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
541 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
542 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700543 if (! flowEntry.isValidFlowId())
544 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700545 }
546
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800547 if (FlowDatabaseOperation.addFlow(this, dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700548 datagridService.notificationSendFlowAdded(flowPath);
549 return true;
550 }
551 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800552 }
553
554 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700555 * Add a flow entry to the Network MAP.
556 *
557 * @param flowObj the corresponding Flow Path object for the Flow Entry.
558 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700559 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700560 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700561 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800562 return FlowDatabaseOperation.addFlowEntry(this, dbHandlerInner,
563 flowObj, flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700564 }
565
566 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700567 * Delete a flow entry from the Network MAP.
568 *
569 * @param flowObj the corresponding Flow Path object for the Flow Entry.
570 * @param flowEntry the Flow Entry to delete.
571 * @return true on success, otherwise false.
572 */
573 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800574 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
575 flowObj, flowEntry);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800576 }
577
578 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000579 * Delete all previously added flows.
580 *
581 * @return true on success, otherwise false.
582 */
583 @Override
584 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800585 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700586 datagridService.notificationSendAllFlowsRemoved();
587 return true;
588 }
589 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000590 }
591
592 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800593 * Delete a previously added flow.
594 *
595 * @param flowId the Flow ID of the flow to delete.
596 * @return true on success, otherwise false.
597 */
598 @Override
599 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800600 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700601 datagridService.notificationSendFlowRemoved(flowId);
602 return true;
603 }
604 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800605 }
606
607 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000608 * Clear the state for all previously added flows.
609 *
610 * @return true on success, otherwise false.
611 */
612 @Override
613 public boolean clearAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800614 if (FlowDatabaseOperation.clearAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700615 datagridService.notificationSendAllFlowsRemoved();
616 return true;
617 }
618 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000619 }
620
621 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700622 * Clear the state for a previously added flow.
623 *
624 * @param flowId the Flow ID of the flow to clear.
625 * @return true on success, otherwise false.
626 */
627 @Override
628 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800629 if (FlowDatabaseOperation.clearFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700630 datagridService.notificationSendFlowRemoved(flowId);
631 return true;
632 }
633 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700634 }
635
636 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800637 * Get a previously added flow.
638 *
639 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800640 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800641 */
642 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800643 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800644 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700645 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800646
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700647 /**
648 * Get all installed flows by all installers.
649 *
650 * @return the Flow Paths if found, otherwise null.
651 */
652 @Override
653 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800654 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800655 }
656
657 /**
658 * Get all previously added flows by a specific installer for a given
659 * data path endpoints.
660 *
661 * @param installerId the Caller ID of the installer of the flow to get.
662 * @param dataPathEndpoints the data path endpoints of the flow to get.
663 * @return the Flow Paths if found, otherwise null.
664 */
665 @Override
666 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
667 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800668 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700669 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800670 }
671
672 /**
673 * Get all installed flows by all installers for given data path endpoints.
674 *
675 * @param dataPathEndpoints the data path endpoints of the flows to get.
676 * @return the Flow Paths if found, otherwise null.
677 */
678 @Override
679 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800680 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
681 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800682 }
683
684 /**
admin944ef4f2013-10-08 17:48:37 -0700685 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700686 *
admin944ef4f2013-10-08 17:48:37 -0700687 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700688 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700689 * @return the Flow Paths if found, otherwise null.
690 */
691 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700692 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
693 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800694 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700695 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700696 }
697
698 /**
admin944ef4f2013-10-08 17:48:37 -0700699 * Get all Flows information, without the associated Flow Entries.
700 *
701 * @return all Flows information, without the associated Flow Entries.
702 */
703 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800704 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandlerApi);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700705 }
706
707 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700708 * Add and maintain a shortest-path flow.
709 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700710 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700711 *
712 * @param flowPath the Flow Path with the endpoints and the match
713 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700714 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700715 */
716 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700717 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700718 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000719 // Don't do the shortest path computation here.
720 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700721 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700722
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700723 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700724 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700725 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700726
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700727 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700728 }
729
730 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800731 * Get the collection of my switches.
732 *
733 * @return the collection of my switches.
734 */
735 public Map<Long, IOFSwitch> getMySwitches() {
736 return floodlightProvider.getSwitches();
737 }
738
739 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800740 * Get the network topology.
741 *
742 * @return the network topology.
743 */
744 public Topology getTopology() {
745 return flowEventHandler.getTopology();
746 }
747
748 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700749 * Reconcile a flow.
750 *
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800751 * @param flowObj the flow that needs to be reconciled.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700752 * @param newDataPath the new data path to use.
753 * @return true on success, otherwise false.
754 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700755 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700756 String flowIdStr = flowObj.getFlowId();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700757
758 //
759 // Set the incoming port matching and the outgoing port output
760 // actions for each flow entry.
761 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700762 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700763 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700764 flowEntry.setFlowId(new FlowId(flowIdStr));
765
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700766 // Mark the Flow Entry as not updated in the switch
767 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700768 // Set the incoming port matching
769 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
770 flowEntry.setFlowEntryMatch(flowEntryMatch);
771 flowEntryMatch.enableInPort(flowEntry.inPort());
772
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700773 //
774 // Set the actions
775 //
776 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
777 //
778 // If the first Flow Entry, copy the Flow Path actions to it
779 //
780 if (idx == 0) {
781 String actionsStr = flowObj.getActions();
782 if (actionsStr != null) {
783 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
784 for (FlowEntryAction action : flowActions.actions())
785 flowEntryActions.addAction(action);
786 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700787 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700788 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700789 //
790 // Add the outgoing port output action
791 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700792 FlowEntryAction flowEntryAction = new FlowEntryAction();
793 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700794 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700795 }
796
797 //
798 // Remove the old Flow Entries, and add the new Flow Entries
799 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700800 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700801 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700802 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700803 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700804 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700805 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700806 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700807 }
808
809 //
810 // Set the Data Path Summary
811 //
812 String dataPathSummaryStr = newDataPath.dataPathSummary();
813 flowObj.setDataPathSummary(dataPathSummaryStr);
814
815 return true;
816 }
817
818 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700819 * Reconcile all flows in a set.
820 *
821 * @param flowObjSet the set of flows that need to be reconciliated.
822 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700823 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700824 if (! flowObjSet.iterator().hasNext())
825 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700826 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700827 }
828
829 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700830 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700831 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700832 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700833 * @param flowObj the flow path object for the flow entry to install.
834 * @param flowEntryObj the flow entry object to install.
835 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700836 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700837 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700838 IFlowEntry flowEntryObj) {
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800839 return pusher.add(mySwitch, flowObj, flowEntryObj);
Naoki Shiota36e89432013-11-13 11:11:43 -0800840
841// LEGACY
842// return FlowSwitchOperation.installFlowEntry(
843// floodlightProvider.getOFMessageFactory(),
844// messageDamper, mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700845 }
846
847 /**
848 * Install a Flow Entry on a switch.
849 *
850 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700851 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700852 * @param flowEntry the flow entry to install.
853 * @return true on success, otherwise false.
854 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700855 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700856 FlowEntry flowEntry) {
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800857 return pusher.add(mySwitch, flowPath, flowEntry);
Naoki Shiota36e89432013-11-13 11:11:43 -0800858
859// LEGACY
860// return FlowSwitchOperation.installFlowEntry(
861// floodlightProvider.getOFMessageFactory(),
862// messageDamper, mySwitch, flowPath, flowEntry);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700863 }
864
865 /**
866 * Remove a Flow Entry from a switch.
867 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700868 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700869 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700870 * @param flowEntry the flow entry to remove.
871 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700872 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700873 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700874 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700875 //
876 // The installFlowEntry() method implements both installation
877 // and removal of flow entries.
878 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700879 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700880 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700881
882 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800883 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700884 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800885 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700886 * are pushed.
887 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800888 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700889 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800890 public void pushModifiedFlowEntriesToSwitches(
891 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700892 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800893 if (! enableNotifications)
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700894 return;
895
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800896 if (modifiedFlowEntries.isEmpty())
897 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700898
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800899 Map<Long, IOFSwitch> mySwitches = getMySwitches();
900
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800901 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
902 FlowPath flowPath = flowPair.flowPath;
903 FlowEntry flowEntry = flowPair.flowEntry;
904
905 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
906 if (mySwitch == null)
907 continue;
908
909 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
910
911 //
912 // Install the Flow Entry into the switch
913 //
914 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
915 String logMsg = "Cannot install Flow Entry " +
916 flowEntry.flowEntryId() +
917 " from Flow Path " + flowPath.flowId() +
918 " on switch " + flowEntry.dpid();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700919 log.error(logMsg);
920 continue;
921 }
922
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800923 //
924 // NOTE: Here we assume that the switch has been
925 // successfully updated.
926 //
927 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
928 }
929 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700930
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800931 /**
932 * Push modified Flow Entries to the datagrid.
933 *
934 * @param modifiedFlowEntries the collection of modified Flow Entries.
935 */
936 public void pushModifiedFlowEntriesToDatagrid(
937 Collection<FlowPathEntryPair> modifiedFlowEntries) {
938 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800939 if (! enableNotifications)
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800940 return;
941
942 if (modifiedFlowEntries.isEmpty())
943 return;
944
945 Map<Long, IOFSwitch> mySwitches = getMySwitches();
946
947 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
948 FlowEntry flowEntry = flowPair.flowEntry;
949
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800950 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
951
952 //
953 // TODO: For now Flow Entries are removed by all instances,
954 // even if this Flow Entry is not for our switches.
955 //
956 // This is needed to handle the case a switch going down:
957 // it has no Master controller instance, hence no
958 // controller instance will cleanup its flow entries.
959 // This is sub-optimal: we need to elect a controller
960 // instance to handle the cleanup of such orphaned flow
961 // entries.
962 //
963 if (mySwitch == null) {
964 if (flowEntry.flowEntryUserState() !=
965 FlowEntryUserState.FE_USER_DELETE) {
966 continue;
967 }
968 if (! flowEntry.isValidFlowEntryId())
969 continue;
970 }
971
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800972 log.debug("Pushing Flow Entry To Datagrid: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800973 //
974 // Write the Flow Entry to the Datagrid
975 //
976 switch (flowEntry.flowEntryUserState()) {
977 case FE_USER_ADD:
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700978 if (mySwitch == null)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800979 break; // Install only flow entries for my switches
980 datagridService.notificationSendFlowEntryAdded(flowEntry);
981 break;
982 case FE_USER_MODIFY:
983 if (mySwitch == null)
984 break; // Install only flow entries for my switches
985 datagridService.notificationSendFlowEntryUpdated(flowEntry);
986 break;
987 case FE_USER_DELETE:
988 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
989 break;
990 }
991 }
992 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700993
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800994 /**
995 * Push Flow Entries to the Network MAP.
996 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800997 * NOTE: The Flow Entries are pushed only on the instance responsible
998 * for the first switch. This is to avoid database errors when multiple
999 * instances are writing Flow Entries for the same Flow Path.
1000 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001001 * @param modifiedFlowEntries the collection of Flow Entries to push.
1002 */
1003 public void pushModifiedFlowEntriesToDatabase(
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001004 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001005 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -08001006 if (! enableNotifications)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001007 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001008
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001009 if (modifiedFlowEntries.isEmpty())
1010 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001011
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001012 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001013
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001014 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
1015 FlowPath flowPath = flowPair.flowPath;
1016 FlowEntry flowEntry = flowPair.flowEntry;
1017
1018 if (! flowEntry.isValidFlowEntryId())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001019 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001020
1021 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001022 // Push the changes only on the instance responsible for the
1023 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001024 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001025 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
1026 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
1027 if (mySrcSwitch == null)
1028 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001029
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001030 log.debug("Pushing Flow Entry To Database: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001031 //
1032 // Write the Flow Entry to the Network Map
1033 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001034 // NOTE: We try a number of times, in case somehow some other
1035 // instances are writing at the same time.
1036 // Apparently, if other instances are writing at the same time
1037 // this will trigger an error.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001038 //
1039 for (int i = 0; i < 6; i++) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001040 try {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001041 //
1042 // Find the Flow Path in the Network MAP.
1043 //
1044 // NOTE: The Flow Path might not be found if the Flow was
1045 // just removed by some other controller instance.
1046 //
1047 IFlowPath flowObj =
1048 dbHandlerInner.searchFlowPath(flowEntry.flowId());
1049 if (flowObj == null) {
1050 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001051 log.error(logMsg);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001052 break;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001053 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001054
1055 // Write the Flow Entry
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001056 switch (flowEntry.flowEntryUserState()) {
1057 case FE_USER_ADD:
1058 // FALLTHROUGH
1059 case FE_USER_MODIFY:
1060 if (addFlowEntry(flowObj, flowEntry) == null) {
1061 String logMsg = "Cannot write to Network MAP Flow Entry " +
1062 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001063 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001064 " on switch " + flowEntry.dpid();
1065 log.error(logMsg);
1066 }
1067 break;
1068 case FE_USER_DELETE:
1069 if (deleteFlowEntry(flowObj, flowEntry) == false) {
1070 String logMsg = "Cannot remove from Network MAP Flow Entry " +
1071 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001072 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001073 " on switch " + flowEntry.dpid();
1074 log.error(logMsg);
1075 }
1076 break;
1077 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001078
1079 // Commit to the database
1080 dbHandlerInner.commit();
1081 break; // Success
1082
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001083 } catch (Exception e) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -08001084 log.debug("Exception writing Flow Entry to Network MAP: ", e);
1085 dbHandlerInner.rollback();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001086 // Wait a bit (random value [1ms, 20ms] and try again
1087 int delay = 1 + randomGenerator.nextInt() % 20;
1088 try {
1089 Thread.sleep(delay);
1090 } catch (Exception e0) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001091 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001092 }
1093 }
1094 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001095 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001096}