blob: 0e70a9b6134e818683e49329e385422402c46ffc [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 Radoslavov05378272013-10-19 23:23:05 -070021import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070022import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070023import net.onrc.onos.ofcontroller.core.INetMapStorage;
24import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
25import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070026import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070027import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070028import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070029import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -070030import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070031import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080032
Naoki Shiota8ee48d52013-11-11 15:51:17 -080033import org.openflow.protocol.OFMessage;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080034import org.slf4j.Logger;
35import org.slf4j.LoggerFactory;
36
admin944ef4f2013-10-08 17:48:37 -070037/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070038 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070039 */
Naoki Shiota8ee48d52013-11-11 15:51:17 -080040public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage,
41 IFlowPusherService {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080042
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070043 protected GraphDBOperation dbHandler;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080044
Jonathan Hart50a94982013-04-10 14:49:51 -070045 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070046 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070047 protected volatile IDatagridService datagridService;
48 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070049 protected FloodlightModuleContext context;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070050 protected PathComputation pathComputation;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080051
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080052 protected FlowPusher pusher;
53
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000054 // Flow Entry ID generation state
55 private static Random randomGenerator = new Random();
56 private static int nextFlowEntryIdPrefix = 0;
57 private static int nextFlowEntryIdSuffix = 0;
58 private static long nextFlowEntryId = 0;
59
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080060 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070061 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080062
63 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070064 private ScheduledExecutorService mapReaderScheduler;
65 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -070066
admin944ef4f2013-10-08 17:48:37 -070067 /**
68 * Periodic task for reading the Flow Entries and pushing changes
69 * into the switches.
70 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070071 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070073 try {
74 runImpl();
75 } catch (Exception e) {
76 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070077 dbHandler.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070078 return;
79 }
80 }
81
82 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070083 long startTime = System.nanoTime();
84 int counterAllFlowEntries = 0;
85 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070086
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080087 if (floodlightProvider == null) {
88 log.debug("FloodlightProvider service not found!");
89 return;
90 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000091 Map<Long, IOFSwitch> mySwitches =
92 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -070093 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -070094 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -070095 return;
96 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -070097 LinkedList<IFlowEntry> addFlowEntries =
98 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000099 LinkedList<IFlowEntry> deleteFlowEntries =
100 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700101
102 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700103 // Fetch all Flow Entries which need to be updated and select
104 // only my Flow Entries that need to be updated into the
105 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700106 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000107 Iterable<IFlowEntry> allFlowEntries =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700108 dbHandler.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700109 for (IFlowEntry flowEntryObj : allFlowEntries) {
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800110 log.debug("flowEntryobj : {}", flowEntryObj);
111
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700112 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000113
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000114 String dpidStr = flowEntryObj.getSwitchDpid();
115 if (dpidStr == null)
116 continue;
117 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800118 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000119 if (mySwitch == null)
120 continue; // Ignore the entry: not my switch
121
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700122 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700123 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700124 if (flowObj == null)
125 continue; // Should NOT happen
126 if (flowObj.getFlowId() == null)
127 continue; // Invalid entry
128
129 //
130 // NOTE: For now we process the DELETE before the ADD
131 // to cover the more common scenario.
132 // TODO: This is error prone and needs to be fixed!
133 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000134 String userState = flowEntryObj.getUserState();
135 if (userState == null)
136 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700137 if (userState.equals("FE_USER_DELETE")) {
138 // An entry that needs to be deleted.
139 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700140 installFlowEntry(mySwitch, flowObj, flowEntryObj);
141 } else {
142 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700143 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700144 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700145 }
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800146
147 log.debug("addFlowEntries : {}", addFlowEntries);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700148
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700149 //
150 // Process the Flow Entries that need to be added
151 //
152 for (IFlowEntry flowEntryObj : addFlowEntries) {
153 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700154 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700155 if (flowObj == null)
156 continue; // Should NOT happen
157 if (flowObj.getFlowId() == null)
158 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700159
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700160 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700161 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000162 if (mySwitch == null)
163 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700164 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800165 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000166
167 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000168 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700169 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000170 //
171 // TODO: We should use the OpenFlow Barrier mechanism
172 // to check for errors, and delete the Flow Entries after the
173 // Barrier message is received.
174 //
175 while (! deleteFlowEntries.isEmpty()) {
176 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
177 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700178 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000179 if (flowObj == null) {
180 log.debug("Did not find FlowPath to be deleted");
181 continue;
182 }
183 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700184 dbHandler.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000185 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700186
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700187 dbHandler.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700188
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700189 long estimatedTime = System.nanoTime() - startTime;
190 double rate = 0.0;
191 if (estimatedTime > 0)
192 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
193 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
194 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
195 counterMyNotUpdatedFlowEntries + " in " +
196 (double)estimatedTime / 1000000000 + " sec: " +
197 rate + " paths/s";
198 log.debug(logMsg);
199 }
200 };
201
admin944ef4f2013-10-08 17:48:37 -0700202 /**
203 * Periodic task for reading the Flow Paths and recomputing the
204 * shortest paths.
205 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700206 final Runnable shortestPathReconcile = new Runnable() {
207 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700208 try {
209 runImpl();
210 } catch (Exception e) {
211 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700212 dbHandler.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700213 return;
214 }
215 }
216
217 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700218 long startTime = System.nanoTime();
219 int counterAllFlowPaths = 0;
220 int counterMyFlowPaths = 0;
221
222 if (floodlightProvider == null) {
223 log.debug("FloodlightProvider service not found!");
224 return;
225 }
226 Map<Long, IOFSwitch> mySwitches =
227 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700228 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700229 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700230 return;
231 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700232 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
233
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700234 //
235 // Fetch and recompute the Shortest Path for those
236 // Flow Paths this controller is responsible for.
237 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700238 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700239 Iterable<IFlowPath> allFlowPaths = dbHandler.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700240 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700241 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700242 if (flowPathObj == null)
243 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700244
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700245 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000246 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700247 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700248 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700249 //
250 // Use the source DPID as a heuristic to decide
251 // which controller is responsible for maintaining the
252 // shortest path.
253 // NOTE: This heuristic is error-prone: if the switch
254 // goes away and no controller is responsible for that
255 // switch, then the original Flow Path is not cleaned-up
256 //
257 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
258 if (mySwitch == null)
259 continue; // Ignore: not my responsibility
260
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700261 // Test whether we need to maintain this flow
262 String flowPathTypeStr = flowPathObj.getFlowPathType();
263 if (flowPathTypeStr == null)
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700264 continue; // Could be invalid entry?
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700265 if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700266 continue; // No need to maintain this flow
267
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000268 //
269 // Test whether we need to complete the Flow cleanup,
270 // if the Flow has been deleted by the user.
271 //
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700272 String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
273 if ((flowPathUserStateStr != null)
274 && flowPathUserStateStr.equals("FP_USER_DELETE")) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000275 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700276 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000277 if (empty)
278 deleteFlows.add(flowPathObj);
279 }
280
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000281 // Fetch the fields needed to recompute the shortest path
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700282 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000283 Short srcPortShort = flowPathObj.getSrcPort();
284 String dstDpidStr = flowPathObj.getDstSwitch();
285 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700286 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700287 if ((dataPathSummaryStr == null) ||
288 (srcPortShort == null) ||
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000289 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700290 (dstPortShort == null) ||
291 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000292 continue;
293 }
294
295 Port srcPort = new Port(srcPortShort);
296 Dpid dstDpid = new Dpid(dstDpidStr);
297 Port dstPort = new Port(dstPortShort);
298 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
299 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700300 FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700301 FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700302 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000303
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700304 counterMyFlowPaths++;
305
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700306 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700307 // NOTE: Using here the regular getDatabaseShortestPath()
308 // method won't work here, because that method calls
309 // internally "conn.endTx(Transaction.COMMIT)", and that
310 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700311 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700312 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700313 // to avoid closing the transaction.
314 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700315 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700316 topologyNetService.getTopologyShortestPath(
317 topology,
318 srcSwitchPort,
319 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000320 if (dataPath == null) {
321 // We need the DataPath to compare the paths
322 dataPath = new DataPath();
323 dataPath.setSrcPort(srcSwitchPort);
324 dataPath.setDstPort(dstSwitchPort);
325 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700326 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000327
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700328 String newDataPathSummaryStr = dataPath.dataPathSummary();
329 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
330 continue; // Nothing changed
331
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700332 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700333 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000334
335 //
336 // Delete all leftover Flows marked for deletion from the
337 // Network MAP.
338 //
339 while (! deleteFlows.isEmpty()) {
340 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700341 dbHandler.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000342 }
343
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700344 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700345
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700346 dbHandler.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700347
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700348 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700349 double rate = 0.0;
350 if (estimatedTime > 0)
351 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700352 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700353 counterAllFlowPaths + " MyFlowPaths: " +
354 counterMyFlowPaths + " in " +
355 (double)estimatedTime / 1000000000 + " sec: " +
356 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700357 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800358 }
359 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700360
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800361
admin944ef4f2013-10-08 17:48:37 -0700362 /**
363 * Initialize the Flow Manager.
364 *
365 * @param conf the Graph Database configuration string.
366 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800367 @Override
368 public void init(String conf) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700369 dbHandler = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800370 }
371
admin944ef4f2013-10-08 17:48:37 -0700372 /**
373 * Shutdown the Flow Manager operation.
374 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800375 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700376 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800377 }
378
admin944ef4f2013-10-08 17:48:37 -0700379 /**
380 * Shutdown the Flow Manager operation.
381 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800382 @Override
383 public void close() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700384 datagridService.deregisterPathComputationService(pathComputation);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700385 dbHandler.close();
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800386 pusher.stop();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800387 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800388
admin944ef4f2013-10-08 17:48:37 -0700389 /**
390 * Get the collection of offered module services.
391 *
392 * @return the collection of offered module services.
393 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800394 @Override
395 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
396 Collection<Class<? extends IFloodlightService>> l =
397 new ArrayList<Class<? extends IFloodlightService>>();
398 l.add(IFlowService.class);
399 return l;
400 }
401
admin944ef4f2013-10-08 17:48:37 -0700402 /**
403 * Get the collection of implemented services.
404 *
405 * @return the collection of implemented services.
406 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800407 @Override
408 public Map<Class<? extends IFloodlightService>, IFloodlightService>
409 getServiceImpls() {
410 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700411 IFloodlightService> m =
412 new HashMap<Class<? extends IFloodlightService>,
413 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800414 m.put(IFlowService.class, this);
415 return m;
416 }
417
admin944ef4f2013-10-08 17:48:37 -0700418 /**
419 * Get the collection of modules this module depends on.
420 *
421 * @return the collection of modules this module depends on.
422 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800423 @Override
424 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700425 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800426 Collection<Class<? extends IFloodlightService>> l =
427 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800428 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700429 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700430 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800431 l.add(IRestApiService.class);
432 return l;
433 }
434
admin944ef4f2013-10-08 17:48:37 -0700435 /**
436 * Initialize the module.
437 *
438 * @param context the module context to use for the initialization.
439 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800440 @Override
441 public void init(FloodlightModuleContext context)
442 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700443 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800444 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700445 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
446 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800447 restApi = context.getServiceImpl(IRestApiService.class);
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800448
449 pusher = new FlowPusher();
450 pusher.init(null, floodlightProvider.getOFMessageFactory(), null);
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800451
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700452 this.init("");
453
admin944ef4f2013-10-08 17:48:37 -0700454 mapReaderScheduler = Executors.newScheduledThreadPool(1);
455 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800456 }
457
admin944ef4f2013-10-08 17:48:37 -0700458 /**
459 * Get the next Flow Entry ID to use.
460 *
461 * @return the next Flow Entry ID to use.
462 */
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700463 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000464 //
465 // Generate the next Flow Entry ID.
466 // NOTE: For now, the higher 32 bits are random, and
467 // the lower 32 bits are sequential.
468 // In the future, we need a better allocation mechanism.
469 //
470 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
471 nextFlowEntryIdPrefix = randomGenerator.nextInt();
472 nextFlowEntryIdSuffix = 0;
473 } else {
474 nextFlowEntryIdSuffix++;
475 }
476 long result = (long)nextFlowEntryIdPrefix << 32;
477 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
478 return result;
479 }
480
admin944ef4f2013-10-08 17:48:37 -0700481 /**
482 * Startup module operation.
483 *
484 * @param context the module context to use for the startup.
485 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800486 @Override
487 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700488 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700489
admin944ef4f2013-10-08 17:48:37 -0700490 // Initialize the Flow Entry ID generator
491 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700492
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800493 pusher.start();
494
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700495 //
496 // Create the Path Computation thread and register it with the
497 // Datagrid Service
498 //
499 pathComputation = new PathComputation(this, datagridService);
500 datagridService.registerPathComputationService(pathComputation);
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -0700501
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700502 // Schedule the threads and periodic tasks
503 pathComputation.start();
admin944ef4f2013-10-08 17:48:37 -0700504 mapReaderScheduler.scheduleAtFixedRate(
505 mapReader, 3, 3, TimeUnit.SECONDS);
506 shortestPathReconcileScheduler.scheduleAtFixedRate(
507 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800508 }
509
510 /**
511 * Add a flow.
512 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800513 * @param flowPath the Flow Path to install.
514 * @param flowId the return-by-reference Flow ID as assigned internally.
515 * @return true on success, otherwise false.
516 */
517 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700518 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700519 //
520 // NOTE: We need to explicitly initialize the Flow Entry Switch State,
521 // in case the application didn't do it.
522 //
523 for (FlowEntry flowEntry : flowPath.flowEntries()) {
524 if (flowEntry.flowEntrySwitchState() ==
525 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
526 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
527 }
528 }
529
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700530 if (FlowDatabaseOperation.addFlow(this, dbHandler, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700531 datagridService.notificationSendFlowAdded(flowPath);
532 return true;
533 }
534 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800535 }
536
537 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700538 * Add a flow entry to the Network MAP.
539 *
540 * @param flowObj the corresponding Flow Path object for the Flow Entry.
541 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700542 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700543 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700544 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700545 return FlowDatabaseOperation.addFlowEntry(this, dbHandler, flowObj,
546 flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700547 }
548
549 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000550 * Delete all previously added flows.
551 *
552 * @return true on success, otherwise false.
553 */
554 @Override
555 public boolean deleteAllFlows() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700556 if (FlowDatabaseOperation.deleteAllFlows(dbHandler)) {
557 datagridService.notificationSendAllFlowsRemoved();
558 return true;
559 }
560 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000561 }
562
563 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800564 * Delete a previously added flow.
565 *
566 * @param flowId the Flow ID of the flow to delete.
567 * @return true on success, otherwise false.
568 */
569 @Override
570 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700571 if (FlowDatabaseOperation.deleteFlow(dbHandler, flowId)) {
572 datagridService.notificationSendFlowRemoved(flowId);
573 return true;
574 }
575 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800576 }
577
578 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000579 * Clear the state for all previously added flows.
580 *
581 * @return true on success, otherwise false.
582 */
583 @Override
584 public boolean clearAllFlows() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700585 if (FlowDatabaseOperation.clearAllFlows(dbHandler)) {
586 datagridService.notificationSendAllFlowsRemoved();
587 return true;
588 }
589 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000590 }
591
592 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700593 * Clear the state for a previously added flow.
594 *
595 * @param flowId the Flow ID of the flow to clear.
596 * @return true on success, otherwise false.
597 */
598 @Override
599 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700600 if (FlowDatabaseOperation.clearFlow(dbHandler, flowId)) {
601 datagridService.notificationSendFlowRemoved(flowId);
602 return true;
603 }
604 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700605 }
606
607 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800608 * Get a previously added flow.
609 *
610 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800611 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800612 */
613 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800614 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700615 return FlowDatabaseOperation.getFlow(dbHandler, flowId);
616 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800617
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700618 /**
619 * Get all installed flows by all installers.
620 *
621 * @return the Flow Paths if found, otherwise null.
622 */
623 @Override
624 public ArrayList<FlowPath> getAllFlows() {
625 return FlowDatabaseOperation.getAllFlows(dbHandler);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800626 }
627
628 /**
629 * Get all previously added flows by a specific installer for a given
630 * data path endpoints.
631 *
632 * @param installerId the Caller ID of the installer of the flow to get.
633 * @param dataPathEndpoints the data path endpoints of the flow to get.
634 * @return the Flow Paths if found, otherwise null.
635 */
636 @Override
637 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
638 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700639 return FlowDatabaseOperation.getAllFlows(dbHandler, installerId,
640 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800641 }
642
643 /**
644 * Get all installed flows by all installers for given data path endpoints.
645 *
646 * @param dataPathEndpoints the data path endpoints of the flows to get.
647 * @return the Flow Paths if found, otherwise null.
648 */
649 @Override
650 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700651 return FlowDatabaseOperation.getAllFlows(dbHandler, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800652 }
653
654 /**
admin944ef4f2013-10-08 17:48:37 -0700655 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700656 *
admin944ef4f2013-10-08 17:48:37 -0700657 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700658 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700659 * @return the Flow Paths if found, otherwise null.
660 */
661 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700662 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
663 int maxFlows) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700664 return FlowDatabaseOperation.getAllFlowsSummary(dbHandler, flowId,
665 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700666 }
667
668 /**
admin944ef4f2013-10-08 17:48:37 -0700669 * Get all Flows information, without the associated Flow Entries.
670 *
671 * @return all Flows information, without the associated Flow Entries.
672 */
673 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700674 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandler);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700675 }
676
677 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700678 * Add and maintain a shortest-path flow.
679 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700680 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700681 *
682 * @param flowPath the Flow Path with the endpoints and the match
683 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700684 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700685 */
686 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700687 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700688 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000689 // Don't do the shortest path computation here.
690 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700691 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700692
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700693 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700694 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700695 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700696
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700697 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700698 }
699
700 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700701 * Reconcile a flow.
702 *
703 * @param flowObj the flow that needs to be reconciliated.
704 * @param newDataPath the new data path to use.
705 * @return true on success, otherwise false.
706 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700707 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700708
709 //
710 // Set the incoming port matching and the outgoing port output
711 // actions for each flow entry.
712 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700713 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700714 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700715 // Mark the Flow Entry as not updated in the switch
716 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700717 // Set the incoming port matching
718 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
719 flowEntry.setFlowEntryMatch(flowEntryMatch);
720 flowEntryMatch.enableInPort(flowEntry.inPort());
721
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700722 //
723 // Set the actions
724 //
725 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
726 //
727 // If the first Flow Entry, copy the Flow Path actions to it
728 //
729 if (idx == 0) {
730 String actionsStr = flowObj.getActions();
731 if (actionsStr != null) {
732 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
733 for (FlowEntryAction action : flowActions.actions())
734 flowEntryActions.addAction(action);
735 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700736 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700737 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700738 //
739 // Add the outgoing port output action
740 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700741 FlowEntryAction flowEntryAction = new FlowEntryAction();
742 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700743 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700744 }
745
746 //
747 // Remove the old Flow Entries, and add the new Flow Entries
748 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700749 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700750 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700751 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700752 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700753 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700754 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700755 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700756 }
757
758 //
759 // Set the Data Path Summary
760 //
761 String dataPathSummaryStr = newDataPath.dataPathSummary();
762 flowObj.setDataPathSummary(dataPathSummaryStr);
763
764 return true;
765 }
766
767 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700768 * Reconcile all flows in a set.
769 *
770 * @param flowObjSet the set of flows that need to be reconciliated.
771 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700772 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700773 if (! flowObjSet.iterator().hasNext())
774 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700775 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700776 }
777
778 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700779 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700780 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700781 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700782 * @param flowObj the flow path object for the flow entry to install.
783 * @param flowEntryObj the flow entry object to install.
784 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700785 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700786 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700787 IFlowEntry flowEntryObj) {
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800788 return pusher.add(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700789 }
790
791 /**
792 * Install a Flow Entry on a switch.
793 *
794 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700795 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700796 * @param flowEntry the flow entry to install.
797 * @return true on success, otherwise false.
798 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700799 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700800 FlowEntry flowEntry) {
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800801 return pusher.add(mySwitch, flowPath, flowEntry);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700802 }
803
804 /**
805 * Remove a Flow Entry from a switch.
806 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700807 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700808 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700809 * @param flowEntry the flow entry to remove.
810 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700811 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700812 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700813 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700814 //
815 // The installFlowEntry() method implements both installation
816 // and removal of flow entries.
817 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700818 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700819 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700820
821 /**
822 * Push the modified Flow Entries of a collection of Flow Paths.
823 * Only the Flow Entries to switches controlled by this instance
824 * are pushed.
825 *
826 * NOTE: Currently, we write to both the Network MAP and the switches.
827 *
828 * @param modifiedFlowPaths the collection of Flow Paths with the modified
829 * Flow Entries.
830 */
831 public void pushModifiedFlowEntries(Collection<FlowPath> modifiedFlowPaths) {
832
833 // TODO: For now, the pushing of Flow Entries is disabled
834 if (true)
835 return;
836
837 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
838
839 for (FlowPath flowPath : modifiedFlowPaths) {
840 IFlowPath flowObj = dbHandler.searchFlowPath(flowPath.flowId());
841 if (flowObj == null) {
842 String logMsg = "Cannot find Network MAP entry for Flow Path " +
843 flowPath.flowId();
844 log.error(logMsg);
845 continue;
846 }
847
848 for (FlowEntry flowEntry : flowPath.flowEntries()) {
849 if (flowEntry.flowEntrySwitchState() !=
850 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
851 continue; // No need to update the entry
852 }
853
854 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
855 if (mySwitch == null)
856 continue; // Ignore the entry: not my switch
857
858 //
859 // Assign the FlowEntry ID if needed
860 //
861 if ((flowEntry.flowEntryId() == null) ||
862 (flowEntry.flowEntryId().value() == 0)) {
863 long id = getNextFlowEntryId();
864 flowEntry.setFlowEntryId(new FlowEntryId(id));
865 }
866
867 //
868 // Install the Flow Entry into the switch
869 //
870 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
871 String logMsg = "Cannot install Flow Entry " +
872 flowEntry.flowEntryId() +
873 " from Flow Path " + flowPath.flowId() +
874 " on switch " + flowEntry.dpid();
875 log.error(logMsg);
876 continue;
877 }
878
879 //
880 // NOTE: Here we assume that the switch has been successfully
881 // updated.
882 //
883 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
884
885 //
886 // Write the Flow Entry to the Network Map
887 //
888 try {
889 if (addFlowEntry(flowObj, flowEntry) == null) {
890 String logMsg = "Cannot write to Network MAP Flow Entry " +
891 flowEntry.flowEntryId() +
892 " from Flow Path " + flowPath.flowId() +
893 " on switch " + flowEntry.dpid();
894 log.error(logMsg);
895 continue;
896 }
897 } catch (Exception e) {
898 String logMsg = "Exception writing Flow Entry to Network MAP";
899 log.debug(logMsg);
900 dbHandler.rollback();
901 continue;
902 }
903 }
904 }
905
906 dbHandler.commit();
907 }
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800908
909 @Override
910 public void addMessage(long dpid, OFMessage msg) {
911 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
912 if (sw == null) {
913 return;
914 }
915
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800916 pusher.add(sw, msg);
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800917 }
918
919 @Override
920 public boolean suspend(long dpid) {
921 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
922 if (sw == null) {
923 return false;
924 }
925
926 return pusher.suspend(sw);
927 }
928
929 @Override
930 public boolean resume(long dpid) {
931 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
932 if (sw == null) {
933 return false;
934 }
935
936 return pusher.resume(sw);
937 }
938
939 @Override
940 public boolean isSuspended(long dpid) {
941 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
942 if (sw == null) {
943 return false;
944 }
945
946 return pusher.isSuspended(sw);
947 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800948}