blob: 42f5e3c6dd070cfd82ba0c2e692ae50119d33334 [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 -070021
22import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070023import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070024import net.onrc.onos.ofcontroller.core.INetMapStorage;
25import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
26import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070027import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070028import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070029import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070030import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -070031import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070032import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033
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 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070040public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070042 protected GraphDBOperation dbHandler;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080043
Jonathan Hart50a94982013-04-10 14:49:51 -070044 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070045 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070046 protected volatile IDatagridService datagridService;
47 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070048 protected FloodlightModuleContext context;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070049 protected PathComputation pathComputation;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080050
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080051 protected FlowPusher pusher;
52
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000053 // Flow Entry ID generation state
54 private static Random randomGenerator = new Random();
55 private static int nextFlowEntryIdPrefix = 0;
56 private static int nextFlowEntryIdSuffix = 0;
57 private static long nextFlowEntryId = 0;
58
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080059 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070060 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080061
62 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070063 private ScheduledExecutorService mapReaderScheduler;
64 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -070065
admin944ef4f2013-10-08 17:48:37 -070066 /**
67 * Periodic task for reading the Flow Entries and pushing changes
68 * into the switches.
69 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070070 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070072 try {
73 runImpl();
74 } catch (Exception e) {
75 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070076 dbHandler.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070077 return;
78 }
79 }
80
81 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070082 long startTime = System.nanoTime();
83 int counterAllFlowEntries = 0;
84 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070085
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080086 if (floodlightProvider == null) {
87 log.debug("FloodlightProvider service not found!");
88 return;
89 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000090 Map<Long, IOFSwitch> mySwitches =
91 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -070092 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -070093 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -070094 return;
95 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -070096 LinkedList<IFlowEntry> addFlowEntries =
97 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000098 LinkedList<IFlowEntry> deleteFlowEntries =
99 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700100
101 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700102 // Fetch all Flow Entries which need to be updated and select
103 // only my Flow Entries that need to be updated into the
104 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700105 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000106 Iterable<IFlowEntry> allFlowEntries =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700107 dbHandler.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700108 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700109 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000110
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000111 String dpidStr = flowEntryObj.getSwitchDpid();
112 if (dpidStr == null)
113 continue;
114 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800115 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000116 if (mySwitch == null)
117 continue; // Ignore the entry: not my switch
118
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700119 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700120 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700121 if (flowObj == null)
122 continue; // Should NOT happen
123 if (flowObj.getFlowId() == null)
124 continue; // Invalid entry
125
126 //
127 // NOTE: For now we process the DELETE before the ADD
128 // to cover the more common scenario.
129 // TODO: This is error prone and needs to be fixed!
130 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000131 String userState = flowEntryObj.getUserState();
132 if (userState == null)
133 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700134 if (userState.equals("FE_USER_DELETE")) {
135 // An entry that needs to be deleted.
136 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700137 installFlowEntry(mySwitch, flowObj, flowEntryObj);
138 } else {
139 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700140 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700141 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700142 }
143
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700144 //
145 // Process the Flow Entries that need to be added
146 //
147 for (IFlowEntry flowEntryObj : addFlowEntries) {
148 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700149 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700150 if (flowObj == null)
151 continue; // Should NOT happen
152 if (flowObj.getFlowId() == null)
153 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700154
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700155 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700156 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000157 if (mySwitch == null)
158 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700159 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800160 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000161
162 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000163 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700164 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000165 //
166 // TODO: We should use the OpenFlow Barrier mechanism
167 // to check for errors, and delete the Flow Entries after the
168 // Barrier message is received.
169 //
170 while (! deleteFlowEntries.isEmpty()) {
171 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
172 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700173 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000174 if (flowObj == null) {
175 log.debug("Did not find FlowPath to be deleted");
176 continue;
177 }
178 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700179 dbHandler.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000180 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700181
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700182 dbHandler.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700183
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700184 long estimatedTime = System.nanoTime() - startTime;
185 double rate = 0.0;
186 if (estimatedTime > 0)
187 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
188 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
189 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
190 counterMyNotUpdatedFlowEntries + " in " +
191 (double)estimatedTime / 1000000000 + " sec: " +
192 rate + " paths/s";
193 log.debug(logMsg);
194 }
195 };
196
admin944ef4f2013-10-08 17:48:37 -0700197 /**
198 * Periodic task for reading the Flow Paths and recomputing the
199 * shortest paths.
200 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700201 final Runnable shortestPathReconcile = new Runnable() {
202 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700203 try {
204 runImpl();
205 } catch (Exception e) {
206 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700207 dbHandler.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700208 return;
209 }
210 }
211
212 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700213 long startTime = System.nanoTime();
214 int counterAllFlowPaths = 0;
215 int counterMyFlowPaths = 0;
216
217 if (floodlightProvider == null) {
218 log.debug("FloodlightProvider service not found!");
219 return;
220 }
221 Map<Long, IOFSwitch> mySwitches =
222 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700223 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700224 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700225 return;
226 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700227 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
228
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700229 //
230 // Fetch and recompute the Shortest Path for those
231 // Flow Paths this controller is responsible for.
232 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700233 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700234 Iterable<IFlowPath> allFlowPaths = dbHandler.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700235 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700236 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700237 if (flowPathObj == null)
238 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700239
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700240 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000241 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700242 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700243 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700244 //
245 // Use the source DPID as a heuristic to decide
246 // which controller is responsible for maintaining the
247 // shortest path.
248 // NOTE: This heuristic is error-prone: if the switch
249 // goes away and no controller is responsible for that
250 // switch, then the original Flow Path is not cleaned-up
251 //
252 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
253 if (mySwitch == null)
254 continue; // Ignore: not my responsibility
255
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700256 // Test whether we need to maintain this flow
257 String flowPathTypeStr = flowPathObj.getFlowPathType();
258 if (flowPathTypeStr == null)
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700259 continue; // Could be invalid entry?
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700260 if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700261 continue; // No need to maintain this flow
262
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000263 //
264 // Test whether we need to complete the Flow cleanup,
265 // if the Flow has been deleted by the user.
266 //
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700267 String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
268 if ((flowPathUserStateStr != null)
269 && flowPathUserStateStr.equals("FP_USER_DELETE")) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000270 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700271 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000272 if (empty)
273 deleteFlows.add(flowPathObj);
274 }
275
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000276 // Fetch the fields needed to recompute the shortest path
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700277 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000278 Short srcPortShort = flowPathObj.getSrcPort();
279 String dstDpidStr = flowPathObj.getDstSwitch();
280 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700281 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700282 if ((dataPathSummaryStr == null) ||
283 (srcPortShort == null) ||
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000284 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700285 (dstPortShort == null) ||
286 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000287 continue;
288 }
289
290 Port srcPort = new Port(srcPortShort);
291 Dpid dstDpid = new Dpid(dstDpidStr);
292 Port dstPort = new Port(dstPortShort);
293 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
294 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700295 FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700296 FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700297 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000298
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700299 counterMyFlowPaths++;
300
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700301 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700302 // NOTE: Using here the regular getDatabaseShortestPath()
303 // method won't work here, because that method calls
304 // internally "conn.endTx(Transaction.COMMIT)", and that
305 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700306 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700307 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700308 // to avoid closing the transaction.
309 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700310 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700311 topologyNetService.getTopologyShortestPath(
312 topology,
313 srcSwitchPort,
314 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000315 if (dataPath == null) {
316 // We need the DataPath to compare the paths
317 dataPath = new DataPath();
318 dataPath.setSrcPort(srcSwitchPort);
319 dataPath.setDstPort(dstSwitchPort);
320 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700321 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000322
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700323 String newDataPathSummaryStr = dataPath.dataPathSummary();
324 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
325 continue; // Nothing changed
326
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700327 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700328 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000329
330 //
331 // Delete all leftover Flows marked for deletion from the
332 // Network MAP.
333 //
334 while (! deleteFlows.isEmpty()) {
335 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700336 dbHandler.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000337 }
338
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700339 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700340
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700341 dbHandler.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700342
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700343 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700344 double rate = 0.0;
345 if (estimatedTime > 0)
346 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700347 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700348 counterAllFlowPaths + " MyFlowPaths: " +
349 counterMyFlowPaths + " in " +
350 (double)estimatedTime / 1000000000 + " sec: " +
351 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700352 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800353 }
354 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700355
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800356
admin944ef4f2013-10-08 17:48:37 -0700357 /**
358 * Initialize the Flow Manager.
359 *
360 * @param conf the Graph Database configuration string.
361 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800362 @Override
363 public void init(String conf) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700364 dbHandler = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800365 }
366
admin944ef4f2013-10-08 17:48:37 -0700367 /**
368 * Shutdown the Flow Manager operation.
369 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800370 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700371 close();
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 @Override
378 public void close() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700379 datagridService.deregisterPathComputationService(pathComputation);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700380 dbHandler.close();
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800381 pusher.stop();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800382 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800383
admin944ef4f2013-10-08 17:48:37 -0700384 /**
385 * Get the collection of offered module services.
386 *
387 * @return the collection of offered module services.
388 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800389 @Override
390 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
391 Collection<Class<? extends IFloodlightService>> l =
392 new ArrayList<Class<? extends IFloodlightService>>();
393 l.add(IFlowService.class);
394 return l;
395 }
396
admin944ef4f2013-10-08 17:48:37 -0700397 /**
398 * Get the collection of implemented services.
399 *
400 * @return the collection of implemented services.
401 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800402 @Override
403 public Map<Class<? extends IFloodlightService>, IFloodlightService>
404 getServiceImpls() {
405 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700406 IFloodlightService> m =
407 new HashMap<Class<? extends IFloodlightService>,
408 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800409 m.put(IFlowService.class, this);
410 return m;
411 }
412
admin944ef4f2013-10-08 17:48:37 -0700413 /**
414 * Get the collection of modules this module depends on.
415 *
416 * @return the collection of modules this module depends on.
417 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800418 @Override
419 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700420 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800421 Collection<Class<? extends IFloodlightService>> l =
422 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800423 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700424 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700425 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800426 l.add(IRestApiService.class);
427 return l;
428 }
429
admin944ef4f2013-10-08 17:48:37 -0700430 /**
431 * Initialize the module.
432 *
433 * @param context the module context to use for the initialization.
434 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800435 @Override
436 public void init(FloodlightModuleContext context)
437 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700438 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800439 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700440 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
441 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800442 restApi = context.getServiceImpl(IRestApiService.class);
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800443
444 pusher = new FlowPusher();
445 pusher.init(null, floodlightProvider.getOFMessageFactory(), null);
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700446 this.init("");
447
admin944ef4f2013-10-08 17:48:37 -0700448 mapReaderScheduler = Executors.newScheduledThreadPool(1);
449 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800450
451 pusher.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800452 }
453
admin944ef4f2013-10-08 17:48:37 -0700454 /**
455 * Get the next Flow Entry ID to use.
456 *
457 * @return the next Flow Entry ID to use.
458 */
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700459 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000460 //
461 // Generate the next Flow Entry ID.
462 // NOTE: For now, the higher 32 bits are random, and
463 // the lower 32 bits are sequential.
464 // In the future, we need a better allocation mechanism.
465 //
466 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
467 nextFlowEntryIdPrefix = randomGenerator.nextInt();
468 nextFlowEntryIdSuffix = 0;
469 } else {
470 nextFlowEntryIdSuffix++;
471 }
472 long result = (long)nextFlowEntryIdPrefix << 32;
473 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
474 return result;
475 }
476
admin944ef4f2013-10-08 17:48:37 -0700477 /**
478 * Startup module operation.
479 *
480 * @param context the module context to use for the startup.
481 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800482 @Override
483 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700484 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700485
admin944ef4f2013-10-08 17:48:37 -0700486 // Initialize the Flow Entry ID generator
487 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700488
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700489 //
490 // Create the Path Computation thread and register it with the
491 // Datagrid Service
492 //
493 pathComputation = new PathComputation(this, datagridService);
494 datagridService.registerPathComputationService(pathComputation);
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -0700495
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700496 // Schedule the threads and periodic tasks
497 pathComputation.start();
admin944ef4f2013-10-08 17:48:37 -0700498 mapReaderScheduler.scheduleAtFixedRate(
499 mapReader, 3, 3, TimeUnit.SECONDS);
500 shortestPathReconcileScheduler.scheduleAtFixedRate(
501 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800502 }
503
504 /**
505 * Add a flow.
506 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800507 * @param flowPath the Flow Path to install.
508 * @param flowId the return-by-reference Flow ID as assigned internally.
509 * @return true on success, otherwise false.
510 */
511 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700512 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700513 //
514 // NOTE: We need to explicitly initialize the Flow Entry Switch State,
515 // in case the application didn't do it.
516 //
517 for (FlowEntry flowEntry : flowPath.flowEntries()) {
518 if (flowEntry.flowEntrySwitchState() ==
519 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
520 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
521 }
522 }
523
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700524 if (FlowDatabaseOperation.addFlow(this, dbHandler, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700525 datagridService.notificationSendFlowAdded(flowPath);
526 return true;
527 }
528 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800529 }
530
531 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700532 * Add a flow entry to the Network MAP.
533 *
534 * @param flowObj the corresponding Flow Path object for the Flow Entry.
535 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700536 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700537 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700538 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700539 return FlowDatabaseOperation.addFlowEntry(this, dbHandler, flowObj,
540 flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700541 }
542
543 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000544 * Delete all previously added flows.
545 *
546 * @return true on success, otherwise false.
547 */
548 @Override
549 public boolean deleteAllFlows() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700550 if (FlowDatabaseOperation.deleteAllFlows(dbHandler)) {
551 datagridService.notificationSendAllFlowsRemoved();
552 return true;
553 }
554 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000555 }
556
557 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800558 * Delete a previously added flow.
559 *
560 * @param flowId the Flow ID of the flow to delete.
561 * @return true on success, otherwise false.
562 */
563 @Override
564 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700565 if (FlowDatabaseOperation.deleteFlow(dbHandler, flowId)) {
566 datagridService.notificationSendFlowRemoved(flowId);
567 return true;
568 }
569 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800570 }
571
572 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000573 * Clear the state for all previously added flows.
574 *
575 * @return true on success, otherwise false.
576 */
577 @Override
578 public boolean clearAllFlows() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700579 if (FlowDatabaseOperation.clearAllFlows(dbHandler)) {
580 datagridService.notificationSendAllFlowsRemoved();
581 return true;
582 }
583 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000584 }
585
586 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700587 * Clear the state for a previously added flow.
588 *
589 * @param flowId the Flow ID of the flow to clear.
590 * @return true on success, otherwise false.
591 */
592 @Override
593 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700594 if (FlowDatabaseOperation.clearFlow(dbHandler, flowId)) {
595 datagridService.notificationSendFlowRemoved(flowId);
596 return true;
597 }
598 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700599 }
600
601 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800602 * Get a previously added flow.
603 *
604 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800605 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800606 */
607 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800608 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700609 return FlowDatabaseOperation.getFlow(dbHandler, flowId);
610 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800611
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700612 /**
613 * Get all installed flows by all installers.
614 *
615 * @return the Flow Paths if found, otherwise null.
616 */
617 @Override
618 public ArrayList<FlowPath> getAllFlows() {
619 return FlowDatabaseOperation.getAllFlows(dbHandler);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800620 }
621
622 /**
623 * Get all previously added flows by a specific installer for a given
624 * data path endpoints.
625 *
626 * @param installerId the Caller ID of the installer of the flow to get.
627 * @param dataPathEndpoints the data path endpoints of the flow to get.
628 * @return the Flow Paths if found, otherwise null.
629 */
630 @Override
631 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
632 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700633 return FlowDatabaseOperation.getAllFlows(dbHandler, installerId,
634 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800635 }
636
637 /**
638 * Get all installed flows by all installers for given data path endpoints.
639 *
640 * @param dataPathEndpoints the data path endpoints of the flows to get.
641 * @return the Flow Paths if found, otherwise null.
642 */
643 @Override
644 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700645 return FlowDatabaseOperation.getAllFlows(dbHandler, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800646 }
647
648 /**
admin944ef4f2013-10-08 17:48:37 -0700649 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700650 *
admin944ef4f2013-10-08 17:48:37 -0700651 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700652 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700653 * @return the Flow Paths if found, otherwise null.
654 */
655 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700656 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
657 int maxFlows) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700658 return FlowDatabaseOperation.getAllFlowsSummary(dbHandler, flowId,
659 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700660 }
661
662 /**
admin944ef4f2013-10-08 17:48:37 -0700663 * Get all Flows information, without the associated Flow Entries.
664 *
665 * @return all Flows information, without the associated Flow Entries.
666 */
667 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700668 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandler);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700669 }
670
671 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700672 * Add and maintain a shortest-path flow.
673 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700674 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700675 *
676 * @param flowPath the Flow Path with the endpoints and the match
677 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700678 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700679 */
680 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700681 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700682 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000683 // Don't do the shortest path computation here.
684 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700685 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700686
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700687 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700688 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700689 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700690
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700691 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700692 }
693
694 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700695 * Reconcile a flow.
696 *
697 * @param flowObj the flow that needs to be reconciliated.
698 * @param newDataPath the new data path to use.
699 * @return true on success, otherwise false.
700 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700701 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700702
703 //
704 // Set the incoming port matching and the outgoing port output
705 // actions for each flow entry.
706 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700707 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700708 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700709 // Mark the Flow Entry as not updated in the switch
710 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700711 // Set the incoming port matching
712 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
713 flowEntry.setFlowEntryMatch(flowEntryMatch);
714 flowEntryMatch.enableInPort(flowEntry.inPort());
715
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700716 //
717 // Set the actions
718 //
719 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
720 //
721 // If the first Flow Entry, copy the Flow Path actions to it
722 //
723 if (idx == 0) {
724 String actionsStr = flowObj.getActions();
725 if (actionsStr != null) {
726 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
727 for (FlowEntryAction action : flowActions.actions())
728 flowEntryActions.addAction(action);
729 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700730 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700731 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700732 //
733 // Add the outgoing port output action
734 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700735 FlowEntryAction flowEntryAction = new FlowEntryAction();
736 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700737 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700738 }
739
740 //
741 // Remove the old Flow Entries, and add the new Flow Entries
742 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700743 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700744 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700745 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700746 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700747 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700748 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700749 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700750 }
751
752 //
753 // Set the Data Path Summary
754 //
755 String dataPathSummaryStr = newDataPath.dataPathSummary();
756 flowObj.setDataPathSummary(dataPathSummaryStr);
757
758 return true;
759 }
760
761 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700762 * Reconcile all flows in a set.
763 *
764 * @param flowObjSet the set of flows that need to be reconciliated.
765 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700766 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700767 if (! flowObjSet.iterator().hasNext())
768 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700769 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700770 }
771
772 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700773 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700774 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700775 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700776 * @param flowObj the flow path object for the flow entry to install.
777 * @param flowEntryObj the flow entry object to install.
778 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700779 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700780 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700781 IFlowEntry flowEntryObj) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800782 log.debug("Flow is sent to pusher : dpid({}) flow_id({})", mySwitch.getId(), flowEntryObj.getFlowEntryId());
783 return pusher.send(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700784 }
785
786 /**
787 * Install a Flow Entry on a switch.
788 *
789 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700790 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700791 * @param flowEntry the flow entry to install.
792 * @return true on success, otherwise false.
793 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700794 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700795 FlowEntry flowEntry) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800796 log.debug("Flow is sent to pusher : dpid({}) flow_id({})", mySwitch.getId(), flowEntry.getFlowId());
797 // TODO handle this installation by FlowPusher
798
799// return FlowSwitchOperation.installFlowEntry(
800// floodlightProvider.getOFMessageFactory(),
801// messageDamper, mySwitch, flowPath, flowEntry);
802
803 return true;
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 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800910}