blob: ab4be1a2c5ee7c23bb1bb0dab6cf1fa2ffbe9da1 [file] [log] [blame]
HIGUCHI Yuta60a10142013-06-14 15:50:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
3import java.util.ArrayList;
4import java.util.Collection;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08005import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08006import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00007import java.util.LinkedList;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08008import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +00009import java.util.Random;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.concurrent.Executors;
11import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080012import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080013
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080016import net.floodlightcontroller.core.module.FloodlightModuleContext;
17import net.floodlightcontroller.core.module.FloodlightModuleException;
18import net.floodlightcontroller.core.module.IFloodlightModule;
19import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.util.OFMessageDamper;
Pavlin Radoslavov05378272013-10-19 23:23:05 -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;
Naoki Shiotaaea88582013-11-12 17:58:34 -080029import net.onrc.onos.ofcontroller.flowprogrammer.FlowPusher;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070030import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070031import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -070032import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070033import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080034
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080035import org.openflow.protocol.OFType;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
admin944ef4f2013-10-08 17:48:37 -070039/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070040 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070041 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070042public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -080044 //
45 // TODO: A temporary variable to switch between the poll-based and
46 // notification mechanism for the Flow Manager.
47 //
48 private final static boolean enableNotifications = false;
49
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080050 protected GraphDBOperation dbHandlerApi;
51 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080052
Jonathan Hart50a94982013-04-10 14:49:51 -070053 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070054 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070055 protected volatile IDatagridService datagridService;
56 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070057 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070058 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080059
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080060 protected FlowPusher pusher;
Naoki Shiota36e89432013-11-13 11:11:43 -080061 private static final int NUM_PUSHER_THREAD = 1;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080062
Naoki Shiota36e89432013-11-13 11:11:43 -080063// LEGACY
64// 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) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700129 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000130
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000131 String dpidStr = flowEntryObj.getSwitchDpid();
132 if (dpidStr == null)
133 continue;
134 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800135 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000136 if (mySwitch == null)
137 continue; // Ignore the entry: not my switch
138
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700139 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800140 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700141 if (flowObj == null)
142 continue; // Should NOT happen
143 if (flowObj.getFlowId() == null)
144 continue; // Invalid entry
145
146 //
147 // NOTE: For now we process the DELETE before the ADD
148 // to cover the more common scenario.
149 // TODO: This is error prone and needs to be fixed!
150 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000151 String userState = flowEntryObj.getUserState();
152 if (userState == null)
153 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700154 if (userState.equals("FE_USER_DELETE")) {
155 // An entry that needs to be deleted.
156 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700157 installFlowEntry(mySwitch, flowObj, flowEntryObj);
158 } else {
159 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700160 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700161 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700162 }
163
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700164 //
165 // Process the Flow Entries that need to be added
166 //
167 for (IFlowEntry flowEntryObj : addFlowEntries) {
168 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800169 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700170 if (flowObj == null)
171 continue; // Should NOT happen
172 if (flowObj.getFlowId() == null)
173 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700174
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700175 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700176 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000177 if (mySwitch == null)
178 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700179 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800180 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000181
182 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000183 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700184 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000185 //
186 // TODO: We should use the OpenFlow Barrier mechanism
187 // to check for errors, and delete the Flow Entries after the
188 // Barrier message is received.
189 //
190 while (! deleteFlowEntries.isEmpty()) {
191 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
192 IFlowPath flowObj =
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800193 dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000194 if (flowObj == null) {
195 log.debug("Did not find FlowPath to be deleted");
196 continue;
197 }
198 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800199 dbHandlerInner.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000200 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700201
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800202 dbHandlerInner.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700203
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700204 long estimatedTime = System.nanoTime() - startTime;
205 double rate = 0.0;
206 if (estimatedTime > 0)
207 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
208 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
209 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
210 counterMyNotUpdatedFlowEntries + " in " +
211 (double)estimatedTime / 1000000000 + " sec: " +
212 rate + " paths/s";
213 log.debug(logMsg);
214 }
215 };
216
admin944ef4f2013-10-08 17:48:37 -0700217 /**
218 * Periodic task for reading the Flow Paths and recomputing the
219 * shortest paths.
220 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700221 final Runnable shortestPathReconcile = new Runnable() {
222 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700223 try {
224 runImpl();
225 } catch (Exception e) {
226 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800227 dbHandlerInner.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700228 return;
229 }
230 }
231
232 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700233 long startTime = System.nanoTime();
234 int counterAllFlowPaths = 0;
235 int counterMyFlowPaths = 0;
236
237 if (floodlightProvider == null) {
238 log.debug("FloodlightProvider service not found!");
239 return;
240 }
241 Map<Long, IOFSwitch> mySwitches =
242 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700243 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700244 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700245 return;
246 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700247 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
248
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700249 //
250 // Fetch and recompute the Shortest Path for those
251 // Flow Paths this controller is responsible for.
252 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700253 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800254 Iterable<IFlowPath> allFlowPaths = dbHandlerInner.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700255 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700256 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700257 if (flowPathObj == null)
258 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700259
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700260 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000261 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700262 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700263 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700264 //
265 // Use the source DPID as a heuristic to decide
266 // which controller is responsible for maintaining the
267 // shortest path.
268 // NOTE: This heuristic is error-prone: if the switch
269 // goes away and no controller is responsible for that
270 // switch, then the original Flow Path is not cleaned-up
271 //
272 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
273 if (mySwitch == null)
274 continue; // Ignore: not my responsibility
275
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700276 // Test whether we need to maintain this flow
277 String flowPathTypeStr = flowPathObj.getFlowPathType();
278 if (flowPathTypeStr == null)
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700279 continue; // Could be invalid entry?
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700280 if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700281 continue; // No need to maintain this flow
282
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000283 //
284 // Test whether we need to complete the Flow cleanup,
285 // if the Flow has been deleted by the user.
286 //
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700287 String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
288 if ((flowPathUserStateStr != null)
289 && flowPathUserStateStr.equals("FP_USER_DELETE")) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000290 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700291 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000292 if (empty)
293 deleteFlows.add(flowPathObj);
294 }
295
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000296 // Fetch the fields needed to recompute the shortest path
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700297 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000298 Short srcPortShort = flowPathObj.getSrcPort();
299 String dstDpidStr = flowPathObj.getDstSwitch();
300 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700301 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700302 if ((dataPathSummaryStr == null) ||
303 (srcPortShort == null) ||
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000304 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700305 (dstPortShort == null) ||
306 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000307 continue;
308 }
309
310 Port srcPort = new Port(srcPortShort);
311 Dpid dstDpid = new Dpid(dstDpidStr);
312 Port dstPort = new Port(dstPortShort);
313 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
314 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700315 FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
Pavlin Radoslavov7d4a40e2013-10-27 23:39:40 -0700316 FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700317 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000318
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700319 counterMyFlowPaths++;
320
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700321 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700322 // NOTE: Using here the regular getDatabaseShortestPath()
323 // method won't work here, because that method calls
324 // internally "conn.endTx(Transaction.COMMIT)", and that
325 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700326 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700327 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700328 // to avoid closing the transaction.
329 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700330 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700331 topologyNetService.getTopologyShortestPath(
332 topology,
333 srcSwitchPort,
334 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000335 if (dataPath == null) {
336 // We need the DataPath to compare the paths
337 dataPath = new DataPath();
338 dataPath.setSrcPort(srcSwitchPort);
339 dataPath.setDstPort(dstSwitchPort);
340 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700341 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000342
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700343 String newDataPathSummaryStr = dataPath.dataPathSummary();
344 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
345 continue; // Nothing changed
346
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700347 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700348 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000349
350 //
351 // Delete all leftover Flows marked for deletion from the
352 // Network MAP.
353 //
354 while (! deleteFlows.isEmpty()) {
355 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800356 dbHandlerInner.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000357 }
358
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700359 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700360
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800361 dbHandlerInner.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700362
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700363 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700364 double rate = 0.0;
365 if (estimatedTime > 0)
366 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700367 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700368 counterAllFlowPaths + " MyFlowPaths: " +
369 counterMyFlowPaths + " in " +
370 (double)estimatedTime / 1000000000 + " sec: " +
371 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700372 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800373 }
374 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700375
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800376
admin944ef4f2013-10-08 17:48:37 -0700377 /**
378 * Initialize the Flow Manager.
379 *
380 * @param conf the Graph Database configuration string.
381 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800382 @Override
383 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800384 dbHandlerApi = new GraphDBOperation(conf);
385 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800386 }
387
admin944ef4f2013-10-08 17:48:37 -0700388 /**
389 * Shutdown the Flow Manager operation.
390 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800391 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700392 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800393 }
394
admin944ef4f2013-10-08 17:48:37 -0700395 /**
396 * Shutdown the Flow Manager operation.
397 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800398 @Override
399 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700400 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800401 dbHandlerApi.close();
402 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800403 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800404
admin944ef4f2013-10-08 17:48:37 -0700405 /**
406 * Get the collection of offered module services.
407 *
408 * @return the collection of offered module services.
409 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800410 @Override
411 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
412 Collection<Class<? extends IFloodlightService>> l =
413 new ArrayList<Class<? extends IFloodlightService>>();
414 l.add(IFlowService.class);
415 return l;
416 }
417
admin944ef4f2013-10-08 17:48:37 -0700418 /**
419 * Get the collection of implemented services.
420 *
421 * @return the collection of implemented services.
422 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800423 @Override
424 public Map<Class<? extends IFloodlightService>, IFloodlightService>
425 getServiceImpls() {
426 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700427 IFloodlightService> m =
428 new HashMap<Class<? extends IFloodlightService>,
429 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800430 m.put(IFlowService.class, this);
431 return m;
432 }
433
admin944ef4f2013-10-08 17:48:37 -0700434 /**
435 * Get the collection of modules this module depends on.
436 *
437 * @return the collection of modules this module depends on.
438 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800439 @Override
440 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700441 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800442 Collection<Class<? extends IFloodlightService>> l =
443 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800444 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700445 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700446 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800447 l.add(IRestApiService.class);
448 return l;
449 }
450
admin944ef4f2013-10-08 17:48:37 -0700451 /**
452 * Initialize the module.
453 *
454 * @param context the module context to use for the initialization.
455 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800456 @Override
457 public void init(FloodlightModuleContext context)
458 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700459 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800460 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700461 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
462 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800463 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700464
Naoki Shiota36e89432013-11-13 11:11:43 -0800465// LEGACY
466// messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
467// EnumSet.of(OFType.FLOW_MOD),
468// OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700469
Naoki Shiota36e89432013-11-13 11:11:43 -0800470 pusher = new FlowPusher(NUM_PUSHER_THREAD);
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800471 pusher.init(null, floodlightProvider.getOFMessageFactory(), null);
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700472 this.init("");
473
admin944ef4f2013-10-08 17:48:37 -0700474 mapReaderScheduler = Executors.newScheduledThreadPool(1);
475 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800476 }
477
admin944ef4f2013-10-08 17:48:37 -0700478 /**
479 * Get the next Flow Entry ID to use.
480 *
481 * @return the next Flow Entry ID to use.
482 */
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700483 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000484 //
485 // Generate the next Flow Entry ID.
486 // NOTE: For now, the higher 32 bits are random, and
487 // the lower 32 bits are sequential.
488 // In the future, we need a better allocation mechanism.
489 //
490 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
491 nextFlowEntryIdPrefix = randomGenerator.nextInt();
492 nextFlowEntryIdSuffix = 0;
493 } else {
494 nextFlowEntryIdSuffix++;
495 }
496 long result = (long)nextFlowEntryIdPrefix << 32;
497 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
498 return result;
499 }
500
admin944ef4f2013-10-08 17:48:37 -0700501 /**
502 * Startup module operation.
503 *
504 * @param context the module context to use for the startup.
505 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800506 @Override
507 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700508 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700509
admin944ef4f2013-10-08 17:48:37 -0700510 // Initialize the Flow Entry ID generator
511 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700512
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800513 pusher.start();
Naoki Shiota36e89432013-11-13 11:11:43 -0800514
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700515 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700516 // Create the Flow Event Handler thread and register it with the
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700517 // Datagrid Service
518 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700519 flowEventHandler = new FlowEventHandler(this, datagridService);
520 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovaaace7f2013-10-25 19:42:00 -0700521
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700522 // Schedule the threads and periodic tasks
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700523 flowEventHandler.start();
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800524 if (! enableNotifications) {
525 mapReaderScheduler.scheduleAtFixedRate(
admin944ef4f2013-10-08 17:48:37 -0700526 mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800527 shortestPathReconcileScheduler.scheduleAtFixedRate(
admin944ef4f2013-10-08 17:48:37 -0700528 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800529 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800530 }
531
532 /**
533 * Add a flow.
534 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800535 * @param flowPath the Flow Path to install.
536 * @param flowId the return-by-reference Flow ID as assigned internally.
537 * @return true on success, otherwise false.
538 */
539 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700540 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700541 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700542 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700543 // in case the application didn't do it.
544 //
545 for (FlowEntry flowEntry : flowPath.flowEntries()) {
546 if (flowEntry.flowEntrySwitchState() ==
547 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
548 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
549 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700550 if (! flowEntry.isValidFlowId())
551 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700552 }
553
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800554 if (FlowDatabaseOperation.addFlow(this, dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700555 datagridService.notificationSendFlowAdded(flowPath);
556 return true;
557 }
558 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800559 }
560
561 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700562 * Add a flow entry to the Network MAP.
563 *
564 * @param flowObj the corresponding Flow Path object for the Flow Entry.
565 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700566 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700567 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700568 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800569 return FlowDatabaseOperation.addFlowEntry(this, dbHandlerInner,
570 flowObj, flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700571 }
572
573 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700574 * Delete a flow entry from the Network MAP.
575 *
576 * @param flowObj the corresponding Flow Path object for the Flow Entry.
577 * @param flowEntry the Flow Entry to delete.
578 * @return true on success, otherwise false.
579 */
580 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800581 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
582 flowObj, flowEntry);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800583 }
584
585 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000586 * Delete all previously added flows.
587 *
588 * @return true on success, otherwise false.
589 */
590 @Override
591 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800592 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700593 datagridService.notificationSendAllFlowsRemoved();
594 return true;
595 }
596 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000597 }
598
599 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800600 * Delete a previously added flow.
601 *
602 * @param flowId the Flow ID of the flow to delete.
603 * @return true on success, otherwise false.
604 */
605 @Override
606 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800607 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700608 datagridService.notificationSendFlowRemoved(flowId);
609 return true;
610 }
611 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800612 }
613
614 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000615 * Clear the state for all previously added flows.
616 *
617 * @return true on success, otherwise false.
618 */
619 @Override
620 public boolean clearAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800621 if (FlowDatabaseOperation.clearAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700622 datagridService.notificationSendAllFlowsRemoved();
623 return true;
624 }
625 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000626 }
627
628 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700629 * Clear the state for a previously added flow.
630 *
631 * @param flowId the Flow ID of the flow to clear.
632 * @return true on success, otherwise false.
633 */
634 @Override
635 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800636 if (FlowDatabaseOperation.clearFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700637 datagridService.notificationSendFlowRemoved(flowId);
638 return true;
639 }
640 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700641 }
642
643 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800644 * Get a previously added flow.
645 *
646 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800647 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800648 */
649 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800650 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800651 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700652 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800653
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700654 /**
655 * Get all installed flows by all installers.
656 *
657 * @return the Flow Paths if found, otherwise null.
658 */
659 @Override
660 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800661 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800662 }
663
664 /**
665 * Get all previously added flows by a specific installer for a given
666 * data path endpoints.
667 *
668 * @param installerId the Caller ID of the installer of the flow to get.
669 * @param dataPathEndpoints the data path endpoints of the flow to get.
670 * @return the Flow Paths if found, otherwise null.
671 */
672 @Override
673 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
674 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800675 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700676 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800677 }
678
679 /**
680 * Get all installed flows by all installers for given data path endpoints.
681 *
682 * @param dataPathEndpoints the data path endpoints of the flows to get.
683 * @return the Flow Paths if found, otherwise null.
684 */
685 @Override
686 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800687 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
688 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800689 }
690
691 /**
admin944ef4f2013-10-08 17:48:37 -0700692 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700693 *
admin944ef4f2013-10-08 17:48:37 -0700694 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700695 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700696 * @return the Flow Paths if found, otherwise null.
697 */
698 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700699 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
700 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800701 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700702 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700703 }
704
705 /**
admin944ef4f2013-10-08 17:48:37 -0700706 * Get all Flows information, without the associated Flow Entries.
707 *
708 * @return all Flows information, without the associated Flow Entries.
709 */
710 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800711 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandlerApi);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700712 }
713
714 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700715 * Add and maintain a shortest-path flow.
716 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700717 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700718 *
719 * @param flowPath the Flow Path with the endpoints and the match
720 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700721 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700722 */
723 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700724 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700725 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000726 // Don't do the shortest path computation here.
727 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700728 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700729
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700730 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700731 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700732 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700733
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700734 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700735 }
736
737 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800738 * Get the collection of my switches.
739 *
740 * @return the collection of my switches.
741 */
742 public Map<Long, IOFSwitch> getMySwitches() {
743 return floodlightProvider.getSwitches();
744 }
745
746 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800747 * Get the network topology.
748 *
749 * @return the network topology.
750 */
751 public Topology getTopology() {
752 return flowEventHandler.getTopology();
753 }
754
755 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700756 * Reconcile a flow.
757 *
758 * @param flowObj the flow that needs to be reconciliated.
759 * @param newDataPath the new data path to use.
760 * @return true on success, otherwise false.
761 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700762 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700763 String flowIdStr = flowObj.getFlowId();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700764
765 //
766 // Set the incoming port matching and the outgoing port output
767 // actions for each flow entry.
768 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700769 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700770 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700771 flowEntry.setFlowId(new FlowId(flowIdStr));
772
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700773 // Mark the Flow Entry as not updated in the switch
774 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700775 // Set the incoming port matching
776 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
777 flowEntry.setFlowEntryMatch(flowEntryMatch);
778 flowEntryMatch.enableInPort(flowEntry.inPort());
779
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700780 //
781 // Set the actions
782 //
783 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
784 //
785 // If the first Flow Entry, copy the Flow Path actions to it
786 //
787 if (idx == 0) {
788 String actionsStr = flowObj.getActions();
789 if (actionsStr != null) {
790 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
791 for (FlowEntryAction action : flowActions.actions())
792 flowEntryActions.addAction(action);
793 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700794 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700795 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700796 //
797 // Add the outgoing port output action
798 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700799 FlowEntryAction flowEntryAction = new FlowEntryAction();
800 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700801 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700802 }
803
804 //
805 // Remove the old Flow Entries, and add the new Flow Entries
806 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700807 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700808 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700809 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700810 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700811 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700812 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700813 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700814 }
815
816 //
817 // Set the Data Path Summary
818 //
819 String dataPathSummaryStr = newDataPath.dataPathSummary();
820 flowObj.setDataPathSummary(dataPathSummaryStr);
821
822 return true;
823 }
824
825 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700826 * Reconcile all flows in a set.
827 *
828 * @param flowObjSet the set of flows that need to be reconciliated.
829 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700830 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700831 if (! flowObjSet.iterator().hasNext())
832 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700833 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700834 }
835
836 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700837 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700838 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700839 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700840 * @param flowObj the flow path object for the flow entry to install.
841 * @param flowEntryObj the flow entry object to install.
842 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700843 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700844 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700845 IFlowEntry flowEntryObj) {
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800846 return pusher.add(mySwitch, flowObj, flowEntryObj);
Naoki Shiota36e89432013-11-13 11:11:43 -0800847
848// LEGACY
849// return FlowSwitchOperation.installFlowEntry(
850// floodlightProvider.getOFMessageFactory(),
851// messageDamper, mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700852 }
853
854 /**
855 * Install a Flow Entry on a switch.
856 *
857 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700858 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700859 * @param flowEntry the flow entry to install.
860 * @return true on success, otherwise false.
861 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700862 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700863 FlowEntry flowEntry) {
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800864 return pusher.add(mySwitch, flowPath, flowEntry);
Naoki Shiota36e89432013-11-13 11:11:43 -0800865
866// LEGACY
867// return FlowSwitchOperation.installFlowEntry(
868// floodlightProvider.getOFMessageFactory(),
869// messageDamper, mySwitch, flowPath, flowEntry);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700870 }
871
872 /**
873 * Remove a Flow Entry from a switch.
874 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700875 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700876 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700877 * @param flowEntry the flow entry to remove.
878 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700879 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700880 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700881 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700882 //
883 // The installFlowEntry() method implements both installation
884 // and removal of flow entries.
885 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700886 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700887 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700888
889 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800890 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700891 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800892 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700893 * are pushed.
894 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800895 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700896 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800897 public void pushModifiedFlowEntriesToSwitches(
898 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700899 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800900 if (! enableNotifications)
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700901 return;
902
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800903 if (modifiedFlowEntries.isEmpty())
904 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700905
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800906 Map<Long, IOFSwitch> mySwitches = getMySwitches();
907
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800908 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
909 FlowPath flowPath = flowPair.flowPath;
910 FlowEntry flowEntry = flowPair.flowEntry;
911
912 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
913 if (mySwitch == null)
914 continue;
915
916 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
917
918 //
919 // Install the Flow Entry into the switch
920 //
921 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
922 String logMsg = "Cannot install Flow Entry " +
923 flowEntry.flowEntryId() +
924 " from Flow Path " + flowPath.flowId() +
925 " on switch " + flowEntry.dpid();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700926 log.error(logMsg);
927 continue;
928 }
929
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800930 //
931 // NOTE: Here we assume that the switch has been
932 // successfully updated.
933 //
934 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
935 }
936 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700937
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800938 /**
939 * Push modified Flow Entries to the datagrid.
940 *
941 * @param modifiedFlowEntries the collection of modified Flow Entries.
942 */
943 public void pushModifiedFlowEntriesToDatagrid(
944 Collection<FlowPathEntryPair> modifiedFlowEntries) {
945 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -0800946 if (! enableNotifications)
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800947 return;
948
949 if (modifiedFlowEntries.isEmpty())
950 return;
951
952 Map<Long, IOFSwitch> mySwitches = getMySwitches();
953
954 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
955 FlowEntry flowEntry = flowPair.flowEntry;
956
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800957 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
958
959 //
960 // TODO: For now Flow Entries are removed by all instances,
961 // even if this Flow Entry is not for our switches.
962 //
963 // This is needed to handle the case a switch going down:
964 // it has no Master controller instance, hence no
965 // controller instance will cleanup its flow entries.
966 // This is sub-optimal: we need to elect a controller
967 // instance to handle the cleanup of such orphaned flow
968 // entries.
969 //
970 if (mySwitch == null) {
971 if (flowEntry.flowEntryUserState() !=
972 FlowEntryUserState.FE_USER_DELETE) {
973 continue;
974 }
975 if (! flowEntry.isValidFlowEntryId())
976 continue;
977 }
978
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800979 log.debug("Pushing Flow Entry To Datagrid: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800980 //
981 // Write the Flow Entry to the Datagrid
982 //
983 switch (flowEntry.flowEntryUserState()) {
984 case FE_USER_ADD:
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700985 if (mySwitch == null)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800986 break; // Install only flow entries for my switches
987 datagridService.notificationSendFlowEntryAdded(flowEntry);
988 break;
989 case FE_USER_MODIFY:
990 if (mySwitch == null)
991 break; // Install only flow entries for my switches
992 datagridService.notificationSendFlowEntryUpdated(flowEntry);
993 break;
994 case FE_USER_DELETE:
995 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
996 break;
997 }
998 }
999 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001000
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001001 /**
1002 * Push Flow Entries to the Network MAP.
1003 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001004 * NOTE: The Flow Entries are pushed only on the instance responsible
1005 * for the first switch. This is to avoid database errors when multiple
1006 * instances are writing Flow Entries for the same Flow Path.
1007 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001008 * @param modifiedFlowEntries the collection of Flow Entries to push.
1009 */
1010 public void pushModifiedFlowEntriesToDatabase(
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001011 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001012 // TODO: For now, the pushing of Flow Entries is disabled
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -08001013 if (! enableNotifications)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001014 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001015
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001016 if (modifiedFlowEntries.isEmpty())
1017 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001018
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001019 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001020
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001021 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
1022 FlowPath flowPath = flowPair.flowPath;
1023 FlowEntry flowEntry = flowPair.flowEntry;
1024
1025 if (! flowEntry.isValidFlowEntryId())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001026 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001027
1028 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001029 // Push the changes only on the instance responsible for the
1030 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001031 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001032 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
1033 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
1034 if (mySrcSwitch == null)
1035 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001036
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001037 log.debug("Pushing Flow Entry To Database: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001038 //
1039 // Write the Flow Entry to the Network Map
1040 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001041 // NOTE: We try a number of times, in case somehow some other
1042 // instances are writing at the same time.
1043 // Apparently, if other instances are writing at the same time
1044 // this will trigger an error.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001045 //
1046 for (int i = 0; i < 6; i++) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001047 try {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001048 //
1049 // Find the Flow Path in the Network MAP.
1050 //
1051 // NOTE: The Flow Path might not be found if the Flow was
1052 // just removed by some other controller instance.
1053 //
1054 IFlowPath flowObj =
1055 dbHandlerInner.searchFlowPath(flowEntry.flowId());
1056 if (flowObj == null) {
1057 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001058 log.error(logMsg);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001059 break;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001060 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001061
1062 // Write the Flow Entry
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001063 switch (flowEntry.flowEntryUserState()) {
1064 case FE_USER_ADD:
1065 // FALLTHROUGH
1066 case FE_USER_MODIFY:
1067 if (addFlowEntry(flowObj, flowEntry) == null) {
1068 String logMsg = "Cannot write to Network MAP Flow Entry " +
1069 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001070 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001071 " on switch " + flowEntry.dpid();
1072 log.error(logMsg);
1073 }
1074 break;
1075 case FE_USER_DELETE:
1076 if (deleteFlowEntry(flowObj, flowEntry) == false) {
1077 String logMsg = "Cannot remove from Network MAP Flow Entry " +
1078 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001079 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001080 " on switch " + flowEntry.dpid();
1081 log.error(logMsg);
1082 }
1083 break;
1084 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001085
1086 // Commit to the database
1087 dbHandlerInner.commit();
1088 break; // Success
1089
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001090 } catch (Exception e) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -08001091 log.debug("Exception writing Flow Entry to Network MAP: ", e);
1092 dbHandlerInner.rollback();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -08001093 // Wait a bit (random value [1ms, 20ms] and try again
1094 int delay = 1 + randomGenerator.nextInt() % 20;
1095 try {
1096 Thread.sleep(delay);
1097 } catch (Exception e0) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -07001098 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001099 }
1100 }
1101 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -07001102 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001103}