blob: 9e1c1ec6d7d896e4d7dbc1b3168e88dd153b9d0c [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;
5import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00006import java.util.LinkedList;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08007import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +00008import java.util.Random;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -08009import java.util.concurrent.BlockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080010import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import 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;
yoshi2fd4c7e2013-11-22 15:47:55 -080022import net.onrc.onos.graph.DBOperation;
23import net.onrc.onos.graph.GraphDBManager;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070024import net.onrc.onos.datagrid.IDatagridService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070025import net.onrc.onos.ofcontroller.core.INetMapStorage;
26import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
27import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070028import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070029import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080030import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
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
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -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 {
Naoki Shiota1a37ca12013-11-18 10:55:23 -080042 // flag to use FlowPusher instead of FlowSwitchOperation/MessageDamper
43 private final static boolean enableFlowPusher = false;
yoshitomob292c622013-11-23 14:35:58 -080044 protected DBOperation dbHandlerApi;
45 protected DBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080046
Jonathan Hart50a94982013-04-10 14:49:51 -070047 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070048 protected volatile IDatagridService datagridService;
49 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070050 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070051 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080052
Brian O'Connor8c166a72013-11-14 18:41:48 -080053 protected IFlowPusherService pusher;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080054
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000055 // Flow Entry ID generation state
56 private static Random randomGenerator = new Random();
57 private static int nextFlowEntryIdPrefix = 0;
58 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070059
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080060 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070061 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080062
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080063 // The queue to write Flow Entries to the database
64 private BlockingQueue<FlowPathEntryPair> flowEntriesToDatabaseQueue =
65 new LinkedBlockingQueue<FlowPathEntryPair>();
66 FlowDatabaseWriter flowDatabaseWriter;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080067
admin944ef4f2013-10-08 17:48:37 -070068 /**
69 * Initialize the Flow Manager.
70 *
71 * @param conf the Graph Database configuration string.
72 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080073 @Override
yoshi2fd4c7e2013-11-22 15:47:55 -080074 public void init(final String dbStore, final String conf) {
yoshid38cd312013-12-02 19:54:44 -080075 dbHandlerApi = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
76 dbHandlerInner = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
77
78 //dbHandlerApi = GraphDBManager.getDBOperation(dbStore, conf);
79 //dbHandlerInner = GraphDBManager.getDBOperation(dbStore, conf);
yoshitomob292c622013-11-23 14:35:58 -080080
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080081 }
82
admin944ef4f2013-10-08 17:48:37 -070083 /**
84 * Shutdown the Flow Manager operation.
85 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080086 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070087 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080088 }
89
admin944ef4f2013-10-08 17:48:37 -070090 /**
91 * Shutdown the Flow Manager operation.
92 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080093 @Override
94 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070095 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080096 dbHandlerApi.close();
97 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080098 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080099
admin944ef4f2013-10-08 17:48:37 -0700100 /**
101 * Get the collection of offered module services.
102 *
103 * @return the collection of offered module services.
104 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800105 @Override
106 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
107 Collection<Class<? extends IFloodlightService>> l =
108 new ArrayList<Class<? extends IFloodlightService>>();
109 l.add(IFlowService.class);
110 return l;
111 }
112
admin944ef4f2013-10-08 17:48:37 -0700113 /**
114 * Get the collection of implemented services.
115 *
116 * @return the collection of implemented services.
117 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800118 @Override
119 public Map<Class<? extends IFloodlightService>, IFloodlightService>
120 getServiceImpls() {
121 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700122 IFloodlightService> m =
123 new HashMap<Class<? extends IFloodlightService>,
124 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800125 m.put(IFlowService.class, this);
126 return m;
127 }
128
admin944ef4f2013-10-08 17:48:37 -0700129 /**
130 * Get the collection of modules this module depends on.
131 *
132 * @return the collection of modules this module depends on.
133 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800134 @Override
135 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700136 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800137 Collection<Class<? extends IFloodlightService>> l =
138 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800139 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700140 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700141 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800142 l.add(IRestApiService.class);
143 return l;
144 }
145
admin944ef4f2013-10-08 17:48:37 -0700146 /**
147 * Initialize the module.
148 *
149 * @param context the module context to use for the initialization.
150 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800151 @Override
152 public void init(FloodlightModuleContext context)
153 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700154 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800155 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700156 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800157 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800158 pusher = context.getServiceImpl(IFlowPusherService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800159
yoshi0fee3de2013-11-23 09:13:37 -0800160 this.init("","");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800161 }
162
admin944ef4f2013-10-08 17:48:37 -0700163 /**
164 * Get the next Flow Entry ID to use.
165 *
166 * @return the next Flow Entry ID to use.
167 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800168 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700169 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000170 //
171 // Generate the next Flow Entry ID.
172 // NOTE: For now, the higher 32 bits are random, and
173 // the lower 32 bits are sequential.
174 // In the future, we need a better allocation mechanism.
175 //
176 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
177 nextFlowEntryIdPrefix = randomGenerator.nextInt();
178 nextFlowEntryIdSuffix = 0;
179 } else {
180 nextFlowEntryIdSuffix++;
181 }
182 long result = (long)nextFlowEntryIdPrefix << 32;
183 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
184 return result;
185 }
186
admin944ef4f2013-10-08 17:48:37 -0700187 /**
188 * Startup module operation.
189 *
190 * @param context the module context to use for the startup.
191 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800192 @Override
193 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700194 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700195
admin944ef4f2013-10-08 17:48:37 -0700196 // Initialize the Flow Entry ID generator
197 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800198
199 //
200 // The thread to write to the database
201 //
202 flowDatabaseWriter = new FlowDatabaseWriter(this,
203 flowEntriesToDatabaseQueue);
204 flowDatabaseWriter.start();
205
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700206 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800207 // The Flow Event Handler thread:
208 // - create
209 // - register with the Datagrid Service
210 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700211 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700212 flowEventHandler = new FlowEventHandler(this, datagridService);
213 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700214 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800215 }
216
217 /**
218 * Add a flow.
219 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800220 * @param flowPath the Flow Path to install.
221 * @param flowId the return-by-reference Flow ID as assigned internally.
222 * @return true on success, otherwise false.
223 */
224 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700225 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700226 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700227 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700228 // in case the application didn't do it.
229 //
230 for (FlowEntry flowEntry : flowPath.flowEntries()) {
231 if (flowEntry.flowEntrySwitchState() ==
232 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
233 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800234 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700235 if (! flowEntry.isValidFlowId())
236 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700237 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800238
yoshi361f6282013-12-06 16:14:14 -0800239 dbHandlerApi = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800240 if (FlowDatabaseOperation.addFlow(this, dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700241 datagridService.notificationSendFlowAdded(flowPath);
242 return true;
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700243 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700244 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800245 }
246
247 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700248 * Add a flow entry to the Network MAP.
249 *
250 * @param flowObj the corresponding Flow Path object for the Flow Entry.
251 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700252 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700253 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700254 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
yoshi361f6282013-12-06 16:14:14 -0800255 dbHandlerInner = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800256 return FlowDatabaseOperation.addFlowEntry(this, dbHandlerInner,
257 flowObj, flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700258 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800259
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700260 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700261 * Delete a flow entry from the Network MAP.
262 *
263 * @param flowObj the corresponding Flow Path object for the Flow Entry.
264 * @param flowEntry the Flow Entry to delete.
265 * @return true on success, otherwise false.
266 */
267 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
yoshi361f6282013-12-06 16:14:14 -0800268 dbHandlerInner = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800269 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
270 flowObj, flowEntry);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800271 }
272
273 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000274 * Delete all previously added flows.
275 *
276 * @return true on success, otherwise false.
277 */
278 @Override
279 public boolean deleteAllFlows() {
yoshi361f6282013-12-06 16:14:14 -0800280 dbHandlerApi = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800281 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700282 datagridService.notificationSendAllFlowsRemoved();
283 return true;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000284 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700285 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000286 }
287
288 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800289 * Delete a previously added flow.
290 *
291 * @param flowId the Flow ID of the flow to delete.
292 * @return true on success, otherwise false.
293 */
294 @Override
295 public boolean deleteFlow(FlowId flowId) {
yoshi361f6282013-12-06 16:14:14 -0800296 dbHandlerApi = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800297 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700298 datagridService.notificationSendFlowRemoved(flowId);
299 return true;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700300 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700301 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700302 }
303
304 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800305 * Get a previously added flow.
306 *
307 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800308 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800309 */
310 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800311 public FlowPath getFlow(FlowId flowId) {
yoshi361f6282013-12-06 16:14:14 -0800312 dbHandlerApi = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800313 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700314 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800315
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700316 /**
317 * Get all installed flows by all installers.
318 *
319 * @return the Flow Paths if found, otherwise null.
320 */
321 @Override
322 public ArrayList<FlowPath> getAllFlows() {
yoshi361f6282013-12-06 16:14:14 -0800323 dbHandlerApi = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800324 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800325 }
326
327 /**
328 * Get all previously added flows by a specific installer for a given
329 * data path endpoints.
330 *
331 * @param installerId the Caller ID of the installer of the flow to get.
332 * @param dataPathEndpoints the data path endpoints of the flow to get.
333 * @return the Flow Paths if found, otherwise null.
334 */
335 @Override
336 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
337 DataPathEndpoints dataPathEndpoints) {
yoshi361f6282013-12-06 16:14:14 -0800338 dbHandlerApi = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800339 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700340 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800341 }
342
343 /**
344 * Get all installed flows by all installers for given data path endpoints.
345 *
346 * @param dataPathEndpoints the data path endpoints of the flows to get.
347 * @return the Flow Paths if found, otherwise null.
348 */
349 @Override
350 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
yoshi361f6282013-12-06 16:14:14 -0800351 dbHandlerApi = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800352 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
353 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800354 }
355
356 /**
admin944ef4f2013-10-08 17:48:37 -0700357 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700358 *
admin944ef4f2013-10-08 17:48:37 -0700359 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700360 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700361 * @return the Flow Paths if found, otherwise null.
362 */
363 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800364 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
365 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800366 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700367 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700368 }
369
370 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700371 * Add and maintain a shortest-path flow.
372 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700373 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700374 *
375 * @param flowPath the Flow Path with the endpoints and the match
376 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700377 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700378 */
379 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700380 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700381 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000382 // Don't do the shortest path computation here.
383 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700384 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700385
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700386 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700387 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700388 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700389
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700390 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700391 }
392
393 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800394 * Get the collection of my switches.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700395 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800396 * @return the collection of my switches.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700397 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800398 public Map<Long, IOFSwitch> getMySwitches() {
399 return floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700400 }
401
402 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800403 * Get the network topology.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700404 *
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800405 * @return the network topology.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700406 */
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800407 public Topology getTopology() {
408 return flowEventHandler.getTopology();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700409 }
410
411 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800412 * Inform the Flow Manager that a Flow Entry on switch expired.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700413 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800414 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800415 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700416 */
Brian O'Connor4f0b60c2013-11-26 15:00:04 -0800417 public void flowEntryOnSwitchExpired(IOFSwitch sw, FlowEntryId flowEntryId) {
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800418 // TODO: Not implemented yet
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700419 }
420
421 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800422 * Push modified Flow Entries to switches.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700423 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800424 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700425 * are pushed.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700426 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800427 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700428 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800429 public void pushModifiedFlowEntriesToSwitches(
430 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800431 if (modifiedFlowEntries.isEmpty())
432 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700433
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800434 Map<Long, IOFSwitch> mySwitches = getMySwitches();
435
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800436 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
437 FlowPath flowPath = flowPair.flowPath;
438 FlowEntry flowEntry = flowPair.flowEntry;
439
440 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
441 if (mySwitch == null)
442 continue;
443
444 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
445
446 //
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800447 // Push the Flow Entry into the switch
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800448 //
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800449 if (! pusher.add(mySwitch, flowPath, flowEntry)) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800450 String logMsg = "Cannot install Flow Entry " +
451 flowEntry.flowEntryId() +
452 " from Flow Path " + flowPath.flowId() +
453 " on switch " + flowEntry.dpid();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700454 log.error(logMsg);
455 continue;
456 }
457
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800458 //
459 // NOTE: Here we assume that the switch has been
460 // successfully updated.
461 //
462 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
463 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700464 }
465
466 /**
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800467 * Push modified Flow Entries to the datagrid.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700468 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800469 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700470 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800471 public void pushModifiedFlowEntriesToDatagrid(
472 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800473 if (modifiedFlowEntries.isEmpty())
474 return;
475
476 Map<Long, IOFSwitch> mySwitches = getMySwitches();
477
478 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
479 FlowEntry flowEntry = flowPair.flowEntry;
480
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800481 if (! flowEntry.isValidFlowEntryId())
482 continue;
483
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800484 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
485
486 //
487 // TODO: For now Flow Entries are removed by all instances,
488 // even if this Flow Entry is not for our switches.
489 //
490 // This is needed to handle the case a switch going down:
491 // it has no Master controller instance, hence no
492 // controller instance will cleanup its flow entries.
493 // This is sub-optimal: we need to elect a controller
494 // instance to handle the cleanup of such orphaned flow
495 // entries.
496 //
497 if (mySwitch == null) {
498 if (flowEntry.flowEntryUserState() !=
499 FlowEntryUserState.FE_USER_DELETE) {
500 continue;
501 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800502 }
503
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800504 log.debug("Pushing Flow Entry To Datagrid: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800505 //
506 // Write the Flow Entry to the Datagrid
507 //
508 switch (flowEntry.flowEntryUserState()) {
509 case FE_USER_ADD:
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700510 if (mySwitch == null)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800511 break; // Install only flow entries for my switches
512 datagridService.notificationSendFlowEntryAdded(flowEntry);
513 break;
514 case FE_USER_MODIFY:
515 if (mySwitch == null)
516 break; // Install only flow entries for my switches
517 datagridService.notificationSendFlowEntryUpdated(flowEntry);
518 break;
519 case FE_USER_DELETE:
520 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
521 break;
522 }
523 }
524 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700525
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800526 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800527 * Class to implement writing to the database in a separate thread.
528 */
529 class FlowDatabaseWriter extends Thread {
530 private FlowManager flowManager;
531 private BlockingQueue<FlowPathEntryPair> blockingQueue;
532
533 /**
534 * Constructor.
535 *
536 * @param flowManager the Flow Manager to use.
537 * @param blockingQueue the blocking queue to use.
538 */
539 FlowDatabaseWriter(FlowManager flowManager,
540 BlockingQueue<FlowPathEntryPair> blockingQueue) {
541 this.flowManager = flowManager;
542 this.blockingQueue = blockingQueue;
543 }
544
545 /**
546 * Run the thread.
547 */
548 @Override
549 public void run() {
550 //
551 // The main loop
552 //
553 Collection<FlowPathEntryPair> collection =
554 new LinkedList<FlowPathEntryPair>();
555 try {
556 while (true) {
557 FlowPathEntryPair entryPair = blockingQueue.take();
558 collection.add(entryPair);
559 blockingQueue.drainTo(collection);
560 flowManager.writeModifiedFlowEntriesToDatabase(collection);
561 collection.clear();
562 }
563 } catch (Exception exception) {
564 log.debug("Exception writing to the Database: ", exception);
565 }
566 }
567 }
568
569 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800570 * Push Flow Entries to the Network MAP.
571 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800572 * NOTE: The Flow Entries are pushed only on the instance responsible
573 * for the first switch. This is to avoid database errors when multiple
574 * instances are writing Flow Entries for the same Flow Path.
575 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800576 * @param modifiedFlowEntries the collection of Flow Entries to push.
577 */
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800578 void pushModifiedFlowEntriesToDatabase(
579 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700580 //
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800581 // We only add the Flow Entries to the Database Queue.
582 // The FlowDatabaseWriter thread is responsible for the actual writing.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700583 //
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800584 flowEntriesToDatabaseQueue.addAll(modifiedFlowEntries);
585 }
586
587 /**
588 * Write Flow Entries to the Network MAP.
589 *
590 * NOTE: The Flow Entries are written only on the instance responsible
591 * for the first switch. This is to avoid database errors when multiple
592 * instances are writing Flow Entries for the same Flow Path.
593 *
594 * @param modifiedFlowEntries the collection of Flow Entries to write.
595 */
596 private void writeModifiedFlowEntriesToDatabase(
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800597 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800598 if (modifiedFlowEntries.isEmpty())
599 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700600
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800601 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700602
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800603 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
604 FlowPath flowPath = flowPair.flowPath;
605 FlowEntry flowEntry = flowPair.flowEntry;
606
607 if (! flowEntry.isValidFlowEntryId())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800608 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800609
610 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800611 // Push the changes only on the instance responsible for the
612 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800613 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800614 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
615 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
616 if (mySrcSwitch == null)
617 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800618
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800619 log.debug("Pushing Flow Entry To Database: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800620 //
621 // Write the Flow Entry to the Network Map
622 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800623 // NOTE: We try a number of times, in case somehow some other
624 // instances are writing at the same time.
625 // Apparently, if other instances are writing at the same time
626 // this will trigger an error.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800627 //
628 for (int i = 0; i < 6; i++) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700629 try {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800630 //
631 // Find the Flow Path in the Network MAP.
632 //
633 // NOTE: The Flow Path might not be found if the Flow was
634 // just removed by some other controller instance.
635 //
yoshi2b7f4302013-12-03 00:44:56 -0800636 System.out.println("writeModifiedFlowEntriesToDatabase");
yoshi361f6282013-12-06 16:14:14 -0800637 dbHandlerInner = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800638 IFlowPath flowObj =
639 dbHandlerInner.searchFlowPath(flowEntry.flowId());
640 if (flowObj == null) {
641 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700642 log.error(logMsg);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800643 break;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700644 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800645
646 // Write the Flow Entry
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700647 switch (flowEntry.flowEntryUserState()) {
648 case FE_USER_ADD:
649 // FALLTHROUGH
650 case FE_USER_MODIFY:
651 if (addFlowEntry(flowObj, flowEntry) == null) {
652 String logMsg = "Cannot write to Network MAP Flow Entry " +
653 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800654 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700655 " on switch " + flowEntry.dpid();
656 log.error(logMsg);
657 }
658 break;
659 case FE_USER_DELETE:
660 if (deleteFlowEntry(flowObj, flowEntry) == false) {
661 String logMsg = "Cannot remove from Network MAP Flow Entry " +
662 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800663 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700664 " on switch " + flowEntry.dpid();
665 log.error(logMsg);
666 }
667 break;
668 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800669
670 // Commit to the database
671 dbHandlerInner.commit();
672 break; // Success
673
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700674 } catch (Exception e) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800675 log.debug("Exception writing Flow Entry to Network MAP: ", e);
676 dbHandlerInner.rollback();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800677 // Wait a bit (random value [1ms, 20ms] and try again
678 int delay = 1 + randomGenerator.nextInt() % 20;
679 try {
680 Thread.sleep(delay);
681 } catch (Exception e0) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700682 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700683 }
684 }
685 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700686 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800687}