blob: 0927e498bd3ca1d043561b8b7691719616e25f4a [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;
Naoki Shiota1a37ca12013-11-18 10:55:23 -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;
Naoki Shiota1a37ca12013-11-18 10:55:23 -080021import net.floodlightcontroller.util.OFMessageDamper;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070022import 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;
Brian O'Connor8c166a72013-11-14 18:41:48 -080029import 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 Radoslavov661c86f2013-10-21 12:40:40 -070032import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033
Naoki Shiota1a37ca12013-11-18 10:55:23 -080034import org.openflow.protocol.OFType;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080035import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
admin944ef4f2013-10-08 17:48:37 -070038/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070039 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070040 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070041public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080042
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -080043 //
44 // TODO: A temporary variable to switch between the poll-based and
45 // notification mechanism for the Flow Manager.
46 //
47 private final static boolean enableNotifications = false;
Naoki Shiota1a37ca12013-11-18 10:55:23 -080048
49 // flag to use FlowPusher instead of FlowSwitchOperation/MessageDamper
50 private final static boolean enableFlowPusher = false;
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -080051
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080052 protected GraphDBOperation dbHandlerApi;
53 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080054
Jonathan Hart50a94982013-04-10 14:49:51 -070055 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070056 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070057 protected volatile IDatagridService datagridService;
58 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070059 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070060 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080061
Brian O'Connor8c166a72013-11-14 18:41:48 -080062 protected IFlowPusherService pusher;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080063
Naoki Shiota1a37ca12013-11-18 10:55:23 -080064 protected OFMessageDamper messageDamper;
65
66 //
67 // TODO: Values copied from elsewhere (class LearningSwitch).
68 // The local copy should go away!
69 //
70 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
71 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080072
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000073 // Flow Entry ID generation state
74 private static Random randomGenerator = new Random();
75 private static int nextFlowEntryIdPrefix = 0;
76 private static int nextFlowEntryIdSuffix = 0;
77 private static long nextFlowEntryId = 0;
78
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080079 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070080 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080081
82 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070083 private ScheduledExecutorService mapReaderScheduler;
84 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -070085
admin944ef4f2013-10-08 17:48:37 -070086 /**
87 * Periodic task for reading the Flow Entries and pushing changes
88 * into the switches.
89 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070090 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080091 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070092 try {
93 runImpl();
94 } catch (Exception e) {
95 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080096 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070097 return;
98 }
99 }
100
101 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700102 long startTime = System.nanoTime();
103 int counterAllFlowEntries = 0;
104 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700105
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800106 if (floodlightProvider == null) {
107 log.debug("FloodlightProvider service not found!");
108 return;
109 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000110 Map<Long, IOFSwitch> mySwitches =
111 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700112 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700113 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700114 return;
115 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700116 LinkedList<IFlowEntry> addFlowEntries =
117 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000118 LinkedList<IFlowEntry> deleteFlowEntries =
119 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700120
121 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700122 // Fetch all Flow Entries which need to be updated and select
123 // only my Flow Entries that need to be updated into the
124 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700125 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000126 Iterable<IFlowEntry> allFlowEntries =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800127 dbHandlerInner.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700128 for (IFlowEntry flowEntryObj : allFlowEntries) {
Naoki Shiota4e77de92013-11-18 17:29:54 -0800129 log.debug("flowEntryobj : {}", flowEntryObj);
130
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700131 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000132
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000133 String dpidStr = flowEntryObj.getSwitchDpid();
134 if (dpidStr == null)
135 continue;
136 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800137 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000138 if (mySwitch == null)
139 continue; // Ignore the entry: not my switch
140
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700141 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800142 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700143 if (flowObj == null)
144 continue; // Should NOT happen
145 if (flowObj.getFlowId() == null)
146 continue; // Invalid entry
147
148 //
149 // NOTE: For now we process the DELETE before the ADD
150 // to cover the more common scenario.
151 // TODO: This is error prone and needs to be fixed!
152 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000153 String userState = flowEntryObj.getUserState();
154 if (userState == null)
155 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700156 if (userState.equals("FE_USER_DELETE")) {
157 // An entry that needs to be deleted.
158 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700159 installFlowEntry(mySwitch, flowObj, flowEntryObj);
160 } else {
161 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700162 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700163 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700164 }
Naoki Shiota4e77de92013-11-18 17:29:54 -0800165
166 log.debug("addFlowEntries : {}", addFlowEntries);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700167
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700168 //
169 // Process the Flow Entries that need to be added
170 //
171 for (IFlowEntry flowEntryObj : addFlowEntries) {
172 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800173 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700174 if (flowObj == null)
175 continue; // Should NOT happen
176 if (flowObj.getFlowId() == null)
177 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700178
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700179 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700180 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000181 if (mySwitch == null)
182 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700183 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800184 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000185
186 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000187 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700188 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000189 //
190 // TODO: We should use the OpenFlow Barrier mechanism
191 // to check for errors, and delete the Flow Entries after the
192 // Barrier message is received.
193 //
194 while (! deleteFlowEntries.isEmpty()) {
195 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
196 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800197 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000198 if (flowObj == null) {
199 log.debug("Did not find FlowPath to be deleted");
200 continue;
201 }
202 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800203 dbHandlerInner.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000204 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700205
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800206 dbHandlerInner.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700207
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700208 long estimatedTime = System.nanoTime() - startTime;
209 double rate = 0.0;
210 if (estimatedTime > 0)
211 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
212 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
213 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
214 counterMyNotUpdatedFlowEntries + " in " +
215 (double)estimatedTime / 1000000000 + " sec: " +
216 rate + " paths/s";
217 log.debug(logMsg);
218 }
219 };
220
admin944ef4f2013-10-08 17:48:37 -0700221 /**
222 * Periodic task for reading the Flow Paths and recomputing the
223 * shortest paths.
224 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700225 final Runnable shortestPathReconcile = new Runnable() {
226 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700227 try {
228 runImpl();
229 } catch (Exception e) {
230 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800231 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700232 return;
233 }
234 }
235
236 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700237 long startTime = System.nanoTime();
238 int counterAllFlowPaths = 0;
239 int counterMyFlowPaths = 0;
240
241 if (floodlightProvider == null) {
242 log.debug("FloodlightProvider service not found!");
243 return;
244 }
245 Map<Long, IOFSwitch> mySwitches =
246 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700247 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700248 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700249 return;
250 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700251 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
252
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700253 //
254 // Fetch and recompute the Shortest Path for those
255 // Flow Paths this controller is responsible for.
256 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700257 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800258 Iterable<IFlowPath> allFlowPaths = dbHandlerInner.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700259 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700260 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700261 if (flowPathObj == null)
262 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700263
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700264 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000265 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700266 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700267 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700268 //
269 // Use the source DPID as a heuristic to decide
270 // which controller is responsible for maintaining the
271 // shortest path.
272 // NOTE: This heuristic is error-prone: if the switch
273 // goes away and no controller is responsible for that
274 // switch, then the original Flow Path is not cleaned-up
275 //
276 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
277 if (mySwitch == null)
278 continue; // Ignore: not my responsibility
279
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700280 // Test whether we need to maintain this flow
281 String flowPathTypeStr = flowPathObj.getFlowPathType();
282 if (flowPathTypeStr == null)
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700283 continue; // Could be invalid entry?
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700284 if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700285 continue; // No need to maintain this flow
286
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000287 //
288 // Test whether we need to complete the Flow cleanup,
289 // if the Flow has been deleted by the user.
290 //
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700291 String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
292 if ((flowPathUserStateStr != null)
293 && flowPathUserStateStr.equals("FP_USER_DELETE")) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000294 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700295 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000296 if (empty)
297 deleteFlows.add(flowPathObj);
298 }
299
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000300 // Fetch the fields needed to recompute the shortest path
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700301 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000302 Short srcPortShort = flowPathObj.getSrcPort();
303 String dstDpidStr = flowPathObj.getDstSwitch();
304 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700305 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700306 if ((dataPathSummaryStr == null) ||
307 (srcPortShort == null) ||
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000308 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700309 (dstPortShort == null) ||
310 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000311 continue;
312 }
313
314 Port srcPort = new Port(srcPortShort);
315 Dpid dstDpid = new Dpid(dstDpidStr);
316 Port dstPort = new Port(dstPortShort);
317 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
318 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700319 FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700320 FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700321 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000322
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700323 counterMyFlowPaths++;
324
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700325 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700326 // NOTE: Using here the regular getDatabaseShortestPath()
327 // method won't work here, because that method calls
328 // internally "conn.endTx(Transaction.COMMIT)", and that
329 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700330 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700331 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700332 // to avoid closing the transaction.
333 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700334 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700335 topologyNetService.getTopologyShortestPath(
336 topology,
337 srcSwitchPort,
338 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000339 if (dataPath == null) {
340 // We need the DataPath to compare the paths
341 dataPath = new DataPath();
342 dataPath.setSrcPort(srcSwitchPort);
343 dataPath.setDstPort(dstSwitchPort);
344 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700345 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000346
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700347 String newDataPathSummaryStr = dataPath.dataPathSummary();
348 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
349 continue; // Nothing changed
350
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700351 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700352 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000353
354 //
355 // Delete all leftover Flows marked for deletion from the
356 // Network MAP.
357 //
358 while (! deleteFlows.isEmpty()) {
359 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800360 dbHandlerInner.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000361 }
362
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700363 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700364
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800365 dbHandlerInner.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700366
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700367 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700368 double rate = 0.0;
369 if (estimatedTime > 0)
370 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700371 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700372 counterAllFlowPaths + " MyFlowPaths: " +
373 counterMyFlowPaths + " in " +
374 (double)estimatedTime / 1000000000 + " sec: " +
375 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700376 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800377 }
378 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700379
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800380
admin944ef4f2013-10-08 17:48:37 -0700381 /**
382 * Initialize the Flow Manager.
383 *
384 * @param conf the Graph Database configuration string.
385 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800386 @Override
387 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800388 dbHandlerApi = new GraphDBOperation(conf);
389 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800390 }
391
admin944ef4f2013-10-08 17:48:37 -0700392 /**
393 * Shutdown the Flow Manager operation.
394 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800395 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700396 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800397 }
398
admin944ef4f2013-10-08 17:48:37 -0700399 /**
400 * Shutdown the Flow Manager operation.
401 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800402 @Override
403 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700404 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800405 dbHandlerApi.close();
406 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800407 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800408
admin944ef4f2013-10-08 17:48:37 -0700409 /**
410 * Get the collection of offered module services.
411 *
412 * @return the collection of offered module services.
413 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800414 @Override
415 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
416 Collection<Class<? extends IFloodlightService>> l =
417 new ArrayList<Class<? extends IFloodlightService>>();
418 l.add(IFlowService.class);
419 return l;
420 }
421
admin944ef4f2013-10-08 17:48:37 -0700422 /**
423 * Get the collection of implemented services.
424 *
425 * @return the collection of implemented services.
426 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800427 @Override
428 public Map<Class<? extends IFloodlightService>, IFloodlightService>
429 getServiceImpls() {
430 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700431 IFloodlightService> m =
432 new HashMap<Class<? extends IFloodlightService>,
433 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800434 m.put(IFlowService.class, this);
435 return m;
436 }
437
admin944ef4f2013-10-08 17:48:37 -0700438 /**
439 * Get the collection of modules this module depends on.
440 *
441 * @return the collection of modules this module depends on.
442 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800443 @Override
444 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700445 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800446 Collection<Class<? extends IFloodlightService>> l =
447 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800448 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700449 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700450 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800451 l.add(IRestApiService.class);
452 return l;
453 }
454
admin944ef4f2013-10-08 17:48:37 -0700455 /**
456 * Initialize the module.
457 *
458 * @param context the module context to use for the initialization.
459 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800460 @Override
461 public void init(FloodlightModuleContext context)
462 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700463 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800464 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700465 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
466 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800467 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700468
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800469 if (enableFlowPusher) {
470 pusher = context.getServiceImpl(IFlowPusherService.class);
471 } else {
472 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
473 EnumSet.of(OFType.FLOW_MOD),
474 OFMESSAGE_DAMPER_TIMEOUT);
475 }
Brian O'Connor8c166a72013-11-14 18:41:48 -0800476
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700477 this.init("");
478
admin944ef4f2013-10-08 17:48:37 -0700479 mapReaderScheduler = Executors.newScheduledThreadPool(1);
480 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800481 }
482
admin944ef4f2013-10-08 17:48:37 -0700483 /**
484 * Get the next Flow Entry ID to use.
485 *
486 * @return the next Flow Entry ID to use.
487 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800488 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700489 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000490 //
491 // Generate the next Flow Entry ID.
492 // NOTE: For now, the higher 32 bits are random, and
493 // the lower 32 bits are sequential.
494 // In the future, we need a better allocation mechanism.
495 //
496 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
497 nextFlowEntryIdPrefix = randomGenerator.nextInt();
498 nextFlowEntryIdSuffix = 0;
499 } else {
500 nextFlowEntryIdSuffix++;
501 }
502 long result = (long)nextFlowEntryIdPrefix << 32;
503 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
504 return result;
505 }
506
admin944ef4f2013-10-08 17:48:37 -0700507 /**
508 * Startup module operation.
509 *
510 * @param context the module context to use for the startup.
511 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800512 @Override
513 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700514 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700515
admin944ef4f2013-10-08 17:48:37 -0700516 // Initialize the Flow Entry ID generator
517 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Naoki Shiota36e89432013-11-13 11:11:43 -0800518
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700519 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700520 // Create the Flow Event Handler thread and register it with the
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700521 // Datagrid Service
522 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700523 flowEventHandler = new FlowEventHandler(this, datagridService);
524 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -0700525
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700526 // Schedule the threads and periodic tasks
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700527 flowEventHandler.start();
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800528 if (! enableNotifications) {
529 mapReaderScheduler.scheduleAtFixedRate(
admin944ef4f2013-10-08 17:48:37 -0700530 mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800531 shortestPathReconcileScheduler.scheduleAtFixedRate(
admin944ef4f2013-10-08 17:48:37 -0700532 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800533 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800534 }
535
536 /**
537 * Add a flow.
538 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800539 * @param flowPath the Flow Path to install.
540 * @param flowId the return-by-reference Flow ID as assigned internally.
541 * @return true on success, otherwise false.
542 */
543 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700544 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700545 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700546 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700547 // in case the application didn't do it.
548 //
549 for (FlowEntry flowEntry : flowPath.flowEntries()) {
550 if (flowEntry.flowEntrySwitchState() ==
551 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
552 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
553 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700554 if (! flowEntry.isValidFlowId())
555 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700556 }
557
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800558 if (FlowDatabaseOperation.addFlow(this, dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700559 datagridService.notificationSendFlowAdded(flowPath);
560 return true;
561 }
562 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800563 }
564
565 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700566 * Add a flow entry to the Network MAP.
567 *
568 * @param flowObj the corresponding Flow Path object for the Flow Entry.
569 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700570 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700571 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700572 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800573 return FlowDatabaseOperation.addFlowEntry(this, dbHandlerInner,
574 flowObj, flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700575 }
576
577 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700578 * Delete a flow entry from the Network MAP.
579 *
580 * @param flowObj the corresponding Flow Path object for the Flow Entry.
581 * @param flowEntry the Flow Entry to delete.
582 * @return true on success, otherwise false.
583 */
584 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800585 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
586 flowObj, flowEntry);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800587 }
588
589 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000590 * Delete all previously added flows.
591 *
592 * @return true on success, otherwise false.
593 */
594 @Override
595 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800596 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700597 datagridService.notificationSendAllFlowsRemoved();
598 return true;
599 }
600 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000601 }
602
603 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800604 * Delete a previously added flow.
605 *
606 * @param flowId the Flow ID of the flow to delete.
607 * @return true on success, otherwise false.
608 */
609 @Override
610 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800611 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700612 datagridService.notificationSendFlowRemoved(flowId);
613 return true;
614 }
615 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800616 }
617
618 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000619 * Clear the state for all previously added flows.
620 *
621 * @return true on success, otherwise false.
622 */
623 @Override
624 public boolean clearAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800625 if (FlowDatabaseOperation.clearAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700626 datagridService.notificationSendAllFlowsRemoved();
627 return true;
628 }
629 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000630 }
631
632 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700633 * Clear the state for a previously added flow.
634 *
635 * @param flowId the Flow ID of the flow to clear.
636 * @return true on success, otherwise false.
637 */
638 @Override
639 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800640 if (FlowDatabaseOperation.clearFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700641 datagridService.notificationSendFlowRemoved(flowId);
642 return true;
643 }
644 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700645 }
646
647 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800648 * Get a previously added flow.
649 *
650 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800651 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800652 */
653 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800654 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800655 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700656 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800657
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700658 /**
659 * Get all installed flows by all installers.
660 *
661 * @return the Flow Paths if found, otherwise null.
662 */
663 @Override
664 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800665 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800666 }
667
668 /**
669 * Get all previously added flows by a specific installer for a given
670 * data path endpoints.
671 *
672 * @param installerId the Caller ID of the installer of the flow to get.
673 * @param dataPathEndpoints the data path endpoints of the flow to get.
674 * @return the Flow Paths if found, otherwise null.
675 */
676 @Override
677 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
678 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800679 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700680 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800681 }
682
683 /**
684 * Get all installed flows by all installers for given data path endpoints.
685 *
686 * @param dataPathEndpoints the data path endpoints of the flows to get.
687 * @return the Flow Paths if found, otherwise null.
688 */
689 @Override
690 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800691 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
692 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800693 }
694
695 /**
admin944ef4f2013-10-08 17:48:37 -0700696 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700697 *
admin944ef4f2013-10-08 17:48:37 -0700698 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700699 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700700 * @return the Flow Paths if found, otherwise null.
701 */
702 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700703 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
704 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800705 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700706 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700707 }
708
709 /**
admin944ef4f2013-10-08 17:48:37 -0700710 * Get all Flows information, without the associated Flow Entries.
711 *
712 * @return all Flows information, without the associated Flow Entries.
713 */
714 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800715 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandlerApi);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700716 }
717
718 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700719 * Add and maintain a shortest-path flow.
720 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700721 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700722 *
723 * @param flowPath the Flow Path with the endpoints and the match
724 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700725 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700726 */
727 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700728 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700729 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000730 // Don't do the shortest path computation here.
731 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700732 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700733
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700734 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700735 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700736 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700737
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700738 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700739 }
740
741 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800742 * Get the collection of my switches.
743 *
744 * @return the collection of my switches.
745 */
746 public Map<Long, IOFSwitch> getMySwitches() {
747 return floodlightProvider.getSwitches();
748 }
749
750 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800751 * Get the network topology.
752 *
753 * @return the network topology.
754 */
755 public Topology getTopology() {
756 return flowEventHandler.getTopology();
757 }
758
759 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700760 * Reconcile a flow.
761 *
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800762 * @param flowObj the flow that needs to be reconciled.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700763 * @param newDataPath the new data path to use.
764 * @return true on success, otherwise false.
765 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700766 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700767 String flowIdStr = flowObj.getFlowId();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700768
769 //
770 // Set the incoming port matching and the outgoing port output
771 // actions for each flow entry.
772 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700773 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700774 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700775 flowEntry.setFlowId(new FlowId(flowIdStr));
776
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700777 // Mark the Flow Entry as not updated in the switch
778 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700779 // Set the incoming port matching
780 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
781 flowEntry.setFlowEntryMatch(flowEntryMatch);
782 flowEntryMatch.enableInPort(flowEntry.inPort());
783
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700784 //
785 // Set the actions
786 //
787 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
788 //
789 // If the first Flow Entry, copy the Flow Path actions to it
790 //
791 if (idx == 0) {
792 String actionsStr = flowObj.getActions();
793 if (actionsStr != null) {
794 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
795 for (FlowEntryAction action : flowActions.actions())
796 flowEntryActions.addAction(action);
797 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700798 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700799 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700800 //
801 // Add the outgoing port output action
802 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700803 FlowEntryAction flowEntryAction = new FlowEntryAction();
804 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700805 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700806 }
807
808 //
809 // Remove the old Flow Entries, and add the new Flow Entries
810 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700811 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700812 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700813 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700814 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700815 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700816 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700817 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700818 }
819
820 //
821 // Set the Data Path Summary
822 //
823 String dataPathSummaryStr = newDataPath.dataPathSummary();
824 flowObj.setDataPathSummary(dataPathSummaryStr);
825
826 return true;
827 }
828
829 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700830 * Reconcile all flows in a set.
831 *
832 * @param flowObjSet the set of flows that need to be reconciliated.
833 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700834 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700835 if (! flowObjSet.iterator().hasNext())
836 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700837 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700838 }
839
840 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700841 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700842 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700843 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700844 * @param flowObj the flow path object for the flow entry to install.
845 * @param flowEntryObj the flow entry object to install.
846 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700847 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700848 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700849 IFlowEntry flowEntryObj) {
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800850 if (enableFlowPusher) {
851 return pusher.add(mySwitch, flowObj, flowEntryObj);
852 } else {
853 return FlowSwitchOperation.installFlowEntry(
854 floodlightProvider.getOFMessageFactory(),
855 messageDamper, mySwitch, flowObj, flowEntryObj);
856 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700857 }
858
859 /**
860 * Install a Flow Entry on a switch.
861 *
862 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700863 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700864 * @param flowEntry the flow entry to install.
865 * @return true on success, otherwise false.
866 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700867 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700868 FlowEntry flowEntry) {
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800869 if (enableFlowPusher) {
870 return pusher.add(mySwitch, flowPath, flowEntry);
871 } else {
872 return FlowSwitchOperation.installFlowEntry(
873 floodlightProvider.getOFMessageFactory(),
874 messageDamper, mySwitch, flowPath, flowEntry);
875 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700876 }
877
878 /**
879 * Remove a Flow Entry from a switch.
880 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700881 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700882 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700883 * @param flowEntry the flow entry to remove.
884 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700885 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700886 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700887 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700888 //
889 // The installFlowEntry() method implements both installation
890 // and removal of flow entries.
891 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700892 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700893 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700894
895 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800896 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700897 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800898 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700899 * are pushed.
900 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800901 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700902 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800903 public void pushModifiedFlowEntriesToSwitches(
904 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700905 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800906 if (! enableNotifications)
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700907 return;
908
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800909 if (modifiedFlowEntries.isEmpty())
910 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700911
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800912 Map<Long, IOFSwitch> mySwitches = getMySwitches();
913
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800914 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
915 FlowPath flowPath = flowPair.flowPath;
916 FlowEntry flowEntry = flowPair.flowEntry;
917
918 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
919 if (mySwitch == null)
920 continue;
921
922 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
923
924 //
925 // Install the Flow Entry into the switch
926 //
927 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
928 String logMsg = "Cannot install Flow Entry " +
929 flowEntry.flowEntryId() +
930 " from Flow Path " + flowPath.flowId() +
931 " on switch " + flowEntry.dpid();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700932 log.error(logMsg);
933 continue;
934 }
935
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800936 //
937 // NOTE: Here we assume that the switch has been
938 // successfully updated.
939 //
940 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
941 }
942 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700943
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800944 /**
945 * Push modified Flow Entries to the datagrid.
946 *
947 * @param modifiedFlowEntries the collection of modified Flow Entries.
948 */
949 public void pushModifiedFlowEntriesToDatagrid(
950 Collection<FlowPathEntryPair> modifiedFlowEntries) {
951 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800952 if (! enableNotifications)
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800953 return;
954
955 if (modifiedFlowEntries.isEmpty())
956 return;
957
958 Map<Long, IOFSwitch> mySwitches = getMySwitches();
959
960 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
961 FlowEntry flowEntry = flowPair.flowEntry;
962
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800963 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
964
965 //
966 // TODO: For now Flow Entries are removed by all instances,
967 // even if this Flow Entry is not for our switches.
968 //
969 // This is needed to handle the case a switch going down:
970 // it has no Master controller instance, hence no
971 // controller instance will cleanup its flow entries.
972 // This is sub-optimal: we need to elect a controller
973 // instance to handle the cleanup of such orphaned flow
974 // entries.
975 //
976 if (mySwitch == null) {
977 if (flowEntry.flowEntryUserState() !=
978 FlowEntryUserState.FE_USER_DELETE) {
979 continue;
980 }
981 if (! flowEntry.isValidFlowEntryId())
982 continue;
983 }
984
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800985 log.debug("Pushing Flow Entry To Datagrid: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800986 //
987 // Write the Flow Entry to the Datagrid
988 //
989 switch (flowEntry.flowEntryUserState()) {
990 case FE_USER_ADD:
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700991 if (mySwitch == null)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800992 break; // Install only flow entries for my switches
993 datagridService.notificationSendFlowEntryAdded(flowEntry);
994 break;
995 case FE_USER_MODIFY:
996 if (mySwitch == null)
997 break; // Install only flow entries for my switches
998 datagridService.notificationSendFlowEntryUpdated(flowEntry);
999 break;
1000 case FE_USER_DELETE:
1001 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
1002 break;
1003 }
1004 }
1005 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001006
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001007 /**
1008 * Push Flow Entries to the Network MAP.
1009 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001010 * NOTE: The Flow Entries are pushed only on the instance responsible
1011 * for the first switch. This is to avoid database errors when multiple
1012 * instances are writing Flow Entries for the same Flow Path.
1013 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001014 * @param modifiedFlowEntries the collection of Flow Entries to push.
1015 */
1016 public void pushModifiedFlowEntriesToDatabase(
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001017 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001018 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -08001019 if (! enableNotifications)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001020 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001021
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001022 if (modifiedFlowEntries.isEmpty())
1023 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001024
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001025 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001026
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001027 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
1028 FlowPath flowPath = flowPair.flowPath;
1029 FlowEntry flowEntry = flowPair.flowEntry;
1030
1031 if (! flowEntry.isValidFlowEntryId())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001032 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001033
1034 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001035 // Push the changes only on the instance responsible for the
1036 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001037 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001038 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
1039 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
1040 if (mySrcSwitch == null)
1041 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001042
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001043 log.debug("Pushing Flow Entry To Database: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001044 //
1045 // Write the Flow Entry to the Network Map
1046 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001047 // NOTE: We try a number of times, in case somehow some other
1048 // instances are writing at the same time.
1049 // Apparently, if other instances are writing at the same time
1050 // this will trigger an error.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001051 //
1052 for (int i = 0; i < 6; i++) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001053 try {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001054 //
1055 // Find the Flow Path in the Network MAP.
1056 //
1057 // NOTE: The Flow Path might not be found if the Flow was
1058 // just removed by some other controller instance.
1059 //
1060 IFlowPath flowObj =
1061 dbHandlerInner.searchFlowPath(flowEntry.flowId());
1062 if (flowObj == null) {
1063 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001064 log.error(logMsg);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001065 break;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001066 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001067
1068 // Write the Flow Entry
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001069 switch (flowEntry.flowEntryUserState()) {
1070 case FE_USER_ADD:
1071 // FALLTHROUGH
1072 case FE_USER_MODIFY:
1073 if (addFlowEntry(flowObj, flowEntry) == null) {
1074 String logMsg = "Cannot write to Network MAP Flow Entry " +
1075 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001076 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001077 " on switch " + flowEntry.dpid();
1078 log.error(logMsg);
1079 }
1080 break;
1081 case FE_USER_DELETE:
1082 if (deleteFlowEntry(flowObj, flowEntry) == false) {
1083 String logMsg = "Cannot remove from Network MAP Flow Entry " +
1084 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001085 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001086 " on switch " + flowEntry.dpid();
1087 log.error(logMsg);
1088 }
1089 break;
1090 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001091
1092 // Commit to the database
1093 dbHandlerInner.commit();
1094 break; // Success
1095
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001096 } catch (Exception e) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -08001097 log.debug("Exception writing Flow Entry to Network MAP: ", e);
1098 dbHandlerInner.rollback();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001099 // Wait a bit (random value [1ms, 20ms] and try again
1100 int delay = 1 + randomGenerator.nextInt() % 20;
1101 try {
1102 Thread.sleep(delay);
1103 } catch (Exception e0) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001104 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001105 }
1106 }
1107 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001108 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001109}