blob: 98f9cceeb21546b86d15058cb6a861374c74ed37 [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 Radoslavovbc96ae12013-11-05 08:44:02 -080044 protected GraphDBOperation dbHandlerApi;
45 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080046
Jonathan Hart50a94982013-04-10 14:49:51 -070047 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070048 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070049 protected volatile IDatagridService datagridService;
50 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070051 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070052 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080053
54 protected OFMessageDamper messageDamper;
55
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070056 //
57 // TODO: Values copied from elsewhere (class LearningSwitch).
58 // The local copy should go away!
59 //
60 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
61 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080062
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000063 // Flow Entry ID generation state
64 private static Random randomGenerator = new Random();
65 private static int nextFlowEntryIdPrefix = 0;
66 private static int nextFlowEntryIdSuffix = 0;
67 private static long nextFlowEntryId = 0;
68
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080069 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070070 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071
72 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070073 private ScheduledExecutorService mapReaderScheduler;
74 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -070075
admin944ef4f2013-10-08 17:48:37 -070076 /**
77 * Periodic task for reading the Flow Entries and pushing changes
78 * into the switches.
79 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070080 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080081 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070082 try {
83 runImpl();
84 } catch (Exception e) {
85 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080086 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070087 return;
88 }
89 }
90
91 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070092 long startTime = System.nanoTime();
93 int counterAllFlowEntries = 0;
94 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070095
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080096 if (floodlightProvider == null) {
97 log.debug("FloodlightProvider service not found!");
98 return;
99 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000100 Map<Long, IOFSwitch> mySwitches =
101 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700102 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700103 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700104 return;
105 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700106 LinkedList<IFlowEntry> addFlowEntries =
107 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000108 LinkedList<IFlowEntry> deleteFlowEntries =
109 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700110
111 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700112 // Fetch all Flow Entries which need to be updated and select
113 // only my Flow Entries that need to be updated into the
114 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700115 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000116 Iterable<IFlowEntry> allFlowEntries =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800117 dbHandlerInner.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700118 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700119 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000120
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000121 String dpidStr = flowEntryObj.getSwitchDpid();
122 if (dpidStr == null)
123 continue;
124 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800125 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000126 if (mySwitch == null)
127 continue; // Ignore the entry: not my switch
128
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700129 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800130 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700131 if (flowObj == null)
132 continue; // Should NOT happen
133 if (flowObj.getFlowId() == null)
134 continue; // Invalid entry
135
136 //
137 // NOTE: For now we process the DELETE before the ADD
138 // to cover the more common scenario.
139 // TODO: This is error prone and needs to be fixed!
140 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000141 String userState = flowEntryObj.getUserState();
142 if (userState == null)
143 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700144 if (userState.equals("FE_USER_DELETE")) {
145 // An entry that needs to be deleted.
146 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700147 installFlowEntry(mySwitch, flowObj, flowEntryObj);
148 } else {
149 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700150 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700151 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700152 }
153
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700154 //
155 // Process the Flow Entries that need to be added
156 //
157 for (IFlowEntry flowEntryObj : addFlowEntries) {
158 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800159 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700160 if (flowObj == null)
161 continue; // Should NOT happen
162 if (flowObj.getFlowId() == null)
163 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700164
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700165 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700166 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000167 if (mySwitch == null)
168 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700169 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800170 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000171
172 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000173 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700174 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000175 //
176 // TODO: We should use the OpenFlow Barrier mechanism
177 // to check for errors, and delete the Flow Entries after the
178 // Barrier message is received.
179 //
180 while (! deleteFlowEntries.isEmpty()) {
181 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
182 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800183 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000184 if (flowObj == null) {
185 log.debug("Did not find FlowPath to be deleted");
186 continue;
187 }
188 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800189 dbHandlerInner.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000190 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700191
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800192 dbHandlerInner.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700193
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700194 long estimatedTime = System.nanoTime() - startTime;
195 double rate = 0.0;
196 if (estimatedTime > 0)
197 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
198 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
199 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
200 counterMyNotUpdatedFlowEntries + " in " +
201 (double)estimatedTime / 1000000000 + " sec: " +
202 rate + " paths/s";
203 log.debug(logMsg);
204 }
205 };
206
admin944ef4f2013-10-08 17:48:37 -0700207 /**
208 * Periodic task for reading the Flow Paths and recomputing the
209 * shortest paths.
210 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700211 final Runnable shortestPathReconcile = new Runnable() {
212 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700213 try {
214 runImpl();
215 } catch (Exception e) {
216 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800217 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700218 return;
219 }
220 }
221
222 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700223 long startTime = System.nanoTime();
224 int counterAllFlowPaths = 0;
225 int counterMyFlowPaths = 0;
226
227 if (floodlightProvider == null) {
228 log.debug("FloodlightProvider service not found!");
229 return;
230 }
231 Map<Long, IOFSwitch> mySwitches =
232 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700233 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700234 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700235 return;
236 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700237 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
238
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700239 //
240 // Fetch and recompute the Shortest Path for those
241 // Flow Paths this controller is responsible for.
242 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700243 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800244 Iterable<IFlowPath> allFlowPaths = dbHandlerInner.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700245 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700246 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700247 if (flowPathObj == null)
248 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700249
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700250 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000251 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700252 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700253 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700254 //
255 // Use the source DPID as a heuristic to decide
256 // which controller is responsible for maintaining the
257 // shortest path.
258 // NOTE: This heuristic is error-prone: if the switch
259 // goes away and no controller is responsible for that
260 // switch, then the original Flow Path is not cleaned-up
261 //
262 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
263 if (mySwitch == null)
264 continue; // Ignore: not my responsibility
265
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700266 // Test whether we need to maintain this flow
267 String flowPathTypeStr = flowPathObj.getFlowPathType();
268 if (flowPathTypeStr == null)
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700269 continue; // Could be invalid entry?
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700270 if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700271 continue; // No need to maintain this flow
272
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000273 //
274 // Test whether we need to complete the Flow cleanup,
275 // if the Flow has been deleted by the user.
276 //
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700277 String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
278 if ((flowPathUserStateStr != null)
279 && flowPathUserStateStr.equals("FP_USER_DELETE")) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000280 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700281 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000282 if (empty)
283 deleteFlows.add(flowPathObj);
284 }
285
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000286 // Fetch the fields needed to recompute the shortest path
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700287 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000288 Short srcPortShort = flowPathObj.getSrcPort();
289 String dstDpidStr = flowPathObj.getDstSwitch();
290 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700291 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700292 if ((dataPathSummaryStr == null) ||
293 (srcPortShort == null) ||
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000294 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700295 (dstPortShort == null) ||
296 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000297 continue;
298 }
299
300 Port srcPort = new Port(srcPortShort);
301 Dpid dstDpid = new Dpid(dstDpidStr);
302 Port dstPort = new Port(dstPortShort);
303 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
304 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700305 FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700306 FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700307 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000308
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700309 counterMyFlowPaths++;
310
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700311 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700312 // NOTE: Using here the regular getDatabaseShortestPath()
313 // method won't work here, because that method calls
314 // internally "conn.endTx(Transaction.COMMIT)", and that
315 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700316 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700317 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700318 // to avoid closing the transaction.
319 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700320 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700321 topologyNetService.getTopologyShortestPath(
322 topology,
323 srcSwitchPort,
324 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000325 if (dataPath == null) {
326 // We need the DataPath to compare the paths
327 dataPath = new DataPath();
328 dataPath.setSrcPort(srcSwitchPort);
329 dataPath.setDstPort(dstSwitchPort);
330 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700331 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000332
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700333 String newDataPathSummaryStr = dataPath.dataPathSummary();
334 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
335 continue; // Nothing changed
336
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700337 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700338 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000339
340 //
341 // Delete all leftover Flows marked for deletion from the
342 // Network MAP.
343 //
344 while (! deleteFlows.isEmpty()) {
345 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800346 dbHandlerInner.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000347 }
348
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700349 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700350
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800351 dbHandlerInner.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700352
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700353 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700354 double rate = 0.0;
355 if (estimatedTime > 0)
356 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700357 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700358 counterAllFlowPaths + " MyFlowPaths: " +
359 counterMyFlowPaths + " in " +
360 (double)estimatedTime / 1000000000 + " sec: " +
361 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700362 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800363 }
364 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700365
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800366
admin944ef4f2013-10-08 17:48:37 -0700367 /**
368 * Initialize the Flow Manager.
369 *
370 * @param conf the Graph Database configuration string.
371 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800372 @Override
373 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800374 dbHandlerApi = new GraphDBOperation(conf);
375 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800376 }
377
admin944ef4f2013-10-08 17:48:37 -0700378 /**
379 * Shutdown the Flow Manager operation.
380 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800381 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700382 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800383 }
384
admin944ef4f2013-10-08 17:48:37 -0700385 /**
386 * Shutdown the Flow Manager operation.
387 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800388 @Override
389 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700390 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800391 dbHandlerApi.close();
392 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800393 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800394
admin944ef4f2013-10-08 17:48:37 -0700395 /**
396 * Get the collection of offered module services.
397 *
398 * @return the collection of offered module services.
399 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800400 @Override
401 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
402 Collection<Class<? extends IFloodlightService>> l =
403 new ArrayList<Class<? extends IFloodlightService>>();
404 l.add(IFlowService.class);
405 return l;
406 }
407
admin944ef4f2013-10-08 17:48:37 -0700408 /**
409 * Get the collection of implemented services.
410 *
411 * @return the collection of implemented services.
412 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800413 @Override
414 public Map<Class<? extends IFloodlightService>, IFloodlightService>
415 getServiceImpls() {
416 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700417 IFloodlightService> m =
418 new HashMap<Class<? extends IFloodlightService>,
419 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800420 m.put(IFlowService.class, this);
421 return m;
422 }
423
admin944ef4f2013-10-08 17:48:37 -0700424 /**
425 * Get the collection of modules this module depends on.
426 *
427 * @return the collection of modules this module depends on.
428 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800429 @Override
430 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700431 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800432 Collection<Class<? extends IFloodlightService>> l =
433 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800434 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700435 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700436 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800437 l.add(IRestApiService.class);
438 return l;
439 }
440
admin944ef4f2013-10-08 17:48:37 -0700441 /**
442 * Initialize the module.
443 *
444 * @param context the module context to use for the initialization.
445 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800446 @Override
447 public void init(FloodlightModuleContext context)
448 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700449 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800450 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700451 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
452 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800453 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700454
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800455 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
456 EnumSet.of(OFType.FLOW_MOD),
457 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700458
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700459 this.init("");
460
admin944ef4f2013-10-08 17:48:37 -0700461 mapReaderScheduler = Executors.newScheduledThreadPool(1);
462 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800463 }
464
admin944ef4f2013-10-08 17:48:37 -0700465 /**
466 * Get the next Flow Entry ID to use.
467 *
468 * @return the next Flow Entry ID to use.
469 */
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700470 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000471 //
472 // Generate the next Flow Entry ID.
473 // NOTE: For now, the higher 32 bits are random, and
474 // the lower 32 bits are sequential.
475 // In the future, we need a better allocation mechanism.
476 //
477 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
478 nextFlowEntryIdPrefix = randomGenerator.nextInt();
479 nextFlowEntryIdSuffix = 0;
480 } else {
481 nextFlowEntryIdSuffix++;
482 }
483 long result = (long)nextFlowEntryIdPrefix << 32;
484 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
485 return result;
486 }
487
admin944ef4f2013-10-08 17:48:37 -0700488 /**
489 * Startup module operation.
490 *
491 * @param context the module context to use for the startup.
492 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800493 @Override
494 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700495 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700496
admin944ef4f2013-10-08 17:48:37 -0700497 // Initialize the Flow Entry ID generator
498 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700499
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700500 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700501 // Create the Flow Event Handler thread and register it with the
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700502 // Datagrid Service
503 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700504 flowEventHandler = new FlowEventHandler(this, datagridService);
505 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -0700506
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700507 // Schedule the threads and periodic tasks
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700508 flowEventHandler.start();
admin944ef4f2013-10-08 17:48:37 -0700509 mapReaderScheduler.scheduleAtFixedRate(
510 mapReader, 3, 3, TimeUnit.SECONDS);
511 shortestPathReconcileScheduler.scheduleAtFixedRate(
512 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800513 }
514
515 /**
516 * Add a flow.
517 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800518 * @param flowPath the Flow Path to install.
519 * @param flowId the return-by-reference Flow ID as assigned internally.
520 * @return true on success, otherwise false.
521 */
522 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700523 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700524 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700525 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700526 // in case the application didn't do it.
527 //
528 for (FlowEntry flowEntry : flowPath.flowEntries()) {
529 if (flowEntry.flowEntrySwitchState() ==
530 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
531 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
532 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700533 if (! flowEntry.isValidFlowId())
534 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700535 }
536
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800537 if (FlowDatabaseOperation.addFlow(this, dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700538 datagridService.notificationSendFlowAdded(flowPath);
539 return true;
540 }
541 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800542 }
543
544 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700545 * Add a flow entry to the Network MAP.
546 *
547 * @param flowObj the corresponding Flow Path object for the Flow Entry.
548 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700549 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700550 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700551 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800552 return FlowDatabaseOperation.addFlowEntry(this, dbHandlerInner,
553 flowObj, flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700554 }
555
556 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700557 * Delete a flow entry from the Network MAP.
558 *
559 * @param flowObj the corresponding Flow Path object for the Flow Entry.
560 * @param flowEntry the Flow Entry to delete.
561 * @return true on success, otherwise false.
562 */
563 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800564 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
565 flowObj, flowEntry);
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700566 }
567
568 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000569 * Delete all previously added flows.
570 *
571 * @return true on success, otherwise false.
572 */
573 @Override
574 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800575 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700576 datagridService.notificationSendAllFlowsRemoved();
577 return true;
578 }
579 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000580 }
581
582 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800583 * Delete a previously added flow.
584 *
585 * @param flowId the Flow ID of the flow to delete.
586 * @return true on success, otherwise false.
587 */
588 @Override
589 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800590 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700591 datagridService.notificationSendFlowRemoved(flowId);
592 return true;
593 }
594 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800595 }
596
597 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000598 * Clear the state for all previously added flows.
599 *
600 * @return true on success, otherwise false.
601 */
602 @Override
603 public boolean clearAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800604 if (FlowDatabaseOperation.clearAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700605 datagridService.notificationSendAllFlowsRemoved();
606 return true;
607 }
608 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000609 }
610
611 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700612 * Clear the state for a previously added flow.
613 *
614 * @param flowId the Flow ID of the flow to clear.
615 * @return true on success, otherwise false.
616 */
617 @Override
618 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800619 if (FlowDatabaseOperation.clearFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700620 datagridService.notificationSendFlowRemoved(flowId);
621 return true;
622 }
623 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700624 }
625
626 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800627 * Get a previously added flow.
628 *
629 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800630 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800631 */
632 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800633 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800634 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700635 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800636
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700637 /**
638 * Get all installed flows by all installers.
639 *
640 * @return the Flow Paths if found, otherwise null.
641 */
642 @Override
643 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800644 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800645 }
646
647 /**
648 * Get all previously added flows by a specific installer for a given
649 * data path endpoints.
650 *
651 * @param installerId the Caller ID of the installer of the flow to get.
652 * @param dataPathEndpoints the data path endpoints of the flow to get.
653 * @return the Flow Paths if found, otherwise null.
654 */
655 @Override
656 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
657 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800658 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700659 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800660 }
661
662 /**
663 * Get all installed flows by all installers for given data path endpoints.
664 *
665 * @param dataPathEndpoints the data path endpoints of the flows to get.
666 * @return the Flow Paths if found, otherwise null.
667 */
668 @Override
669 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800670 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
671 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800672 }
673
674 /**
admin944ef4f2013-10-08 17:48:37 -0700675 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700676 *
admin944ef4f2013-10-08 17:48:37 -0700677 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700678 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700679 * @return the Flow Paths if found, otherwise null.
680 */
681 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700682 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
683 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800684 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700685 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700686 }
687
688 /**
admin944ef4f2013-10-08 17:48:37 -0700689 * Get all Flows information, without the associated Flow Entries.
690 *
691 * @return all Flows information, without the associated Flow Entries.
692 */
693 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800694 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandlerApi);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700695 }
696
697 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700698 * Add and maintain a shortest-path flow.
699 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700700 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700701 *
702 * @param flowPath the Flow Path with the endpoints and the match
703 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700704 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700705 */
706 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700707 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700708 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000709 // Don't do the shortest path computation here.
710 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700711 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700712
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700713 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700714 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700715 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700716
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700717 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700718 }
719
720 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800721 * Get the network topology.
722 *
723 * @return the network topology.
724 */
725 public Topology getTopology() {
726 return flowEventHandler.getTopology();
727 }
728
729 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700730 * Reconcile a flow.
731 *
732 * @param flowObj the flow that needs to be reconciliated.
733 * @param newDataPath the new data path to use.
734 * @return true on success, otherwise false.
735 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700736 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700737 String flowIdStr = flowObj.getFlowId();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700738
739 //
740 // Set the incoming port matching and the outgoing port output
741 // actions for each flow entry.
742 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700743 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700744 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700745 flowEntry.setFlowId(new FlowId(flowIdStr));
746
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700747 // Mark the Flow Entry as not updated in the switch
748 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700749 // Set the incoming port matching
750 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
751 flowEntry.setFlowEntryMatch(flowEntryMatch);
752 flowEntryMatch.enableInPort(flowEntry.inPort());
753
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700754 //
755 // Set the actions
756 //
757 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
758 //
759 // If the first Flow Entry, copy the Flow Path actions to it
760 //
761 if (idx == 0) {
762 String actionsStr = flowObj.getActions();
763 if (actionsStr != null) {
764 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
765 for (FlowEntryAction action : flowActions.actions())
766 flowEntryActions.addAction(action);
767 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700768 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700769 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700770 //
771 // Add the outgoing port output action
772 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700773 FlowEntryAction flowEntryAction = new FlowEntryAction();
774 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700775 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700776 }
777
778 //
779 // Remove the old Flow Entries, and add the new Flow Entries
780 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700781 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700782 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700783 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700784 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700785 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700786 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700787 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700788 }
789
790 //
791 // Set the Data Path Summary
792 //
793 String dataPathSummaryStr = newDataPath.dataPathSummary();
794 flowObj.setDataPathSummary(dataPathSummaryStr);
795
796 return true;
797 }
798
799 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700800 * Reconcile all flows in a set.
801 *
802 * @param flowObjSet the set of flows that need to be reconciliated.
803 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700804 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700805 if (! flowObjSet.iterator().hasNext())
806 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700807 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700808 }
809
810 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700811 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700812 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700813 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700814 * @param flowObj the flow path object for the flow entry to install.
815 * @param flowEntryObj the flow entry object to install.
816 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700817 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700818 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700819 IFlowEntry flowEntryObj) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700820 return FlowSwitchOperation.installFlowEntry(
821 floodlightProvider.getOFMessageFactory(),
822 messageDamper, mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700823 }
824
825 /**
826 * Install a Flow Entry on a switch.
827 *
828 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700829 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700830 * @param flowEntry the flow entry to install.
831 * @return true on success, otherwise false.
832 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700833 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700834 FlowEntry flowEntry) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700835 return FlowSwitchOperation.installFlowEntry(
836 floodlightProvider.getOFMessageFactory(),
837 messageDamper, mySwitch, flowPath, flowEntry);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700838 }
839
840 /**
841 * Remove a Flow Entry from a switch.
842 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700843 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700844 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700845 * @param flowEntry the flow entry to remove.
846 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700847 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700848 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700849 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700850 //
851 // The installFlowEntry() method implements both installation
852 // and removal of flow entries.
853 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700854 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700855 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700856
857 /**
858 * Push the modified Flow Entries of a collection of Flow Paths.
859 * Only the Flow Entries to switches controlled by this instance
860 * are pushed.
861 *
862 * NOTE: Currently, we write to both the Network MAP and the switches.
863 *
864 * @param modifiedFlowPaths the collection of Flow Paths with the modified
865 * Flow Entries.
866 */
867 public void pushModifiedFlowEntries(Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700868 // TODO: For now, the pushing of Flow Entries is disabled
869 if (true)
870 return;
871
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800872 if (modifiedFlowPaths.isEmpty())
873 return;
874
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700875 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
876
877 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700878 //
879 // Find the Flow Path in the Network MAP.
880 // NOTE: The Flow Path might not be found if the Flow was just
881 // removed by some other controller instance.
882 //
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800883 IFlowPath flowObj = dbHandlerInner.searchFlowPath(flowPath.flowId());
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700884
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700885 boolean isFlowEntryDeleted = false;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700886 for (FlowEntry flowEntry : flowPath.flowEntries()) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800887 log.debug("Updating Flow Entry: {}", flowEntry.toString());
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700888
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700889 if (flowEntry.flowEntrySwitchState() !=
890 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
891 continue; // No need to update the entry
892 }
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700893 if (flowEntry.flowEntryUserState() ==
894 FlowEntryUserState.FE_USER_DELETE) {
895 isFlowEntryDeleted = true;
896 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700897
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700898 //
899 // Install the Flow Entries into my switches
900 //
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700901 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700902 if (mySwitch != null) {
903 //
904 // Assign the FlowEntry ID if needed
905 //
906 if (! flowEntry.isValidFlowEntryId()) {
907 long id = getNextFlowEntryId();
908 flowEntry.setFlowEntryId(new FlowEntryId(id));
909 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700910
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700911 //
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();
919 log.error(logMsg);
920 continue;
921 }
922
923 //
924 // NOTE: Here we assume that the switch has been
925 // successfully updated.
926 //
927 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700928 }
929
930 //
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700931 // TODO: For now Flow Entries are removed from the Datagrid
932 // and from the Network Map by all instances, even if this
933 // Flow Entry is not for our switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700934 //
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700935 // This is needed to handle the case a switch going down:
936 // it has no Master controller instance, hence no
937 // controller instance will cleanup its flow entries.
938 // This is sub-optimal: we need to elect a controller
939 // instance to handle the cleanup of such orphaned flow
940 // entries.
941 //
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800942 if (mySwitch == null) {
943 if (flowEntry.flowEntryUserState() !=
944 FlowEntryUserState.FE_USER_DELETE) {
945 continue;
946 }
947 if (! flowEntry.isValidFlowEntryId())
948 continue;
949 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700950
951 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700952 // Write the Flow Entry to the Datagrid
953 //
954 switch (flowEntry.flowEntryUserState()) {
955 case FE_USER_ADD:
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700956 if (mySwitch == null)
957 break; // Install only flow entries for my switches
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700958 datagridService.notificationSendFlowEntryAdded(flowEntry);
959 break;
960 case FE_USER_MODIFY:
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700961 if (mySwitch == null)
962 break; // Install only flow entries for my switches
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700963 datagridService.notificationSendFlowEntryUpdated(flowEntry);
964 break;
965 case FE_USER_DELETE:
966 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
967 break;
968 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700969
970 //
971 // Write the Flow Entry to the Network Map
972 //
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700973 if (flowObj == null) {
974 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowPath.flowId();
975 continue;
976 }
977 try {
978 switch (flowEntry.flowEntryUserState()) {
979 case FE_USER_ADD:
980 // FALLTHROUGH
981 case FE_USER_MODIFY:
982 if (addFlowEntry(flowObj, flowEntry) == null) {
983 String logMsg = "Cannot write to Network MAP Flow Entry " +
984 flowEntry.flowEntryId() +
985 " from Flow Path " + flowPath.flowId() +
986 " on switch " + flowEntry.dpid();
987 log.error(logMsg);
988 }
989 break;
990 case FE_USER_DELETE:
991 if (deleteFlowEntry(flowObj, flowEntry) == false) {
992 String logMsg = "Cannot remove from Network MAP Flow Entry " +
993 flowEntry.flowEntryId() +
994 " from Flow Path " + flowPath.flowId() +
995 " on switch " + flowEntry.dpid();
996 log.error(logMsg);
997 }
998 break;
999 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001000 } catch (Exception e) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -08001001 log.debug("Exception writing Flow Entry to Network MAP: ", e);
1002 dbHandlerInner.rollback();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001003 continue;
1004 }
1005 }
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001006
1007 //
1008 // Remove Flow Entries that were deleted
1009 //
1010 // NOTE: We create a new ArrayList, and add only the Flow Entries
1011 // that are NOT FE_USER_DELETE.
1012 // This is sub-optimal: if it adds notable processing cost,
1013 // the Flow Entries container should be changed to LinkedList
1014 // or some other container that has O(1) cost of removing an entry.
1015 //
1016 if (isFlowEntryDeleted) {
1017 ArrayList<FlowEntry> newFlowEntries = new ArrayList<FlowEntry>();
1018 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1019 if (flowEntry.flowEntryUserState() !=
1020 FlowEntryUserState.FE_USER_DELETE) {
1021 newFlowEntries.add(flowEntry);
1022 }
1023 }
1024 flowPath.dataPath().setFlowEntries(newFlowEntries);
1025 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001026 }
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -08001027 // Try to commit to the database
Pavlin Radoslavovab189252013-11-05 08:50:23 -08001028 try {
1029 dbHandlerInner.commit();
1030 } catch (Exception e) {
1031 log.debug("Exception during commit of Flow Entries to Network MAP", e);
1032 dbHandlerInner.rollback();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -08001033 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001034 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001035}