blob: 415e281b4971ae4a0b5a38c416aa1a46b9177f9d [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 Radoslavov9f33edb2013-11-06 18:24:37 -0800721 * Get the collection of my switches.
722 *
723 * @return the collection of my switches.
724 */
725 public Map<Long, IOFSwitch> getMySwitches() {
726 return floodlightProvider.getSwitches();
727 }
728
729 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800730 * Get the network topology.
731 *
732 * @return the network topology.
733 */
734 public Topology getTopology() {
735 return flowEventHandler.getTopology();
736 }
737
738 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700739 * Reconcile a flow.
740 *
741 * @param flowObj the flow that needs to be reconciliated.
742 * @param newDataPath the new data path to use.
743 * @return true on success, otherwise false.
744 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700745 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700746 String flowIdStr = flowObj.getFlowId();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700747
748 //
749 // Set the incoming port matching and the outgoing port output
750 // actions for each flow entry.
751 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700752 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700753 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700754 flowEntry.setFlowId(new FlowId(flowIdStr));
755
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700756 // Mark the Flow Entry as not updated in the switch
757 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700758 // Set the incoming port matching
759 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
760 flowEntry.setFlowEntryMatch(flowEntryMatch);
761 flowEntryMatch.enableInPort(flowEntry.inPort());
762
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700763 //
764 // Set the actions
765 //
766 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
767 //
768 // If the first Flow Entry, copy the Flow Path actions to it
769 //
770 if (idx == 0) {
771 String actionsStr = flowObj.getActions();
772 if (actionsStr != null) {
773 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
774 for (FlowEntryAction action : flowActions.actions())
775 flowEntryActions.addAction(action);
776 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700777 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700778 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700779 //
780 // Add the outgoing port output action
781 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700782 FlowEntryAction flowEntryAction = new FlowEntryAction();
783 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700784 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700785 }
786
787 //
788 // Remove the old Flow Entries, and add the new Flow Entries
789 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700790 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700791 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700792 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700793 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700794 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700795 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700796 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700797 }
798
799 //
800 // Set the Data Path Summary
801 //
802 String dataPathSummaryStr = newDataPath.dataPathSummary();
803 flowObj.setDataPathSummary(dataPathSummaryStr);
804
805 return true;
806 }
807
808 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700809 * Reconcile all flows in a set.
810 *
811 * @param flowObjSet the set of flows that need to be reconciliated.
812 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700813 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700814 if (! flowObjSet.iterator().hasNext())
815 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700816 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700817 }
818
819 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700820 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700821 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700822 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700823 * @param flowObj the flow path object for the flow entry to install.
824 * @param flowEntryObj the flow entry object to install.
825 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700826 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700827 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700828 IFlowEntry flowEntryObj) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700829 return FlowSwitchOperation.installFlowEntry(
830 floodlightProvider.getOFMessageFactory(),
831 messageDamper, mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700832 }
833
834 /**
835 * Install a Flow Entry on a switch.
836 *
837 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700838 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700839 * @param flowEntry the flow entry to install.
840 * @return true on success, otherwise false.
841 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700842 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700843 FlowEntry flowEntry) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700844 return FlowSwitchOperation.installFlowEntry(
845 floodlightProvider.getOFMessageFactory(),
846 messageDamper, mySwitch, flowPath, flowEntry);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700847 }
848
849 /**
850 * Remove a Flow Entry from a switch.
851 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700852 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700853 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700854 * @param flowEntry the flow entry to remove.
855 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700856 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700857 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700858 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700859 //
860 // The installFlowEntry() method implements both installation
861 // and removal of flow entries.
862 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700863 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700864 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700865
866 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800867 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700868 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800869 * NOTE: Only the Flow Entries to switches controlled by this instance
870 * are pushed.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700871 *
872 * @param modifiedFlowPaths the collection of Flow Paths with the modified
873 * Flow Entries.
874 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800875 public void pushModifiedFlowEntriesToSwitches(
876 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700877 // TODO: For now, the pushing of Flow Entries is disabled
878 if (true)
879 return;
880
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800881 if (modifiedFlowPaths.isEmpty())
882 return;
883
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800884 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700885
886 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700887 for (FlowEntry flowEntry : flowPath.flowEntries()) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800888 log.debug("Updating Flow Entry: {}", flowEntry.toString());
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700889
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700890 if (flowEntry.flowEntrySwitchState() !=
891 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
892 continue; // No need to update the entry
893 }
894
895 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800896 if (mySwitch == null)
897 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700898
899 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800900 // Install the Flow Entry into the switch
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700901 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800902 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
903 String logMsg = "Cannot install Flow Entry " +
904 flowEntry.flowEntryId() +
905 " from Flow Path " + flowPath.flowId() +
906 " on switch " + flowEntry.dpid();
907 log.error(logMsg);
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700908 continue;
909 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800910
911 //
912 // NOTE: Here we assume that the switch has been
913 // successfully updated.
914 //
915 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
916 }
917 }
918 }
919
920 /**
921 * Push modified Flow Entries to the datagrid.
922 *
923 * @param modifiedFlowEntries the collection of modified Flow Entries.
924 */
925 public void pushModifiedFlowEntriesToDatagrid(
926 Collection<FlowEntry> modifiedFlowEntries) {
927 // TODO: For now, the pushing of Flow Entries is disabled
928 if (true)
929 return;
930
931 if (modifiedFlowEntries.isEmpty())
932 return;
933
934 Map<Long, IOFSwitch> mySwitches = getMySwitches();
935
936 for (FlowEntry flowEntry : modifiedFlowEntries) {
937 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
938
939 //
940 // TODO: For now Flow Entries are removed by all instances,
941 // even if this Flow Entry is not for our switches.
942 //
943 // This is needed to handle the case a switch going down:
944 // it has no Master controller instance, hence no
945 // controller instance will cleanup its flow entries.
946 // This is sub-optimal: we need to elect a controller
947 // instance to handle the cleanup of such orphaned flow
948 // entries.
949 //
950 if (mySwitch == null) {
951 if (flowEntry.flowEntryUserState() !=
952 FlowEntryUserState.FE_USER_DELETE) {
953 continue;
954 }
955 if (! flowEntry.isValidFlowEntryId())
956 continue;
957 }
958
959 //
960 // Write the Flow Entry to the Datagrid
961 //
962 switch (flowEntry.flowEntryUserState()) {
963 case FE_USER_ADD:
964 if (mySwitch == null)
965 break; // Install only flow entries for my switches
966 datagridService.notificationSendFlowEntryAdded(flowEntry);
967 break;
968 case FE_USER_MODIFY:
969 if (mySwitch == null)
970 break; // Install only flow entries for my switches
971 datagridService.notificationSendFlowEntryUpdated(flowEntry);
972 break;
973 case FE_USER_DELETE:
974 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
975 break;
976 }
977 }
978 }
979
980 /**
981 * Push Flow Entries to the Network MAP.
982 *
983 * @param modifiedFlowEntries the collection of Flow Entries to push.
984 */
985 public void pushModifiedFlowEntriesToDatabase(
986 Collection<FlowEntry> modifiedFlowEntries) {
987 // TODO: For now, the pushing of Flow Entries is disabled
988 if (true)
989 return;
990
991 if (modifiedFlowEntries.isEmpty())
992 return;
993
994 Map<Long, IOFSwitch> mySwitches = getMySwitches();
995
996 for (FlowEntry flowEntry : modifiedFlowEntries) {
997 if (! flowEntry.isValidFlowId()) {
998 // Shouldn't happen
999 log.error("Cannot push Flow Entry to database: invalid Flow ID: {}", flowEntry.toString());
1000 continue;
1001 }
1002
1003 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1004
1005 //
1006 // TODO: For now Flow Entries are removed by all instances,
1007 // even if this Flow Entry is not for our switches.
1008 //
1009 // This is needed to handle the case a switch going down:
1010 // it has no Master controller instance, hence no
1011 // controller instance will cleanup its flow entries.
1012 // This is sub-optimal: we need to elect a controller
1013 // instance to handle the cleanup of such orphaned flow
1014 // entries.
1015 //
1016 if (mySwitch == null) {
1017 if (flowEntry.flowEntryUserState() !=
1018 FlowEntryUserState.FE_USER_DELETE) {
1019 continue;
1020 }
1021 if (! flowEntry.isValidFlowEntryId())
1022 continue;
1023 }
1024
1025 //
1026 // Write the Flow Entry to the Network Map
1027 //
1028 // NOTE: We try a number of times; apparently, if other instances
1029 // are writing at the same time this will trigger an error.
1030 //
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}