blob: 1ef4431f60b883886ee2b2f7cb8894854d4b9d6d [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;
Naoki Shiotaaea88582013-11-12 17:58:34 -080028import net.onrc.onos.ofcontroller.flowprogrammer.FlowPusher;
29import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
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
Naoki Shiota8ee48d52013-11-11 15:51:17 -080035import org.openflow.protocol.OFMessage;
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 */
Naoki Shiota8ee48d52013-11-11 15:51:17 -080042public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage,
43 IFlowPusherService {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080044
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070045 protected GraphDBOperation dbHandler;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080046
Jonathan Hart50a94982013-04-10 14:49:51 -070047 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070048 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070049 protected volatile IDatagridService datagridService;
50 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070051 protected FloodlightModuleContext context;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070052 protected PathComputation pathComputation;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080053
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080054 protected FlowPusher pusher;
55
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000056 // Flow Entry ID generation state
57 private static Random randomGenerator = new Random();
58 private static int nextFlowEntryIdPrefix = 0;
59 private static int nextFlowEntryIdSuffix = 0;
60 private static long nextFlowEntryId = 0;
61
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080062 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070063 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080064
65 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070066 private ScheduledExecutorService mapReaderScheduler;
67 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -070068
admin944ef4f2013-10-08 17:48:37 -070069 /**
70 * Periodic task for reading the Flow Entries and pushing changes
71 * into the switches.
72 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070073 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080074 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070075 try {
76 runImpl();
77 } catch (Exception e) {
78 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070079 dbHandler.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070080 return;
81 }
82 }
83
84 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070085 long startTime = System.nanoTime();
86 int counterAllFlowEntries = 0;
87 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070088
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080089 if (floodlightProvider == null) {
90 log.debug("FloodlightProvider service not found!");
91 return;
92 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000093 Map<Long, IOFSwitch> mySwitches =
94 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -070095 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -070096 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -070097 return;
98 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -070099 LinkedList<IFlowEntry> addFlowEntries =
100 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000101 LinkedList<IFlowEntry> deleteFlowEntries =
102 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700103
104 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700105 // Fetch all Flow Entries which need to be updated and select
106 // only my Flow Entries that need to be updated into the
107 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700108 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000109 Iterable<IFlowEntry> allFlowEntries =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700110 dbHandler.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700111 for (IFlowEntry flowEntryObj : allFlowEntries) {
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800112 log.debug("flowEntryobj : {}", flowEntryObj);
113
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700114 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000115
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000116 String dpidStr = flowEntryObj.getSwitchDpid();
117 if (dpidStr == null)
118 continue;
119 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800120 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000121 if (mySwitch == null)
122 continue; // Ignore the entry: not my switch
123
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700124 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700125 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700126 if (flowObj == null)
127 continue; // Should NOT happen
128 if (flowObj.getFlowId() == null)
129 continue; // Invalid entry
130
131 //
132 // NOTE: For now we process the DELETE before the ADD
133 // to cover the more common scenario.
134 // TODO: This is error prone and needs to be fixed!
135 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000136 String userState = flowEntryObj.getUserState();
137 if (userState == null)
138 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700139 if (userState.equals("FE_USER_DELETE")) {
140 // An entry that needs to be deleted.
141 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700142 installFlowEntry(mySwitch, flowObj, flowEntryObj);
143 } else {
144 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700145 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700146 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700147 }
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800148
149 log.debug("addFlowEntries : {}", addFlowEntries);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700150
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700151 //
152 // Process the Flow Entries that need to be added
153 //
154 for (IFlowEntry flowEntryObj : addFlowEntries) {
155 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700156 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700157 if (flowObj == null)
158 continue; // Should NOT happen
159 if (flowObj.getFlowId() == null)
160 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700161
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700162 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700163 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000164 if (mySwitch == null)
165 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700166 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800167 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000168
169 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000170 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700171 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000172 //
173 // TODO: We should use the OpenFlow Barrier mechanism
174 // to check for errors, and delete the Flow Entries after the
175 // Barrier message is received.
176 //
177 while (! deleteFlowEntries.isEmpty()) {
178 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
179 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700180 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000181 if (flowObj == null) {
182 log.debug("Did not find FlowPath to be deleted");
183 continue;
184 }
185 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700186 dbHandler.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000187 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700188
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700189 dbHandler.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700190
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700191 long estimatedTime = System.nanoTime() - startTime;
192 double rate = 0.0;
193 if (estimatedTime > 0)
194 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
195 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
196 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
197 counterMyNotUpdatedFlowEntries + " in " +
198 (double)estimatedTime / 1000000000 + " sec: " +
199 rate + " paths/s";
200 log.debug(logMsg);
201 }
202 };
203
admin944ef4f2013-10-08 17:48:37 -0700204 /**
205 * Periodic task for reading the Flow Paths and recomputing the
206 * shortest paths.
207 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700208 final Runnable shortestPathReconcile = new Runnable() {
209 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700210 try {
211 runImpl();
212 } catch (Exception e) {
213 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700214 dbHandler.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700215 return;
216 }
217 }
218
219 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700220 long startTime = System.nanoTime();
221 int counterAllFlowPaths = 0;
222 int counterMyFlowPaths = 0;
223
224 if (floodlightProvider == null) {
225 log.debug("FloodlightProvider service not found!");
226 return;
227 }
228 Map<Long, IOFSwitch> mySwitches =
229 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700230 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700231 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700232 return;
233 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700234 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
235
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700236 //
237 // Fetch and recompute the Shortest Path for those
238 // Flow Paths this controller is responsible for.
239 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700240 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700241 Iterable<IFlowPath> allFlowPaths = dbHandler.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700242 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700243 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700244 if (flowPathObj == null)
245 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700246
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700247 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000248 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700249 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700250 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700251 //
252 // Use the source DPID as a heuristic to decide
253 // which controller is responsible for maintaining the
254 // shortest path.
255 // NOTE: This heuristic is error-prone: if the switch
256 // goes away and no controller is responsible for that
257 // switch, then the original Flow Path is not cleaned-up
258 //
259 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
260 if (mySwitch == null)
261 continue; // Ignore: not my responsibility
262
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700263 // Test whether we need to maintain this flow
264 String flowPathTypeStr = flowPathObj.getFlowPathType();
265 if (flowPathTypeStr == null)
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700266 continue; // Could be invalid entry?
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700267 if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700268 continue; // No need to maintain this flow
269
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000270 //
271 // Test whether we need to complete the Flow cleanup,
272 // if the Flow has been deleted by the user.
273 //
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700274 String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
275 if ((flowPathUserStateStr != null)
276 && flowPathUserStateStr.equals("FP_USER_DELETE")) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000277 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700278 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000279 if (empty)
280 deleteFlows.add(flowPathObj);
281 }
282
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000283 // Fetch the fields needed to recompute the shortest path
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700284 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000285 Short srcPortShort = flowPathObj.getSrcPort();
286 String dstDpidStr = flowPathObj.getDstSwitch();
287 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700288 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700289 if ((dataPathSummaryStr == null) ||
290 (srcPortShort == null) ||
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000291 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700292 (dstPortShort == null) ||
293 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000294 continue;
295 }
296
297 Port srcPort = new Port(srcPortShort);
298 Dpid dstDpid = new Dpid(dstDpidStr);
299 Port dstPort = new Port(dstPortShort);
300 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
301 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700302 FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700303 FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700304 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000305
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700306 counterMyFlowPaths++;
307
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700308 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700309 // NOTE: Using here the regular getDatabaseShortestPath()
310 // method won't work here, because that method calls
311 // internally "conn.endTx(Transaction.COMMIT)", and that
312 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700313 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700314 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700315 // to avoid closing the transaction.
316 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700317 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700318 topologyNetService.getTopologyShortestPath(
319 topology,
320 srcSwitchPort,
321 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000322 if (dataPath == null) {
323 // We need the DataPath to compare the paths
324 dataPath = new DataPath();
325 dataPath.setSrcPort(srcSwitchPort);
326 dataPath.setDstPort(dstSwitchPort);
327 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700328 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000329
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700330 String newDataPathSummaryStr = dataPath.dataPathSummary();
331 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
332 continue; // Nothing changed
333
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700334 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700335 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000336
337 //
338 // Delete all leftover Flows marked for deletion from the
339 // Network MAP.
340 //
341 while (! deleteFlows.isEmpty()) {
342 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700343 dbHandler.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000344 }
345
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700346 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700347
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700348 dbHandler.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700349
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700350 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700351 double rate = 0.0;
352 if (estimatedTime > 0)
353 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700354 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700355 counterAllFlowPaths + " MyFlowPaths: " +
356 counterMyFlowPaths + " in " +
357 (double)estimatedTime / 1000000000 + " sec: " +
358 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700359 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800360 }
361 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700362
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800363
admin944ef4f2013-10-08 17:48:37 -0700364 /**
365 * Initialize the Flow Manager.
366 *
367 * @param conf the Graph Database configuration string.
368 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800369 @Override
370 public void init(String conf) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700371 dbHandler = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800372 }
373
admin944ef4f2013-10-08 17:48:37 -0700374 /**
375 * Shutdown the Flow Manager operation.
376 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800377 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700378 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800379 }
380
admin944ef4f2013-10-08 17:48:37 -0700381 /**
382 * Shutdown the Flow Manager operation.
383 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800384 @Override
385 public void close() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700386 datagridService.deregisterPathComputationService(pathComputation);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700387 dbHandler.close();
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800388 pusher.stop();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800389 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800390
admin944ef4f2013-10-08 17:48:37 -0700391 /**
392 * Get the collection of offered module services.
393 *
394 * @return the collection of offered module services.
395 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800396 @Override
397 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
398 Collection<Class<? extends IFloodlightService>> l =
399 new ArrayList<Class<? extends IFloodlightService>>();
400 l.add(IFlowService.class);
401 return l;
402 }
403
admin944ef4f2013-10-08 17:48:37 -0700404 /**
405 * Get the collection of implemented services.
406 *
407 * @return the collection of implemented services.
408 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800409 @Override
410 public Map<Class<? extends IFloodlightService>, IFloodlightService>
411 getServiceImpls() {
412 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700413 IFloodlightService> m =
414 new HashMap<Class<? extends IFloodlightService>,
415 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800416 m.put(IFlowService.class, this);
417 return m;
418 }
419
admin944ef4f2013-10-08 17:48:37 -0700420 /**
421 * Get the collection of modules this module depends on.
422 *
423 * @return the collection of modules this module depends on.
424 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800425 @Override
426 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700427 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800428 Collection<Class<? extends IFloodlightService>> l =
429 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800430 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700431 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700432 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800433 l.add(IRestApiService.class);
434 return l;
435 }
436
admin944ef4f2013-10-08 17:48:37 -0700437 /**
438 * Initialize the module.
439 *
440 * @param context the module context to use for the initialization.
441 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800442 @Override
443 public void init(FloodlightModuleContext context)
444 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700445 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800446 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700447 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
448 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800449 restApi = context.getServiceImpl(IRestApiService.class);
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800450
451 pusher = new FlowPusher();
452 pusher.init(null, floodlightProvider.getOFMessageFactory(), null);
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800453
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700454 this.init("");
455
admin944ef4f2013-10-08 17:48:37 -0700456 mapReaderScheduler = Executors.newScheduledThreadPool(1);
457 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800458 }
459
admin944ef4f2013-10-08 17:48:37 -0700460 /**
461 * Get the next Flow Entry ID to use.
462 *
463 * @return the next Flow Entry ID to use.
464 */
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700465 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000466 //
467 // Generate the next Flow Entry ID.
468 // NOTE: For now, the higher 32 bits are random, and
469 // the lower 32 bits are sequential.
470 // In the future, we need a better allocation mechanism.
471 //
472 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
473 nextFlowEntryIdPrefix = randomGenerator.nextInt();
474 nextFlowEntryIdSuffix = 0;
475 } else {
476 nextFlowEntryIdSuffix++;
477 }
478 long result = (long)nextFlowEntryIdPrefix << 32;
479 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
480 return result;
481 }
482
admin944ef4f2013-10-08 17:48:37 -0700483 /**
484 * Startup module operation.
485 *
486 * @param context the module context to use for the startup.
487 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800488 @Override
489 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700490 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700491
admin944ef4f2013-10-08 17:48:37 -0700492 // Initialize the Flow Entry ID generator
493 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700494
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800495 pusher.start();
496
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700497 //
498 // Create the Path Computation thread and register it with the
499 // Datagrid Service
500 //
501 pathComputation = new PathComputation(this, datagridService);
502 datagridService.registerPathComputationService(pathComputation);
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -0700503
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700504 // Schedule the threads and periodic tasks
505 pathComputation.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 //
522 // NOTE: We need to explicitly initialize the Flow Entry Switch State,
523 // 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 }
530 }
531
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700532 if (FlowDatabaseOperation.addFlow(this, dbHandler, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700533 datagridService.notificationSendFlowAdded(flowPath);
534 return true;
535 }
536 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800537 }
538
539 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700540 * Add a flow entry to the Network MAP.
541 *
542 * @param flowObj the corresponding Flow Path object for the Flow Entry.
543 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700544 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700545 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700546 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700547 return FlowDatabaseOperation.addFlowEntry(this, dbHandler, flowObj,
548 flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700549 }
550
551 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000552 * Delete all previously added flows.
553 *
554 * @return true on success, otherwise false.
555 */
556 @Override
557 public boolean deleteAllFlows() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700558 if (FlowDatabaseOperation.deleteAllFlows(dbHandler)) {
559 datagridService.notificationSendAllFlowsRemoved();
560 return true;
561 }
562 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000563 }
564
565 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800566 * Delete a previously added flow.
567 *
568 * @param flowId the Flow ID of the flow to delete.
569 * @return true on success, otherwise false.
570 */
571 @Override
572 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700573 if (FlowDatabaseOperation.deleteFlow(dbHandler, flowId)) {
574 datagridService.notificationSendFlowRemoved(flowId);
575 return true;
576 }
577 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800578 }
579
580 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000581 * Clear the state for all previously added flows.
582 *
583 * @return true on success, otherwise false.
584 */
585 @Override
586 public boolean clearAllFlows() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700587 if (FlowDatabaseOperation.clearAllFlows(dbHandler)) {
588 datagridService.notificationSendAllFlowsRemoved();
589 return true;
590 }
591 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000592 }
593
594 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700595 * Clear the state for a previously added flow.
596 *
597 * @param flowId the Flow ID of the flow to clear.
598 * @return true on success, otherwise false.
599 */
600 @Override
601 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700602 if (FlowDatabaseOperation.clearFlow(dbHandler, flowId)) {
603 datagridService.notificationSendFlowRemoved(flowId);
604 return true;
605 }
606 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700607 }
608
609 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800610 * Get a previously added flow.
611 *
612 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800613 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800614 */
615 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800616 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700617 return FlowDatabaseOperation.getFlow(dbHandler, flowId);
618 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800619
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700620 /**
621 * Get all installed flows by all installers.
622 *
623 * @return the Flow Paths if found, otherwise null.
624 */
625 @Override
626 public ArrayList<FlowPath> getAllFlows() {
627 return FlowDatabaseOperation.getAllFlows(dbHandler);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800628 }
629
630 /**
631 * Get all previously added flows by a specific installer for a given
632 * data path endpoints.
633 *
634 * @param installerId the Caller ID of the installer of the flow to get.
635 * @param dataPathEndpoints the data path endpoints of the flow to get.
636 * @return the Flow Paths if found, otherwise null.
637 */
638 @Override
639 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
640 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700641 return FlowDatabaseOperation.getAllFlows(dbHandler, installerId,
642 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800643 }
644
645 /**
646 * Get all installed flows by all installers for given data path endpoints.
647 *
648 * @param dataPathEndpoints the data path endpoints of the flows to get.
649 * @return the Flow Paths if found, otherwise null.
650 */
651 @Override
652 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700653 return FlowDatabaseOperation.getAllFlows(dbHandler, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800654 }
655
656 /**
admin944ef4f2013-10-08 17:48:37 -0700657 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700658 *
admin944ef4f2013-10-08 17:48:37 -0700659 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700660 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700661 * @return the Flow Paths if found, otherwise null.
662 */
663 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700664 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
665 int maxFlows) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700666 return FlowDatabaseOperation.getAllFlowsSummary(dbHandler, flowId,
667 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700668 }
669
670 /**
admin944ef4f2013-10-08 17:48:37 -0700671 * Get all Flows information, without the associated Flow Entries.
672 *
673 * @return all Flows information, without the associated Flow Entries.
674 */
675 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700676 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandler);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700677 }
678
679 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700680 * Add and maintain a shortest-path flow.
681 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700682 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700683 *
684 * @param flowPath the Flow Path with the endpoints and the match
685 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700686 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700687 */
688 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700689 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700690 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000691 // Don't do the shortest path computation here.
692 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700693 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700694
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700695 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700696 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700697 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700698
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700699 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700700 }
701
702 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700703 * Reconcile a flow.
704 *
705 * @param flowObj the flow that needs to be reconciliated.
706 * @param newDataPath the new data path to use.
707 * @return true on success, otherwise false.
708 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700709 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700710
711 //
712 // Set the incoming port matching and the outgoing port output
713 // actions for each flow entry.
714 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700715 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700716 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700717 // Mark the Flow Entry as not updated in the switch
718 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700719 // Set the incoming port matching
720 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
721 flowEntry.setFlowEntryMatch(flowEntryMatch);
722 flowEntryMatch.enableInPort(flowEntry.inPort());
723
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700724 //
725 // Set the actions
726 //
727 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
728 //
729 // If the first Flow Entry, copy the Flow Path actions to it
730 //
731 if (idx == 0) {
732 String actionsStr = flowObj.getActions();
733 if (actionsStr != null) {
734 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
735 for (FlowEntryAction action : flowActions.actions())
736 flowEntryActions.addAction(action);
737 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700738 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700739 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700740 //
741 // Add the outgoing port output action
742 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700743 FlowEntryAction flowEntryAction = new FlowEntryAction();
744 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700745 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700746 }
747
748 //
749 // Remove the old Flow Entries, and add the new Flow Entries
750 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700751 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700752 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700753 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700754 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700755 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700756 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700757 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700758 }
759
760 //
761 // Set the Data Path Summary
762 //
763 String dataPathSummaryStr = newDataPath.dataPathSummary();
764 flowObj.setDataPathSummary(dataPathSummaryStr);
765
766 return true;
767 }
768
769 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700770 * Reconcile all flows in a set.
771 *
772 * @param flowObjSet the set of flows that need to be reconciliated.
773 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700774 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700775 if (! flowObjSet.iterator().hasNext())
776 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700777 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700778 }
779
780 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700781 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700782 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700783 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700784 * @param flowObj the flow path object for the flow entry to install.
785 * @param flowEntryObj the flow entry object to install.
786 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700787 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700788 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700789 IFlowEntry flowEntryObj) {
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800790 return pusher.add(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700791 }
792
793 /**
794 * Install a Flow Entry on a switch.
795 *
796 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700797 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700798 * @param flowEntry the flow entry to install.
799 * @return true on success, otherwise false.
800 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700801 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700802 FlowEntry flowEntry) {
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800803 return pusher.add(mySwitch, flowPath, flowEntry);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700804 }
805
806 /**
807 * Remove a Flow Entry from a switch.
808 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700809 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700810 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700811 * @param flowEntry the flow entry to remove.
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 removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700815 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700816 //
817 // The installFlowEntry() method implements both installation
818 // and removal of flow entries.
819 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700820 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700821 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700822
823 /**
824 * Push the modified Flow Entries of a collection of Flow Paths.
825 * Only the Flow Entries to switches controlled by this instance
826 * are pushed.
827 *
828 * NOTE: Currently, we write to both the Network MAP and the switches.
829 *
830 * @param modifiedFlowPaths the collection of Flow Paths with the modified
831 * Flow Entries.
832 */
833 public void pushModifiedFlowEntries(Collection<FlowPath> modifiedFlowPaths) {
834
835 // TODO: For now, the pushing of Flow Entries is disabled
836 if (true)
837 return;
838
839 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
840
841 for (FlowPath flowPath : modifiedFlowPaths) {
842 IFlowPath flowObj = dbHandler.searchFlowPath(flowPath.flowId());
843 if (flowObj == null) {
844 String logMsg = "Cannot find Network MAP entry for Flow Path " +
845 flowPath.flowId();
846 log.error(logMsg);
847 continue;
848 }
849
850 for (FlowEntry flowEntry : flowPath.flowEntries()) {
851 if (flowEntry.flowEntrySwitchState() !=
852 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
853 continue; // No need to update the entry
854 }
855
856 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
857 if (mySwitch == null)
858 continue; // Ignore the entry: not my switch
859
860 //
861 // Assign the FlowEntry ID if needed
862 //
863 if ((flowEntry.flowEntryId() == null) ||
864 (flowEntry.flowEntryId().value() == 0)) {
865 long id = getNextFlowEntryId();
866 flowEntry.setFlowEntryId(new FlowEntryId(id));
867 }
868
869 //
870 // Install the Flow Entry into the switch
871 //
872 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
873 String logMsg = "Cannot install Flow Entry " +
874 flowEntry.flowEntryId() +
875 " from Flow Path " + flowPath.flowId() +
876 " on switch " + flowEntry.dpid();
877 log.error(logMsg);
878 continue;
879 }
880
881 //
882 // NOTE: Here we assume that the switch has been successfully
883 // updated.
884 //
885 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
886
887 //
888 // Write the Flow Entry to the Network Map
889 //
890 try {
891 if (addFlowEntry(flowObj, flowEntry) == null) {
892 String logMsg = "Cannot write to Network MAP Flow Entry " +
893 flowEntry.flowEntryId() +
894 " from Flow Path " + flowPath.flowId() +
895 " on switch " + flowEntry.dpid();
896 log.error(logMsg);
897 continue;
898 }
899 } catch (Exception e) {
900 String logMsg = "Exception writing Flow Entry to Network MAP";
901 log.debug(logMsg);
902 dbHandler.rollback();
903 continue;
904 }
905 }
906 }
907
908 dbHandler.commit();
909 }
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800910
911 @Override
912 public void addMessage(long dpid, OFMessage msg) {
913 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
914 if (sw == null) {
915 return;
916 }
917
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800918 pusher.add(sw, msg);
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800919 }
920
921 @Override
922 public boolean suspend(long dpid) {
923 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
924 if (sw == null) {
925 return false;
926 }
927
928 return pusher.suspend(sw);
929 }
930
931 @Override
932 public boolean resume(long dpid) {
933 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
934 if (sw == null) {
935 return false;
936 }
937
938 return pusher.resume(sw);
939 }
940
941 @Override
942 public boolean isSuspended(long dpid) {
943 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
944 if (sw == null) {
945 return false;
946 }
947
948 return pusher.isSuspended(sw);
949 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800950}