blob: c22b916313bf559a38fb3dc6f0e6a36e6d007bcf [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 Radoslavov661c86f2013-10-21 12:40:40 -070044 protected GraphDBOperation dbHandler;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080045
Jonathan Hart50a94982013-04-10 14:49:51 -070046 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070047 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070048 protected volatile IDatagridService datagridService;
49 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070050 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070051 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080052
53 protected OFMessageDamper messageDamper;
54
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070055 //
56 // TODO: Values copied from elsewhere (class LearningSwitch).
57 // The local copy should go away!
58 //
59 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
60 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080061
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000062 // Flow Entry ID generation state
63 private static Random randomGenerator = new Random();
64 private static int nextFlowEntryIdPrefix = 0;
65 private static int nextFlowEntryIdSuffix = 0;
66 private static long nextFlowEntryId = 0;
67
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080068 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070069 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070
71 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070072 private ScheduledExecutorService mapReaderScheduler;
73 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -070074
admin944ef4f2013-10-08 17:48:37 -070075 /**
76 * Periodic task for reading the Flow Entries and pushing changes
77 * into the switches.
78 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070079 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080080 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070081 try {
82 runImpl();
83 } catch (Exception e) {
84 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070085 dbHandler.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070086 return;
87 }
88 }
89
90 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070091 long startTime = System.nanoTime();
92 int counterAllFlowEntries = 0;
93 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070094
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080095 if (floodlightProvider == null) {
96 log.debug("FloodlightProvider service not found!");
97 return;
98 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000099 Map<Long, IOFSwitch> mySwitches =
100 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700101 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700102 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700103 return;
104 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700105 LinkedList<IFlowEntry> addFlowEntries =
106 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000107 LinkedList<IFlowEntry> deleteFlowEntries =
108 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700109
110 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700111 // Fetch all Flow Entries which need to be updated and select
112 // only my Flow Entries that need to be updated into the
113 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700114 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000115 Iterable<IFlowEntry> allFlowEntries =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700116 dbHandler.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700117 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700118 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000119
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000120 String dpidStr = flowEntryObj.getSwitchDpid();
121 if (dpidStr == null)
122 continue;
123 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800124 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000125 if (mySwitch == null)
126 continue; // Ignore the entry: not my switch
127
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700128 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700129 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700130 if (flowObj == null)
131 continue; // Should NOT happen
132 if (flowObj.getFlowId() == null)
133 continue; // Invalid entry
134
135 //
136 // NOTE: For now we process the DELETE before the ADD
137 // to cover the more common scenario.
138 // TODO: This is error prone and needs to be fixed!
139 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000140 String userState = flowEntryObj.getUserState();
141 if (userState == null)
142 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700143 if (userState.equals("FE_USER_DELETE")) {
144 // An entry that needs to be deleted.
145 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700146 installFlowEntry(mySwitch, flowObj, flowEntryObj);
147 } else {
148 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700149 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700150 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700151 }
152
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700153 //
154 // Process the Flow Entries that need to be added
155 //
156 for (IFlowEntry flowEntryObj : addFlowEntries) {
157 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700158 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700159 if (flowObj == null)
160 continue; // Should NOT happen
161 if (flowObj.getFlowId() == null)
162 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700163
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700164 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700165 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000166 if (mySwitch == null)
167 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700168 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800169 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000170
171 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000172 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700173 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000174 //
175 // TODO: We should use the OpenFlow Barrier mechanism
176 // to check for errors, and delete the Flow Entries after the
177 // Barrier message is received.
178 //
179 while (! deleteFlowEntries.isEmpty()) {
180 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
181 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700182 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000183 if (flowObj == null) {
184 log.debug("Did not find FlowPath to be deleted");
185 continue;
186 }
187 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700188 dbHandler.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000189 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700190
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700191 dbHandler.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700192
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700193 long estimatedTime = System.nanoTime() - startTime;
194 double rate = 0.0;
195 if (estimatedTime > 0)
196 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
197 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
198 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
199 counterMyNotUpdatedFlowEntries + " in " +
200 (double)estimatedTime / 1000000000 + " sec: " +
201 rate + " paths/s";
202 log.debug(logMsg);
203 }
204 };
205
admin944ef4f2013-10-08 17:48:37 -0700206 /**
207 * Periodic task for reading the Flow Paths and recomputing the
208 * shortest paths.
209 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700210 final Runnable shortestPathReconcile = new Runnable() {
211 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700212 try {
213 runImpl();
214 } catch (Exception e) {
215 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700216 dbHandler.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700217 return;
218 }
219 }
220
221 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700222 long startTime = System.nanoTime();
223 int counterAllFlowPaths = 0;
224 int counterMyFlowPaths = 0;
225
226 if (floodlightProvider == null) {
227 log.debug("FloodlightProvider service not found!");
228 return;
229 }
230 Map<Long, IOFSwitch> mySwitches =
231 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700232 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700233 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700234 return;
235 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700236 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
237
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700238 //
239 // Fetch and recompute the Shortest Path for those
240 // Flow Paths this controller is responsible for.
241 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700242 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700243 Iterable<IFlowPath> allFlowPaths = dbHandler.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700244 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700245 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700246 if (flowPathObj == null)
247 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700248
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700249 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000250 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700251 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700252 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700253 //
254 // Use the source DPID as a heuristic to decide
255 // which controller is responsible for maintaining the
256 // shortest path.
257 // NOTE: This heuristic is error-prone: if the switch
258 // goes away and no controller is responsible for that
259 // switch, then the original Flow Path is not cleaned-up
260 //
261 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
262 if (mySwitch == null)
263 continue; // Ignore: not my responsibility
264
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700265 // Test whether we need to maintain this flow
266 String flowPathTypeStr = flowPathObj.getFlowPathType();
267 if (flowPathTypeStr == null)
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700268 continue; // Could be invalid entry?
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700269 if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700270 continue; // No need to maintain this flow
271
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000272 //
273 // Test whether we need to complete the Flow cleanup,
274 // if the Flow has been deleted by the user.
275 //
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700276 String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
277 if ((flowPathUserStateStr != null)
278 && flowPathUserStateStr.equals("FP_USER_DELETE")) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000279 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700280 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000281 if (empty)
282 deleteFlows.add(flowPathObj);
283 }
284
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000285 // Fetch the fields needed to recompute the shortest path
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700286 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000287 Short srcPortShort = flowPathObj.getSrcPort();
288 String dstDpidStr = flowPathObj.getDstSwitch();
289 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700290 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700291 if ((dataPathSummaryStr == null) ||
292 (srcPortShort == null) ||
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000293 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700294 (dstPortShort == null) ||
295 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000296 continue;
297 }
298
299 Port srcPort = new Port(srcPortShort);
300 Dpid dstDpid = new Dpid(dstDpidStr);
301 Port dstPort = new Port(dstPortShort);
302 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
303 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700304 FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700305 FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700306 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000307
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700308 counterMyFlowPaths++;
309
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700310 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700311 // NOTE: Using here the regular getDatabaseShortestPath()
312 // method won't work here, because that method calls
313 // internally "conn.endTx(Transaction.COMMIT)", and that
314 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700315 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700316 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700317 // to avoid closing the transaction.
318 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700319 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700320 topologyNetService.getTopologyShortestPath(
321 topology,
322 srcSwitchPort,
323 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000324 if (dataPath == null) {
325 // We need the DataPath to compare the paths
326 dataPath = new DataPath();
327 dataPath.setSrcPort(srcSwitchPort);
328 dataPath.setDstPort(dstSwitchPort);
329 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700330 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000331
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700332 String newDataPathSummaryStr = dataPath.dataPathSummary();
333 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
334 continue; // Nothing changed
335
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700336 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700337 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000338
339 //
340 // Delete all leftover Flows marked for deletion from the
341 // Network MAP.
342 //
343 while (! deleteFlows.isEmpty()) {
344 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700345 dbHandler.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000346 }
347
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700348 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700349
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700350 dbHandler.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700351
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700352 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700353 double rate = 0.0;
354 if (estimatedTime > 0)
355 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700356 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700357 counterAllFlowPaths + " MyFlowPaths: " +
358 counterMyFlowPaths + " in " +
359 (double)estimatedTime / 1000000000 + " sec: " +
360 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700361 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800362 }
363 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700364
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800365
admin944ef4f2013-10-08 17:48:37 -0700366 /**
367 * Initialize the Flow Manager.
368 *
369 * @param conf the Graph Database configuration string.
370 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800371 @Override
372 public void init(String conf) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700373 dbHandler = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800374 }
375
admin944ef4f2013-10-08 17:48:37 -0700376 /**
377 * Shutdown the Flow Manager operation.
378 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800379 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700380 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800381 }
382
admin944ef4f2013-10-08 17:48:37 -0700383 /**
384 * Shutdown the Flow Manager operation.
385 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800386 @Override
387 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700388 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700389 dbHandler.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800390 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800391
admin944ef4f2013-10-08 17:48:37 -0700392 /**
393 * Get the collection of offered module services.
394 *
395 * @return the collection of offered module services.
396 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800397 @Override
398 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
399 Collection<Class<? extends IFloodlightService>> l =
400 new ArrayList<Class<? extends IFloodlightService>>();
401 l.add(IFlowService.class);
402 return l;
403 }
404
admin944ef4f2013-10-08 17:48:37 -0700405 /**
406 * Get the collection of implemented services.
407 *
408 * @return the collection of implemented services.
409 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800410 @Override
411 public Map<Class<? extends IFloodlightService>, IFloodlightService>
412 getServiceImpls() {
413 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700414 IFloodlightService> m =
415 new HashMap<Class<? extends IFloodlightService>,
416 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800417 m.put(IFlowService.class, this);
418 return m;
419 }
420
admin944ef4f2013-10-08 17:48:37 -0700421 /**
422 * Get the collection of modules this module depends on.
423 *
424 * @return the collection of modules this module depends on.
425 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800426 @Override
427 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700428 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800429 Collection<Class<? extends IFloodlightService>> l =
430 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800431 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700432 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700433 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800434 l.add(IRestApiService.class);
435 return l;
436 }
437
admin944ef4f2013-10-08 17:48:37 -0700438 /**
439 * Initialize the module.
440 *
441 * @param context the module context to use for the initialization.
442 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800443 @Override
444 public void init(FloodlightModuleContext context)
445 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700446 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800447 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700448 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
449 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800450 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700451
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800452 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
453 EnumSet.of(OFType.FLOW_MOD),
454 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700455
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700456 this.init("");
457
admin944ef4f2013-10-08 17:48:37 -0700458 mapReaderScheduler = Executors.newScheduledThreadPool(1);
459 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800460 }
461
admin944ef4f2013-10-08 17:48:37 -0700462 /**
463 * Get the next Flow Entry ID to use.
464 *
465 * @return the next Flow Entry ID to use.
466 */
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700467 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000468 //
469 // Generate the next Flow Entry ID.
470 // NOTE: For now, the higher 32 bits are random, and
471 // the lower 32 bits are sequential.
472 // In the future, we need a better allocation mechanism.
473 //
474 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
475 nextFlowEntryIdPrefix = randomGenerator.nextInt();
476 nextFlowEntryIdSuffix = 0;
477 } else {
478 nextFlowEntryIdSuffix++;
479 }
480 long result = (long)nextFlowEntryIdPrefix << 32;
481 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
482 return result;
483 }
484
admin944ef4f2013-10-08 17:48:37 -0700485 /**
486 * Startup module operation.
487 *
488 * @param context the module context to use for the startup.
489 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800490 @Override
491 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700492 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700493
admin944ef4f2013-10-08 17:48:37 -0700494 // Initialize the Flow Entry ID generator
495 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700496
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700497 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700498 // Create the Flow Event Handler thread and register it with the
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700499 // Datagrid Service
500 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700501 flowEventHandler = new FlowEventHandler(this, datagridService);
502 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -0700503
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700504 // Schedule the threads and periodic tasks
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700505 flowEventHandler.start();
admin944ef4f2013-10-08 17:48:37 -0700506 mapReaderScheduler.scheduleAtFixedRate(
507 mapReader, 3, 3, TimeUnit.SECONDS);
508 shortestPathReconcileScheduler.scheduleAtFixedRate(
509 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800510 }
511
512 /**
513 * Add a flow.
514 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800515 * @param flowPath the Flow Path to install.
516 * @param flowId the return-by-reference Flow ID as assigned internally.
517 * @return true on success, otherwise false.
518 */
519 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700520 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700521 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700522 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700523 // in case the application didn't do it.
524 //
525 for (FlowEntry flowEntry : flowPath.flowEntries()) {
526 if (flowEntry.flowEntrySwitchState() ==
527 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
528 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
529 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700530 if (! flowEntry.isValidFlowId())
531 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700532 }
533
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700534 if (FlowDatabaseOperation.addFlow(this, dbHandler, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700535 datagridService.notificationSendFlowAdded(flowPath);
536 return true;
537 }
538 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800539 }
540
541 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700542 * Add a flow entry to the Network MAP.
543 *
544 * @param flowObj the corresponding Flow Path object for the Flow Entry.
545 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700546 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700547 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700548 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700549 return FlowDatabaseOperation.addFlowEntry(this, dbHandler, flowObj,
550 flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700551 }
552
553 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700554 * Delete a flow entry from the Network MAP.
555 *
556 * @param flowObj the corresponding Flow Path object for the Flow Entry.
557 * @param flowEntry the Flow Entry to delete.
558 * @return true on success, otherwise false.
559 */
560 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
561 return FlowDatabaseOperation.deleteFlowEntry(dbHandler, flowObj,
562 flowEntry);
563 }
564
565 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000566 * Delete all previously added flows.
567 *
568 * @return true on success, otherwise false.
569 */
570 @Override
571 public boolean deleteAllFlows() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700572 if (FlowDatabaseOperation.deleteAllFlows(dbHandler)) {
573 datagridService.notificationSendAllFlowsRemoved();
574 return true;
575 }
576 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000577 }
578
579 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800580 * Delete a previously added flow.
581 *
582 * @param flowId the Flow ID of the flow to delete.
583 * @return true on success, otherwise false.
584 */
585 @Override
586 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700587 if (FlowDatabaseOperation.deleteFlow(dbHandler, flowId)) {
588 datagridService.notificationSendFlowRemoved(flowId);
589 return true;
590 }
591 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800592 }
593
594 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000595 * Clear the state for all previously added flows.
596 *
597 * @return true on success, otherwise false.
598 */
599 @Override
600 public boolean clearAllFlows() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700601 if (FlowDatabaseOperation.clearAllFlows(dbHandler)) {
602 datagridService.notificationSendAllFlowsRemoved();
603 return true;
604 }
605 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000606 }
607
608 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700609 * Clear the state for a previously added flow.
610 *
611 * @param flowId the Flow ID of the flow to clear.
612 * @return true on success, otherwise false.
613 */
614 @Override
615 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700616 if (FlowDatabaseOperation.clearFlow(dbHandler, flowId)) {
617 datagridService.notificationSendFlowRemoved(flowId);
618 return true;
619 }
620 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700621 }
622
623 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800624 * Get a previously added flow.
625 *
626 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800627 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800628 */
629 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800630 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700631 return FlowDatabaseOperation.getFlow(dbHandler, flowId);
632 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800633
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700634 /**
635 * Get all installed flows by all installers.
636 *
637 * @return the Flow Paths if found, otherwise null.
638 */
639 @Override
640 public ArrayList<FlowPath> getAllFlows() {
641 return FlowDatabaseOperation.getAllFlows(dbHandler);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800642 }
643
644 /**
645 * Get all previously added flows by a specific installer for a given
646 * data path endpoints.
647 *
648 * @param installerId the Caller ID of the installer of the flow to get.
649 * @param dataPathEndpoints the data path endpoints of the flow to get.
650 * @return the Flow Paths if found, otherwise null.
651 */
652 @Override
653 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
654 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700655 return FlowDatabaseOperation.getAllFlows(dbHandler, installerId,
656 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800657 }
658
659 /**
660 * Get all installed flows by all installers for given data path endpoints.
661 *
662 * @param dataPathEndpoints the data path endpoints of the flows to get.
663 * @return the Flow Paths if found, otherwise null.
664 */
665 @Override
666 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700667 return FlowDatabaseOperation.getAllFlows(dbHandler, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800668 }
669
670 /**
admin944ef4f2013-10-08 17:48:37 -0700671 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700672 *
admin944ef4f2013-10-08 17:48:37 -0700673 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700674 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700675 * @return the Flow Paths if found, otherwise null.
676 */
677 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700678 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
679 int maxFlows) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700680 return FlowDatabaseOperation.getAllFlowsSummary(dbHandler, flowId,
681 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700682 }
683
684 /**
admin944ef4f2013-10-08 17:48:37 -0700685 * Get all Flows information, without the associated Flow Entries.
686 *
687 * @return all Flows information, without the associated Flow Entries.
688 */
689 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700690 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandler);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700691 }
692
693 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700694 * Add and maintain a shortest-path flow.
695 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700696 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700697 *
698 * @param flowPath the Flow Path with the endpoints and the match
699 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700700 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700701 */
702 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700703 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700704 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000705 // Don't do the shortest path computation here.
706 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700707 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700708
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700709 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700710 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700711 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700712
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700713 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700714 }
715
716 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800717 * Get the network topology.
718 *
719 * @return the network topology.
720 */
721 public Topology getTopology() {
722 return flowEventHandler.getTopology();
723 }
724
725 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700726 * Reconcile a flow.
727 *
728 * @param flowObj the flow that needs to be reconciliated.
729 * @param newDataPath the new data path to use.
730 * @return true on success, otherwise false.
731 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700732 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700733 String flowIdStr = flowObj.getFlowId();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700734
735 //
736 // Set the incoming port matching and the outgoing port output
737 // actions for each flow entry.
738 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700739 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700740 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700741 flowEntry.setFlowId(new FlowId(flowIdStr));
742
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700743 // Mark the Flow Entry as not updated in the switch
744 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700745 // Set the incoming port matching
746 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
747 flowEntry.setFlowEntryMatch(flowEntryMatch);
748 flowEntryMatch.enableInPort(flowEntry.inPort());
749
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700750 //
751 // Set the actions
752 //
753 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
754 //
755 // If the first Flow Entry, copy the Flow Path actions to it
756 //
757 if (idx == 0) {
758 String actionsStr = flowObj.getActions();
759 if (actionsStr != null) {
760 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
761 for (FlowEntryAction action : flowActions.actions())
762 flowEntryActions.addAction(action);
763 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700764 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700765 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700766 //
767 // Add the outgoing port output action
768 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700769 FlowEntryAction flowEntryAction = new FlowEntryAction();
770 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700771 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700772 }
773
774 //
775 // Remove the old Flow Entries, and add the new Flow Entries
776 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700777 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700778 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700779 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700780 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700781 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700782 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700783 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700784 }
785
786 //
787 // Set the Data Path Summary
788 //
789 String dataPathSummaryStr = newDataPath.dataPathSummary();
790 flowObj.setDataPathSummary(dataPathSummaryStr);
791
792 return true;
793 }
794
795 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700796 * Reconcile all flows in a set.
797 *
798 * @param flowObjSet the set of flows that need to be reconciliated.
799 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700800 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700801 if (! flowObjSet.iterator().hasNext())
802 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700803 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700804 }
805
806 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700807 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700808 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700809 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700810 * @param flowObj the flow path object for the flow entry to install.
811 * @param flowEntryObj the flow entry object to install.
812 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700813 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700814 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700815 IFlowEntry flowEntryObj) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700816 return FlowSwitchOperation.installFlowEntry(
817 floodlightProvider.getOFMessageFactory(),
818 messageDamper, mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700819 }
820
821 /**
822 * Install a Flow Entry on a switch.
823 *
824 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700825 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700826 * @param flowEntry the flow entry to install.
827 * @return true on success, otherwise false.
828 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700829 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700830 FlowEntry flowEntry) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700831 return FlowSwitchOperation.installFlowEntry(
832 floodlightProvider.getOFMessageFactory(),
833 messageDamper, mySwitch, flowPath, flowEntry);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700834 }
835
836 /**
837 * Remove a Flow Entry from a switch.
838 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700839 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700840 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700841 * @param flowEntry the flow entry to remove.
842 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700843 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700844 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700845 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700846 //
847 // The installFlowEntry() method implements both installation
848 // and removal of flow entries.
849 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700850 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700851 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700852
853 /**
854 * Push the modified Flow Entries of a collection of Flow Paths.
855 * Only the Flow Entries to switches controlled by this instance
856 * are pushed.
857 *
858 * NOTE: Currently, we write to both the Network MAP and the switches.
859 *
860 * @param modifiedFlowPaths the collection of Flow Paths with the modified
861 * Flow Entries.
862 */
863 public void pushModifiedFlowEntries(Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700864 // TODO: For now, the pushing of Flow Entries is disabled
865 if (true)
866 return;
867
868 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
869
870 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700871 //
872 // Find the Flow Path in the Network MAP.
873 // NOTE: The Flow Path might not be found if the Flow was just
874 // removed by some other controller instance.
875 //
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700876 IFlowPath flowObj = dbHandler.searchFlowPath(flowPath.flowId());
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700877
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700878 boolean isFlowEntryDeleted = false;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700879 for (FlowEntry flowEntry : flowPath.flowEntries()) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800880 log.debug("Updating Flow Entry: {}", flowEntry.toString());
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700881
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700882 if (flowEntry.flowEntrySwitchState() !=
883 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
884 continue; // No need to update the entry
885 }
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700886 if (flowEntry.flowEntryUserState() ==
887 FlowEntryUserState.FE_USER_DELETE) {
888 isFlowEntryDeleted = true;
889 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700890
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700891 //
892 // Install the Flow Entries into my switches
893 //
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700894 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700895 if (mySwitch != null) {
896 //
897 // Assign the FlowEntry ID if needed
898 //
899 if (! flowEntry.isValidFlowEntryId()) {
900 long id = getNextFlowEntryId();
901 flowEntry.setFlowEntryId(new FlowEntryId(id));
902 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700903
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700904 //
905 // Install the Flow Entry into the switch
906 //
907 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
908 String logMsg = "Cannot install Flow Entry " +
909 flowEntry.flowEntryId() +
910 " from Flow Path " + flowPath.flowId() +
911 " on switch " + flowEntry.dpid();
912 log.error(logMsg);
913 continue;
914 }
915
916 //
917 // NOTE: Here we assume that the switch has been
918 // successfully updated.
919 //
920 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700921 }
922
923 //
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700924 // TODO: For now Flow Entries are removed from the Datagrid
925 // and from the Network Map by all instances, even if this
926 // Flow Entry is not for our switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700927 //
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700928 // This is needed to handle the case a switch going down:
929 // it has no Master controller instance, hence no
930 // controller instance will cleanup its flow entries.
931 // This is sub-optimal: we need to elect a controller
932 // instance to handle the cleanup of such orphaned flow
933 // entries.
934 //
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700935
936 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700937 // Write the Flow Entry to the Datagrid
938 //
939 switch (flowEntry.flowEntryUserState()) {
940 case FE_USER_ADD:
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700941 if (mySwitch == null)
942 break; // Install only flow entries for my switches
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700943 datagridService.notificationSendFlowEntryAdded(flowEntry);
944 break;
945 case FE_USER_MODIFY:
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700946 if (mySwitch == null)
947 break; // Install only flow entries for my switches
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700948 datagridService.notificationSendFlowEntryUpdated(flowEntry);
949 break;
950 case FE_USER_DELETE:
951 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
952 break;
953 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700954
955 //
956 // Write the Flow Entry to the Network Map
957 //
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700958 if (mySwitch == null) {
959 if (flowEntry.flowEntryUserState() !=
960 FlowEntryUserState.FE_USER_DELETE) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700961 continue;
962 }
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700963 if (! flowEntry.isValidFlowEntryId())
964 continue;
965 }
966 if (flowObj == null) {
967 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowPath.flowId();
968 continue;
969 }
970 try {
971 switch (flowEntry.flowEntryUserState()) {
972 case FE_USER_ADD:
973 // FALLTHROUGH
974 case FE_USER_MODIFY:
975 if (addFlowEntry(flowObj, flowEntry) == null) {
976 String logMsg = "Cannot write to Network MAP Flow Entry " +
977 flowEntry.flowEntryId() +
978 " from Flow Path " + flowPath.flowId() +
979 " on switch " + flowEntry.dpid();
980 log.error(logMsg);
981 }
982 break;
983 case FE_USER_DELETE:
984 if (deleteFlowEntry(flowObj, flowEntry) == false) {
985 String logMsg = "Cannot remove from Network MAP Flow Entry " +
986 flowEntry.flowEntryId() +
987 " from Flow Path " + flowPath.flowId() +
988 " on switch " + flowEntry.dpid();
989 log.error(logMsg);
990 }
991 break;
992 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700993 } catch (Exception e) {
994 String logMsg = "Exception writing Flow Entry to Network MAP";
995 log.debug(logMsg);
996 dbHandler.rollback();
997 continue;
998 }
999 }
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001000
1001 //
1002 // Remove Flow Entries that were deleted
1003 //
1004 // NOTE: We create a new ArrayList, and add only the Flow Entries
1005 // that are NOT FE_USER_DELETE.
1006 // This is sub-optimal: if it adds notable processing cost,
1007 // the Flow Entries container should be changed to LinkedList
1008 // or some other container that has O(1) cost of removing an entry.
1009 //
1010 if (isFlowEntryDeleted) {
1011 ArrayList<FlowEntry> newFlowEntries = new ArrayList<FlowEntry>();
1012 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1013 if (flowEntry.flowEntryUserState() !=
1014 FlowEntryUserState.FE_USER_DELETE) {
1015 newFlowEntries.add(flowEntry);
1016 }
1017 }
1018 flowPath.dataPath().setFlowEntries(newFlowEntries);
1019 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001020 }
1021
1022 dbHandler.commit();
1023 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001024}