blob: e239ae918dc1966a2ed987b206acdb0e1a31897d [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;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -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 Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.concurrent.Executors;
11import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080012import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080013
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080016import net.floodlightcontroller.core.module.FloodlightModuleContext;
17import net.floodlightcontroller.core.module.FloodlightModuleException;
18import net.floodlightcontroller.core.module.IFloodlightModule;
19import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.util.OFMessageDamper;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070022
23import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070024import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070025import net.onrc.onos.ofcontroller.core.INetMapStorage;
26import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
27import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070028import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070029import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070030import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070031import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -070032import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070033import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080034
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080035import org.openflow.protocol.OFType;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
admin944ef4f2013-10-08 17:48:37 -070039/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070040 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070041 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070042public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -080044 //
45 // TODO: A temporary variable to switch between the poll-based and
46 // notification mechanism for the Flow Manager.
47 //
48 private final static boolean enableNotifications = false;
49
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080050 protected GraphDBOperation dbHandlerApi;
51 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080052
Jonathan Hart50a94982013-04-10 14:49:51 -070053 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070054 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070055 protected volatile IDatagridService datagridService;
56 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070057 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070058 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080059
60 protected OFMessageDamper messageDamper;
61
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070062 //
63 // TODO: Values copied from elsewhere (class LearningSwitch).
64 // The local copy should go away!
65 //
66 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
67 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080068
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000069 // Flow Entry ID generation state
70 private static Random randomGenerator = new Random();
71 private static int nextFlowEntryIdPrefix = 0;
72 private static int nextFlowEntryIdSuffix = 0;
73 private static long nextFlowEntryId = 0;
74
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080075 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070076 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080077
78 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070079 private ScheduledExecutorService mapReaderScheduler;
80 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -070081
admin944ef4f2013-10-08 17:48:37 -070082 /**
83 * Periodic task for reading the Flow Entries and pushing changes
84 * into the switches.
85 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070086 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080087 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070088 try {
89 runImpl();
90 } catch (Exception e) {
91 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080092 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070093 return;
94 }
95 }
96
97 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070098 long startTime = System.nanoTime();
99 int counterAllFlowEntries = 0;
100 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700101
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800102 if (floodlightProvider == null) {
103 log.debug("FloodlightProvider service not found!");
104 return;
105 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000106 Map<Long, IOFSwitch> mySwitches =
107 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700108 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700109 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700110 return;
111 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700112 LinkedList<IFlowEntry> addFlowEntries =
113 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000114 LinkedList<IFlowEntry> deleteFlowEntries =
115 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700116
117 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700118 // Fetch all Flow Entries which need to be updated and select
119 // only my Flow Entries that need to be updated into the
120 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700121 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000122 Iterable<IFlowEntry> allFlowEntries =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800123 dbHandlerInner.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700124 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700125 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000126
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000127 String dpidStr = flowEntryObj.getSwitchDpid();
128 if (dpidStr == null)
129 continue;
130 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800131 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000132 if (mySwitch == null)
133 continue; // Ignore the entry: not my switch
134
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700135 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800136 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700137 if (flowObj == null)
138 continue; // Should NOT happen
139 if (flowObj.getFlowId() == null)
140 continue; // Invalid entry
141
142 //
143 // NOTE: For now we process the DELETE before the ADD
144 // to cover the more common scenario.
145 // TODO: This is error prone and needs to be fixed!
146 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000147 String userState = flowEntryObj.getUserState();
148 if (userState == null)
149 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700150 if (userState.equals("FE_USER_DELETE")) {
151 // An entry that needs to be deleted.
152 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700153 installFlowEntry(mySwitch, flowObj, flowEntryObj);
154 } else {
155 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700156 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700157 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700158 }
159
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700160 //
161 // Process the Flow Entries that need to be added
162 //
163 for (IFlowEntry flowEntryObj : addFlowEntries) {
164 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800165 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700166 if (flowObj == null)
167 continue; // Should NOT happen
168 if (flowObj.getFlowId() == null)
169 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700170
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700171 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700172 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000173 if (mySwitch == null)
174 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700175 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800176 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000177
178 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000179 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700180 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000181 //
182 // TODO: We should use the OpenFlow Barrier mechanism
183 // to check for errors, and delete the Flow Entries after the
184 // Barrier message is received.
185 //
186 while (! deleteFlowEntries.isEmpty()) {
187 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
188 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800189 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000190 if (flowObj == null) {
191 log.debug("Did not find FlowPath to be deleted");
192 continue;
193 }
194 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800195 dbHandlerInner.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000196 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700197
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800198 dbHandlerInner.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700199
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700200 long estimatedTime = System.nanoTime() - startTime;
201 double rate = 0.0;
202 if (estimatedTime > 0)
203 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
204 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
205 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
206 counterMyNotUpdatedFlowEntries + " in " +
207 (double)estimatedTime / 1000000000 + " sec: " +
208 rate + " paths/s";
209 log.debug(logMsg);
210 }
211 };
212
admin944ef4f2013-10-08 17:48:37 -0700213 /**
214 * Periodic task for reading the Flow Paths and recomputing the
215 * shortest paths.
216 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700217 final Runnable shortestPathReconcile = new Runnable() {
218 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700219 try {
220 runImpl();
221 } catch (Exception e) {
222 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800223 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700224 return;
225 }
226 }
227
228 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700229 long startTime = System.nanoTime();
230 int counterAllFlowPaths = 0;
231 int counterMyFlowPaths = 0;
232
233 if (floodlightProvider == null) {
234 log.debug("FloodlightProvider service not found!");
235 return;
236 }
237 Map<Long, IOFSwitch> mySwitches =
238 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700239 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700240 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700241 return;
242 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700243 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
244
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700245 //
246 // Fetch and recompute the Shortest Path for those
247 // Flow Paths this controller is responsible for.
248 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700249 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800250 Iterable<IFlowPath> allFlowPaths = dbHandlerInner.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700251 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700252 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700253 if (flowPathObj == null)
254 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700255
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700256 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000257 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700258 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700259 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700260 //
261 // Use the source DPID as a heuristic to decide
262 // which controller is responsible for maintaining the
263 // shortest path.
264 // NOTE: This heuristic is error-prone: if the switch
265 // goes away and no controller is responsible for that
266 // switch, then the original Flow Path is not cleaned-up
267 //
268 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
269 if (mySwitch == null)
270 continue; // Ignore: not my responsibility
271
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700272 // Test whether we need to maintain this flow
273 String flowPathTypeStr = flowPathObj.getFlowPathType();
274 if (flowPathTypeStr == null)
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700275 continue; // Could be invalid entry?
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700276 if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700277 continue; // No need to maintain this flow
278
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000279 //
280 // Test whether we need to complete the Flow cleanup,
281 // if the Flow has been deleted by the user.
282 //
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700283 String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
284 if ((flowPathUserStateStr != null)
285 && flowPathUserStateStr.equals("FP_USER_DELETE")) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000286 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700287 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000288 if (empty)
289 deleteFlows.add(flowPathObj);
290 }
291
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000292 // Fetch the fields needed to recompute the shortest path
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700293 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000294 Short srcPortShort = flowPathObj.getSrcPort();
295 String dstDpidStr = flowPathObj.getDstSwitch();
296 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700297 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700298 if ((dataPathSummaryStr == null) ||
299 (srcPortShort == null) ||
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000300 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700301 (dstPortShort == null) ||
302 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000303 continue;
304 }
305
306 Port srcPort = new Port(srcPortShort);
307 Dpid dstDpid = new Dpid(dstDpidStr);
308 Port dstPort = new Port(dstPortShort);
309 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
310 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700311 FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700312 FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700313 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000314
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700315 counterMyFlowPaths++;
316
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700317 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700318 // NOTE: Using here the regular getDatabaseShortestPath()
319 // method won't work here, because that method calls
320 // internally "conn.endTx(Transaction.COMMIT)", and that
321 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700322 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700323 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700324 // to avoid closing the transaction.
325 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700326 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700327 topologyNetService.getTopologyShortestPath(
328 topology,
329 srcSwitchPort,
330 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000331 if (dataPath == null) {
332 // We need the DataPath to compare the paths
333 dataPath = new DataPath();
334 dataPath.setSrcPort(srcSwitchPort);
335 dataPath.setDstPort(dstSwitchPort);
336 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700337 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000338
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700339 String newDataPathSummaryStr = dataPath.dataPathSummary();
340 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
341 continue; // Nothing changed
342
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700343 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700344 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000345
346 //
347 // Delete all leftover Flows marked for deletion from the
348 // Network MAP.
349 //
350 while (! deleteFlows.isEmpty()) {
351 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800352 dbHandlerInner.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000353 }
354
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700355 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700356
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800357 dbHandlerInner.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700358
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700359 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700360 double rate = 0.0;
361 if (estimatedTime > 0)
362 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700363 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700364 counterAllFlowPaths + " MyFlowPaths: " +
365 counterMyFlowPaths + " in " +
366 (double)estimatedTime / 1000000000 + " sec: " +
367 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700368 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800369 }
370 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700371
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800372
admin944ef4f2013-10-08 17:48:37 -0700373 /**
374 * Initialize the Flow Manager.
375 *
376 * @param conf the Graph Database configuration string.
377 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800378 @Override
379 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800380 dbHandlerApi = new GraphDBOperation(conf);
381 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800382 }
383
admin944ef4f2013-10-08 17:48:37 -0700384 /**
385 * Shutdown the Flow Manager operation.
386 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800387 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700388 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800389 }
390
admin944ef4f2013-10-08 17:48:37 -0700391 /**
392 * Shutdown the Flow Manager operation.
393 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800394 @Override
395 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700396 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800397 dbHandlerApi.close();
398 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800399 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800400
admin944ef4f2013-10-08 17:48:37 -0700401 /**
402 * Get the collection of offered module services.
403 *
404 * @return the collection of offered module services.
405 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800406 @Override
407 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
408 Collection<Class<? extends IFloodlightService>> l =
409 new ArrayList<Class<? extends IFloodlightService>>();
410 l.add(IFlowService.class);
411 return l;
412 }
413
admin944ef4f2013-10-08 17:48:37 -0700414 /**
415 * Get the collection of implemented services.
416 *
417 * @return the collection of implemented services.
418 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800419 @Override
420 public Map<Class<? extends IFloodlightService>, IFloodlightService>
421 getServiceImpls() {
422 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700423 IFloodlightService> m =
424 new HashMap<Class<? extends IFloodlightService>,
425 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800426 m.put(IFlowService.class, this);
427 return m;
428 }
429
admin944ef4f2013-10-08 17:48:37 -0700430 /**
431 * Get the collection of modules this module depends on.
432 *
433 * @return the collection of modules this module depends on.
434 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800435 @Override
436 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700437 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800438 Collection<Class<? extends IFloodlightService>> l =
439 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800440 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700441 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700442 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800443 l.add(IRestApiService.class);
444 return l;
445 }
446
admin944ef4f2013-10-08 17:48:37 -0700447 /**
448 * Initialize the module.
449 *
450 * @param context the module context to use for the initialization.
451 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800452 @Override
453 public void init(FloodlightModuleContext context)
454 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700455 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800456 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700457 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
458 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800459 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700460
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800461 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
462 EnumSet.of(OFType.FLOW_MOD),
463 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700464
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700465 this.init("");
466
admin944ef4f2013-10-08 17:48:37 -0700467 mapReaderScheduler = Executors.newScheduledThreadPool(1);
468 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800469 }
470
admin944ef4f2013-10-08 17:48:37 -0700471 /**
472 * Get the next Flow Entry ID to use.
473 *
474 * @return the next Flow Entry ID to use.
475 */
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700476 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000477 //
478 // Generate the next Flow Entry ID.
479 // NOTE: For now, the higher 32 bits are random, and
480 // the lower 32 bits are sequential.
481 // In the future, we need a better allocation mechanism.
482 //
483 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
484 nextFlowEntryIdPrefix = randomGenerator.nextInt();
485 nextFlowEntryIdSuffix = 0;
486 } else {
487 nextFlowEntryIdSuffix++;
488 }
489 long result = (long)nextFlowEntryIdPrefix << 32;
490 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
491 return result;
492 }
493
admin944ef4f2013-10-08 17:48:37 -0700494 /**
495 * Startup module operation.
496 *
497 * @param context the module context to use for the startup.
498 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800499 @Override
500 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700501 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700502
admin944ef4f2013-10-08 17:48:37 -0700503 // Initialize the Flow Entry ID generator
504 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700505
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700506 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700507 // Create the Flow Event Handler thread and register it with the
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700508 // Datagrid Service
509 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700510 flowEventHandler = new FlowEventHandler(this, datagridService);
511 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -0700512
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700513 // Schedule the threads and periodic tasks
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700514 flowEventHandler.start();
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800515 if (! enableNotifications) {
516 mapReaderScheduler.scheduleAtFixedRate(
admin944ef4f2013-10-08 17:48:37 -0700517 mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800518 shortestPathReconcileScheduler.scheduleAtFixedRate(
admin944ef4f2013-10-08 17:48:37 -0700519 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800520 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800521 }
522
523 /**
524 * Add a flow.
525 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800526 * @param flowPath the Flow Path to install.
527 * @param flowId the return-by-reference Flow ID as assigned internally.
528 * @return true on success, otherwise false.
529 */
530 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700531 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700532 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700533 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700534 // in case the application didn't do it.
535 //
536 for (FlowEntry flowEntry : flowPath.flowEntries()) {
537 if (flowEntry.flowEntrySwitchState() ==
538 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
539 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
540 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700541 if (! flowEntry.isValidFlowId())
542 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700543 }
544
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800545 if (FlowDatabaseOperation.addFlow(this, dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700546 datagridService.notificationSendFlowAdded(flowPath);
547 return true;
548 }
549 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800550 }
551
552 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700553 * Add a flow entry to the Network MAP.
554 *
555 * @param flowObj the corresponding Flow Path object for the Flow Entry.
556 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700557 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700558 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700559 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800560 return FlowDatabaseOperation.addFlowEntry(this, dbHandlerInner,
561 flowObj, flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700562 }
563
564 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700565 * Delete a flow entry from the Network MAP.
566 *
567 * @param flowObj the corresponding Flow Path object for the Flow Entry.
568 * @param flowEntry the Flow Entry to delete.
569 * @return true on success, otherwise false.
570 */
571 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800572 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
573 flowObj, flowEntry);
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700574 }
575
576 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000577 * Delete all previously added flows.
578 *
579 * @return true on success, otherwise false.
580 */
581 @Override
582 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800583 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700584 datagridService.notificationSendAllFlowsRemoved();
585 return true;
586 }
587 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000588 }
589
590 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800591 * Delete a previously added flow.
592 *
593 * @param flowId the Flow ID of the flow to delete.
594 * @return true on success, otherwise false.
595 */
596 @Override
597 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800598 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700599 datagridService.notificationSendFlowRemoved(flowId);
600 return true;
601 }
602 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800603 }
604
605 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000606 * Clear the state for all previously added flows.
607 *
608 * @return true on success, otherwise false.
609 */
610 @Override
611 public boolean clearAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800612 if (FlowDatabaseOperation.clearAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700613 datagridService.notificationSendAllFlowsRemoved();
614 return true;
615 }
616 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000617 }
618
619 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700620 * Clear the state for a previously added flow.
621 *
622 * @param flowId the Flow ID of the flow to clear.
623 * @return true on success, otherwise false.
624 */
625 @Override
626 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800627 if (FlowDatabaseOperation.clearFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700628 datagridService.notificationSendFlowRemoved(flowId);
629 return true;
630 }
631 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700632 }
633
634 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800635 * Get a previously added flow.
636 *
637 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800638 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800639 */
640 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800641 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800642 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700643 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800644
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700645 /**
646 * Get all installed flows by all installers.
647 *
648 * @return the Flow Paths if found, otherwise null.
649 */
650 @Override
651 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800652 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800653 }
654
655 /**
656 * Get all previously added flows by a specific installer for a given
657 * data path endpoints.
658 *
659 * @param installerId the Caller ID of the installer of the flow to get.
660 * @param dataPathEndpoints the data path endpoints of the flow to get.
661 * @return the Flow Paths if found, otherwise null.
662 */
663 @Override
664 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
665 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800666 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700667 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800668 }
669
670 /**
671 * Get all installed flows by all installers for given data path endpoints.
672 *
673 * @param dataPathEndpoints the data path endpoints of the flows to get.
674 * @return the Flow Paths if found, otherwise null.
675 */
676 @Override
677 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800678 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
679 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800680 }
681
682 /**
admin944ef4f2013-10-08 17:48:37 -0700683 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700684 *
admin944ef4f2013-10-08 17:48:37 -0700685 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700686 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700687 * @return the Flow Paths if found, otherwise null.
688 */
689 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700690 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
691 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800692 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700693 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700694 }
695
696 /**
admin944ef4f2013-10-08 17:48:37 -0700697 * Get all Flows information, without the associated Flow Entries.
698 *
699 * @return all Flows information, without the associated Flow Entries.
700 */
701 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800702 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandlerApi);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700703 }
704
705 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700706 * Add and maintain a shortest-path flow.
707 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700708 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700709 *
710 * @param flowPath the Flow Path with the endpoints and the match
711 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700712 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700713 */
714 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700715 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700716 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000717 // Don't do the shortest path computation here.
718 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700719 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700720
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700721 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700722 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700723 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700724
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700725 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700726 }
727
728 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800729 * Get the collection of my switches.
730 *
731 * @return the collection of my switches.
732 */
733 public Map<Long, IOFSwitch> getMySwitches() {
734 return floodlightProvider.getSwitches();
735 }
736
737 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800738 * Get the network topology.
739 *
740 * @return the network topology.
741 */
742 public Topology getTopology() {
743 return flowEventHandler.getTopology();
744 }
745
746 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700747 * Reconcile a flow.
748 *
749 * @param flowObj the flow that needs to be reconciliated.
750 * @param newDataPath the new data path to use.
751 * @return true on success, otherwise false.
752 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700753 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700754 String flowIdStr = flowObj.getFlowId();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700755
756 //
757 // Set the incoming port matching and the outgoing port output
758 // actions for each flow entry.
759 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700760 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700761 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700762 flowEntry.setFlowId(new FlowId(flowIdStr));
763
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700764 // Mark the Flow Entry as not updated in the switch
765 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700766 // Set the incoming port matching
767 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
768 flowEntry.setFlowEntryMatch(flowEntryMatch);
769 flowEntryMatch.enableInPort(flowEntry.inPort());
770
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700771 //
772 // Set the actions
773 //
774 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
775 //
776 // If the first Flow Entry, copy the Flow Path actions to it
777 //
778 if (idx == 0) {
779 String actionsStr = flowObj.getActions();
780 if (actionsStr != null) {
781 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
782 for (FlowEntryAction action : flowActions.actions())
783 flowEntryActions.addAction(action);
784 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700785 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700786 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700787 //
788 // Add the outgoing port output action
789 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700790 FlowEntryAction flowEntryAction = new FlowEntryAction();
791 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700792 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700793 }
794
795 //
796 // Remove the old Flow Entries, and add the new Flow Entries
797 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700798 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700799 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700800 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700801 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700802 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700803 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700804 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700805 }
806
807 //
808 // Set the Data Path Summary
809 //
810 String dataPathSummaryStr = newDataPath.dataPathSummary();
811 flowObj.setDataPathSummary(dataPathSummaryStr);
812
813 return true;
814 }
815
816 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700817 * Reconcile all flows in a set.
818 *
819 * @param flowObjSet the set of flows that need to be reconciliated.
820 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700821 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700822 if (! flowObjSet.iterator().hasNext())
823 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700824 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700825 }
826
827 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700828 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700829 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700830 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700831 * @param flowObj the flow path object for the flow entry to install.
832 * @param flowEntryObj the flow entry object to install.
833 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700834 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700835 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700836 IFlowEntry flowEntryObj) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700837 return FlowSwitchOperation.installFlowEntry(
838 floodlightProvider.getOFMessageFactory(),
839 messageDamper, mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700840 }
841
842 /**
843 * Install a Flow Entry on a switch.
844 *
845 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700846 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700847 * @param flowEntry the flow entry to install.
848 * @return true on success, otherwise false.
849 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700850 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700851 FlowEntry flowEntry) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700852 return FlowSwitchOperation.installFlowEntry(
853 floodlightProvider.getOFMessageFactory(),
854 messageDamper, mySwitch, flowPath, flowEntry);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700855 }
856
857 /**
858 * Remove a Flow Entry from a switch.
859 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700860 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700861 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700862 * @param flowEntry the flow entry to remove.
863 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700864 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700865 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700866 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700867 //
868 // The installFlowEntry() method implements both installation
869 // and removal of flow entries.
870 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700871 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700872 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700873
874 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800875 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700876 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800877 * NOTE: Only the Flow Entries to switches controlled by this instance
878 * are pushed.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700879 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800880 * @param modifiedFlowEntries the collection of modified Flow Entries.
881 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800882 public void pushModifiedFlowEntriesToSwitches(
883 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800884 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800885 if (! enableNotifications)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800886 return;
887
888 if (modifiedFlowEntries.isEmpty())
889 return;
890
891 Map<Long, IOFSwitch> mySwitches = getMySwitches();
892
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800893 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
894 FlowPath flowPath = flowPair.flowPath;
895 FlowEntry flowEntry = flowPair.flowEntry;
896
897 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
898 if (mySwitch == null)
899 continue;
900
901 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
902
903 //
904 // Install the Flow Entry into the switch
905 //
906 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
907 String logMsg = "Cannot install Flow Entry " +
908 flowEntry.flowEntryId() +
909 " from Flow Path " + flowPath.flowId() +
910 " on switch " + flowEntry.dpid();
911 log.error(logMsg);
912 continue;
913 }
914
915 //
916 // NOTE: Here we assume that the switch has been
917 // successfully updated.
918 //
919 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
920 }
921 }
922
923 /**
924 * Push modified Flow Entries to the datagrid.
925 *
926 * @param modifiedFlowEntries the collection of modified Flow Entries.
927 */
928 public void pushModifiedFlowEntriesToDatagrid(
929 Collection<FlowPathEntryPair> modifiedFlowEntries) {
930 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800931 if (! enableNotifications)
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800932 return;
933
934 if (modifiedFlowEntries.isEmpty())
935 return;
936
937 Map<Long, IOFSwitch> mySwitches = getMySwitches();
938
939 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
940 FlowEntry flowEntry = flowPair.flowEntry;
941
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800942 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
943
944 //
945 // TODO: For now Flow Entries are removed by all instances,
946 // even if this Flow Entry is not for our switches.
947 //
948 // This is needed to handle the case a switch going down:
949 // it has no Master controller instance, hence no
950 // controller instance will cleanup its flow entries.
951 // This is sub-optimal: we need to elect a controller
952 // instance to handle the cleanup of such orphaned flow
953 // entries.
954 //
955 if (mySwitch == null) {
956 if (flowEntry.flowEntryUserState() !=
957 FlowEntryUserState.FE_USER_DELETE) {
958 continue;
959 }
960 if (! flowEntry.isValidFlowEntryId())
961 continue;
962 }
963
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800964 log.debug("Pushing Flow Entry To Datagrid: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800965 //
966 // Write the Flow Entry to the Datagrid
967 //
968 switch (flowEntry.flowEntryUserState()) {
969 case FE_USER_ADD:
970 if (mySwitch == null)
971 break; // Install only flow entries for my switches
972 datagridService.notificationSendFlowEntryAdded(flowEntry);
973 break;
974 case FE_USER_MODIFY:
975 if (mySwitch == null)
976 break; // Install only flow entries for my switches
977 datagridService.notificationSendFlowEntryUpdated(flowEntry);
978 break;
979 case FE_USER_DELETE:
980 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
981 break;
982 }
983 }
984 }
985
986 /**
987 * Push Flow Entries to the Network MAP.
988 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800989 * NOTE: The Flow Entries are pushed only on the instance responsible
990 * for the first switch. This is to avoid database errors when multiple
991 * instances are writing Flow Entries for the same Flow Path.
992 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800993 * @param modifiedFlowEntries the collection of Flow Entries to push.
994 */
995 public void pushModifiedFlowEntriesToDatabase(
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800996 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800997 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800998 if (! enableNotifications)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800999 return;
1000
1001 if (modifiedFlowEntries.isEmpty())
1002 return;
1003
1004 Map<Long, IOFSwitch> mySwitches = getMySwitches();
1005
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001006 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
1007 FlowPath flowPath = flowPair.flowPath;
1008 FlowEntry flowEntry = flowPair.flowEntry;
1009
1010 if (! flowEntry.isValidFlowEntryId())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001011 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001012
1013 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001014 // Push the changes only on the instance responsible for the
1015 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001016 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001017 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
1018 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
1019 if (mySrcSwitch == null)
1020 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001021
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001022 log.debug("Pushing Flow Entry To Database: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001023 //
1024 // Write the Flow Entry to the Network Map
1025 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001026 // NOTE: We try a number of times, in case somehow some other
1027 // instances are writing at the same time.
1028 // Apparently, if other instances are writing at the same time
1029 // this will trigger an error.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001030 //
1031 for (int i = 0; i < 6; i++) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001032 try {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001033 //
1034 // Find the Flow Path in the Network MAP.
1035 //
1036 // NOTE: The Flow Path might not be found if the Flow was
1037 // just removed by some other controller instance.
1038 //
1039 IFlowPath flowObj =
1040 dbHandlerInner.searchFlowPath(flowEntry.flowId());
1041 if (flowObj == null) {
1042 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
1043 log.error(logMsg);
1044 break;
1045 }
1046
1047 // Write the Flow Entry
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001048 switch (flowEntry.flowEntryUserState()) {
1049 case FE_USER_ADD:
1050 // FALLTHROUGH
1051 case FE_USER_MODIFY:
1052 if (addFlowEntry(flowObj, flowEntry) == null) {
1053 String logMsg = "Cannot write to Network MAP Flow Entry " +
1054 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001055 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001056 " on switch " + flowEntry.dpid();
1057 log.error(logMsg);
1058 }
1059 break;
1060 case FE_USER_DELETE:
1061 if (deleteFlowEntry(flowObj, flowEntry) == false) {
1062 String logMsg = "Cannot remove from Network MAP Flow Entry " +
1063 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001064 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001065 " on switch " + flowEntry.dpid();
1066 log.error(logMsg);
1067 }
1068 break;
1069 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001070
1071 // Commit to the database
1072 dbHandlerInner.commit();
1073 break; // Success
1074
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001075 } catch (Exception e) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -08001076 log.debug("Exception writing Flow Entry to Network MAP: ", e);
1077 dbHandlerInner.rollback();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001078 // Wait a bit (random value [1ms, 20ms] and try again
1079 int delay = 1 + randomGenerator.nextInt() % 20;
1080 try {
1081 Thread.sleep(delay);
1082 } catch (Exception e0) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001083 }
1084 }
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001085 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001086 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001087 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001088}