blob: bacfd5d8157332874eae6940aca56d722b489043 [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 Radoslavovab3f8862013-12-04 18:35:53 -08007import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08008import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +00009import java.util.Random;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080010import java.util.SortedMap;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080011import java.util.concurrent.BlockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080012import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080013
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080016import net.floodlightcontroller.core.module.FloodlightModuleContext;
17import net.floodlightcontroller.core.module.FloodlightModuleException;
18import net.floodlightcontroller.core.module.IFloodlightModule;
19import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070021import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070022import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070023import net.onrc.onos.ofcontroller.core.INetMapStorage;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070024import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070025import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080026import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
Pavlin Radoslavovc0862662013-12-10 15:31:49 -080027import net.onrc.onos.ofcontroller.forwarding.IForwardingService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070028import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov63e42602013-12-12 12:54:05 -080029import net.onrc.onos.ofcontroller.util.Dpid;
30import net.onrc.onos.ofcontroller.util.FlowEntry;
31import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
32import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
33import net.onrc.onos.ofcontroller.util.FlowEntryId;
34import net.onrc.onos.ofcontroller.util.FlowId;
35import net.onrc.onos.ofcontroller.util.FlowPath;
36import net.onrc.onos.ofcontroller.util.FlowPathUserState;
37import net.onrc.onos.ofcontroller.util.Pair;
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080038import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
39
Pavlin Radoslavov262e6832013-12-18 14:37:35 -080040import com.thinkaurelius.titan.core.TitanException;
41
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080042import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080044import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
admin944ef4f2013-10-08 17:48:37 -070047/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070048 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070049 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070050public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080051 protected GraphDBOperation dbHandlerApi;
52 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080053
Jonathan Hart50a94982013-04-10 14:49:51 -070054 protected volatile IFloodlightProviderService floodlightProvider;
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
Brian O'Connor8c166a72013-11-14 18:41:48 -080060 protected IFlowPusherService pusher;
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080061 protected IForwardingService forwardingService;
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080062
63 private KryoFactory kryoFactory = new KryoFactory();
64
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000065 // Flow Entry ID generation state
66 private static Random randomGenerator = new Random();
67 private static int nextFlowEntryIdPrefix = 0;
68 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000069
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080070 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070071 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080073 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080074 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
75 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080076 FlowDatabaseWriter flowDatabaseWriter;
77
admin944ef4f2013-10-08 17:48:37 -070078 /**
79 * Initialize the Flow Manager.
80 *
81 * @param conf the Graph Database configuration string.
82 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080083 @Override
84 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080085 dbHandlerApi = new GraphDBOperation(conf);
86 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080087 }
88
admin944ef4f2013-10-08 17:48:37 -070089 /**
90 * Shutdown the Flow Manager operation.
91 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080092 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070093 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080094 }
95
admin944ef4f2013-10-08 17:48:37 -070096 /**
97 * Shutdown the Flow Manager operation.
98 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080099 @Override
100 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700101 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800102 dbHandlerApi.close();
103 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800104 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800105
admin944ef4f2013-10-08 17:48:37 -0700106 /**
107 * Get the collection of offered module services.
108 *
109 * @return the collection of offered module services.
110 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800111 @Override
112 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
113 Collection<Class<? extends IFloodlightService>> l =
114 new ArrayList<Class<? extends IFloodlightService>>();
115 l.add(IFlowService.class);
116 return l;
117 }
118
admin944ef4f2013-10-08 17:48:37 -0700119 /**
120 * Get the collection of implemented services.
121 *
122 * @return the collection of implemented services.
123 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800124 @Override
125 public Map<Class<? extends IFloodlightService>, IFloodlightService>
126 getServiceImpls() {
127 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700128 IFloodlightService> m =
129 new HashMap<Class<? extends IFloodlightService>,
130 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800131 m.put(IFlowService.class, this);
132 return m;
133 }
134
admin944ef4f2013-10-08 17:48:37 -0700135 /**
136 * Get the collection of modules this module depends on.
137 *
138 * @return the collection of modules this module depends on.
139 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800140 @Override
141 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700142 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800143 Collection<Class<? extends IFloodlightService>> l =
144 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800145 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700146 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700147 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800148 l.add(IRestApiService.class);
Pavlin Radoslavovc0862662013-12-10 15:31:49 -0800149 l.add(IFlowPusherService.class);
Pavlin Radoslavov63c2d052013-12-18 18:17:55 -0800150 //
151 // TODO: Comment-out the dependency on the IForwardingService,
152 // because it is an optional module. Apparently, adding the dependency
153 // here automatically enables the module.
154 //
155 // l.add(IForwardingService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800156 return l;
157 }
158
admin944ef4f2013-10-08 17:48:37 -0700159 /**
160 * Initialize the module.
161 *
162 * @param context the module context to use for the initialization.
163 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800164 @Override
165 public void init(FloodlightModuleContext context)
166 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700167 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800168 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700169 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800170 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800171 pusher = context.getServiceImpl(IFlowPusherService.class);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800172 forwardingService = context.getServiceImpl(IForwardingService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800173
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700174 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800175 }
176
admin944ef4f2013-10-08 17:48:37 -0700177 /**
178 * Get the next Flow Entry ID to use.
179 *
180 * @return the next Flow Entry ID to use.
181 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800182 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700183 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000184 //
185 // Generate the next Flow Entry ID.
186 // NOTE: For now, the higher 32 bits are random, and
187 // the lower 32 bits are sequential.
188 // In the future, we need a better allocation mechanism.
189 //
190 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
191 nextFlowEntryIdPrefix = randomGenerator.nextInt();
192 nextFlowEntryIdSuffix = 0;
193 } else {
194 nextFlowEntryIdSuffix++;
195 }
196 long result = (long)nextFlowEntryIdPrefix << 32;
197 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
198 return result;
199 }
200
admin944ef4f2013-10-08 17:48:37 -0700201 /**
202 * Startup module operation.
203 *
204 * @param context the module context to use for the startup.
205 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800206 @Override
207 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700208 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700209
admin944ef4f2013-10-08 17:48:37 -0700210 // Initialize the Flow Entry ID generator
211 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800212
213 //
214 // The thread to write to the database
215 //
216 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800217 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800218 flowDatabaseWriter.start();
219
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700220 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800221 // The Flow Event Handler thread:
222 // - create
223 // - register with the Datagrid Service
224 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700225 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700226 flowEventHandler = new FlowEventHandler(this, datagridService);
227 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700228 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800229 }
230
231 /**
232 * Add a flow.
233 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800234 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800235 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800236 */
237 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800238 public FlowId addFlow(FlowPath flowPath) {
239
240 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800241 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800242 long id = getNextFlowEntryId();
243 flowPath.setFlowId(new FlowId(id));
244 }
245
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700246 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700247 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700248 // in case the application didn't do it.
249 //
250 for (FlowEntry flowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800251 // The Flow Entry switch state
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700252 if (flowEntry.flowEntrySwitchState() ==
253 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
254 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
255 }
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800256 // The Flow Entry ID
257 if (! flowEntry.isValidFlowEntryId()) {
258 long id = getNextFlowEntryId();
259 flowEntry.setFlowEntryId(new FlowEntryId(id));
260 }
261 // The Flow ID
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700262 if (! flowEntry.isValidFlowId())
263 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700264 }
265
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800266 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700267 datagridService.notificationSendFlowAdded(flowPath);
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800268 return flowPath.flowId();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700269 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800270 return null;
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() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800280 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700281 datagridService.notificationSendAllFlowsRemoved();
282 return true;
283 }
284 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000285 }
286
287 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800288 * Delete a previously added flow.
289 *
290 * @param flowId the Flow ID of the flow to delete.
291 * @return true on success, otherwise false.
292 */
293 @Override
294 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800295 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700296 datagridService.notificationSendFlowRemoved(flowId);
297 return true;
298 }
299 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700300 }
301
302 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800303 * Get a previously added flow.
304 *
305 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800306 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800307 */
308 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800309 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800310 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700311 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800312
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700313 /**
314 * Get all installed flows by all installers.
315 *
316 * @return the Flow Paths if found, otherwise null.
317 */
318 @Override
319 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800320 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800321 }
322
323 /**
admin944ef4f2013-10-08 17:48:37 -0700324 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700325 *
admin944ef4f2013-10-08 17:48:37 -0700326 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700327 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700328 * @return the Flow Paths if found, otherwise null.
329 */
330 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800331 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
332 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800333 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
334 SortedMap<Long, FlowPath> sortedFlowPaths =
335 flowEventHandler.getAllFlowPathsCopy();
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800336
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800337 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800338 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800339 //
340 for (FlowPath flowPath : sortedFlowPaths.values()) {
341 //
342 // TODO: Add only the Flow Paths that have been successfully
343 // installed.
344 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800345 flowPath.setFlowEntryMatch(null);
346 flowPath.setFlowEntryActions(null);
347 for (FlowEntry flowEntry : flowPath.flowEntries()) {
348 flowEntry.setFlowEntryMatch(null);
349 flowEntry.setFlowEntryActions(null);
350 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800351 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800352 }
353
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800354 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700355 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700356
357 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800358 * Get the collection of my switches.
359 *
360 * @return the collection of my switches.
361 */
362 public Map<Long, IOFSwitch> getMySwitches() {
363 return floodlightProvider.getSwitches();
364 }
365
366 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800367 * Get the network topology.
368 *
369 * @return the network topology.
370 */
371 public Topology getTopology() {
372 return flowEventHandler.getTopology();
373 }
374
375 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800376 * Inform the Flow Manager that a Flow Entry on switch expired.
377 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800378 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800379 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
380 */
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800381 public void flowEntryOnSwitchExpired(IOFSwitch sw,
382 FlowEntryId flowEntryId) {
383 // Find the Flow Entry
384 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
Pavlin Radoslavovac0fabc2013-12-13 10:47:56 -0800385 if (flowEntry == null)
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800386 return; // Flow Entry not found
387
388 // Find the Flow Path
389 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
390 if (flowPath == null)
391 return; // Flow Path not found
392
393 //
394 // Remove the Flow if the Flow Entry expired on the first switch
395 //
396 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
397 if (srcDpid.value() != sw.getId())
398 return;
399 deleteFlow(flowPath.flowId());
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800400 }
401
402 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800403 * Inform the Flow Manager that a collection of Flow Entries have been
404 * pushed to a switch.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800405 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800406 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
407 * that have been pushed.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800408 */
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800409 public void flowEntriesPushedToSwitch(
410 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800411
412 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800413 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800414 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800415 // TODO: For now we have to create an explicit FlowEntry copy so
416 // we don't modify the original FlowEntry.
417 // This should go away after we start using the OpenFlow Barrier
418 // mechnanism in the FlowPusher.
419 //
420 Kryo kryo = kryoFactory.newKryo();
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800421 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800422 FlowEntry flowEntry = entry.second;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800423
424 //
425 // Mark the Flow Entry that it has been pushed to the switch
426 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800427 FlowEntry copyFlowEntry = kryo.copy(flowEntry);
428 copyFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800429
430 //
431 // Write the Flow Entry to the Datagrid
432 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800433 switch (copyFlowEntry.flowEntryUserState()) {
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800434 case FE_USER_ADD:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800435 datagridService.notificationSendFlowEntryAdded(copyFlowEntry);
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800436 break;
437 case FE_USER_MODIFY:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800438 datagridService.notificationSendFlowEntryUpdated(copyFlowEntry);
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800439 break;
440 case FE_USER_DELETE:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800441 datagridService.notificationSendFlowEntryRemoved(copyFlowEntry.flowEntryId());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800442 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800443 case FE_USER_UNKNOWN:
444 assert(false);
445 break;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800446 }
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800447 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800448 kryoFactory.deleteKryo(kryo);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800449 }
450
451 /**
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800452 * Generate a notification that a collection of Flow Paths has been
453 * installed in the network.
454 *
455 * @param flowPaths the collection of installed Flow Paths.
456 */
457 void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
Pavlin Radoslavov63c2d052013-12-18 18:17:55 -0800458 //
459 // TODO: Add an explicit check for null pointer, because
460 // the IForwardingService is optional. Remove the "if" statement
461 // after hte Forwarding Module becomes mandatory.
462 //
463 if (forwardingService != null)
464 forwardingService.flowsInstalled(flowPaths);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800465 }
466
467 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800468 * Push modified Flow-related state as appropriate.
469 *
470 * @param modifiedFlowPaths the collection of modified Flow Paths.
471 * @param modifiedFlowEntries the collection of modified Flow Entries.
472 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800473 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
474 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800475 //
476 // Push the modified Flow state:
477 // - Flow Entries to switches and the datagrid
478 // - Flow Paths to the database
479 //
480 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800481 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800482 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800483 }
484
485 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800486 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700487 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800488 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700489 * are pushed.
490 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800491 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700492 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800493 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800494 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800495 if (modifiedFlowEntries.isEmpty())
496 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700497
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800498 List<Pair<IOFSwitch, FlowEntry>> entries =
499 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
500
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800501 Map<Long, IOFSwitch> mySwitches = getMySwitches();
502
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800503 //
504 // Create a collection of my Flow Entries to push
505 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800506 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800507 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
508 if (mySwitch == null)
509 continue;
510
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800511 //
512 // Assign Flow Entry IDs if missing.
513 //
514 // NOTE: This is an additional safeguard, in case the
515 // mySwitches set has changed (after the Flow Entry IDs
516 // assignments by the caller).
517 //
518 if (! flowEntry.isValidFlowEntryId()) {
519 long id = getNextFlowEntryId();
520 flowEntry.setFlowEntryId(new FlowEntryId(id));
521 }
522
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800523 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800524 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800525 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800526
527 pusher.pushFlowEntries(entries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800528 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700529
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800530 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800531 * Cleanup deleted Flow Entries from the datagrid.
532 *
533 * NOTE: We cleanup only the Flow Entries that are not for our switches.
534 * This is needed to handle the case a switch going down:
535 * It has no Master controller instance, hence no controller instance
536 * will cleanup its flow entries.
537 * This is sub-optimal: we need to elect a controller instance to handle
538 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800539 *
540 * @param modifiedFlowEntries the collection of modified Flow Entries.
541 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800542 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800543 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800544 if (modifiedFlowEntries.isEmpty())
545 return;
546
547 Map<Long, IOFSwitch> mySwitches = getMySwitches();
548
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800549 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800550 //
551 // Process only Flow Entries that should be deleted and have
552 // a valid Flow Entry ID.
553 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800554 if (! flowEntry.isValidFlowEntryId())
555 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800556 if (flowEntry.flowEntryUserState() !=
557 FlowEntryUserState.FE_USER_DELETE) {
558 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800559 }
560
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800561 //
562 // NOTE: The deletion of Flow Entries for my switches is handled
563 // elsewhere.
564 //
565 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
566 if (mySwitch != null)
567 continue;
568
569 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
570
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800571 //
572 // Write the Flow Entry to the Datagrid
573 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800574 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800575 }
576 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700577
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800578 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800579 * Class to implement writing to the database in a separate thread.
580 */
581 class FlowDatabaseWriter extends Thread {
582 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800583 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800584
585 /**
586 * Constructor.
587 *
588 * @param flowManager the Flow Manager to use.
589 * @param blockingQueue the blocking queue to use.
590 */
591 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800592 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800593 this.flowManager = flowManager;
594 this.blockingQueue = blockingQueue;
595 }
596
597 /**
598 * Run the thread.
599 */
600 @Override
601 public void run() {
602 //
603 // The main loop
604 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800605 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800606 try {
607 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800608 FlowPath flowPath = blockingQueue.take();
609 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800610 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800611 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800612 collection.clear();
613 }
614 } catch (Exception exception) {
615 log.debug("Exception writing to the Database: ", exception);
616 }
617 }
618 }
619
620 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800621 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800622 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800623 * NOTE: The complete Flow Paths are pushed only on the instance
624 * responsible for the first switch. This is to avoid database errors
625 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800626 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800627 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800628 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800629 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800630 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800631 List<FlowPath> copiedFlowPaths = new LinkedList<FlowPath>();
632
633 //
634 // Create a copy of the Flow Paths to push, because the pushing
635 // itself will happen on a separate thread.
636 //
637 Kryo kryo = kryoFactory.newKryo();
638 for (FlowPath flowPath : modifiedFlowPaths) {
639 FlowPath copyFlowPath = kryo.copy(flowPath);
640 copiedFlowPaths.add(copyFlowPath);
641 }
642 kryoFactory.deleteKryo(kryo);
643
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800644 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800645 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800646 // The FlowDatabaseWriter thread is responsible for the actual writing.
647 //
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800648 flowPathsToDatabaseQueue.addAll(copiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800649 }
650
651 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800652 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800653 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800654 * NOTE: The complete Flow Paths are pushed only on the instance
655 * responsible for the first switch. This is to avoid database errors
656 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800657 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800658 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800659 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800660 private void writeModifiedFlowPathsToDatabase(
661 Collection<FlowPath> modifiedFlowPaths) {
662 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800663 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700664
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800665 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700666
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800667 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800668 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800669 // Push the changes only on the instance responsible for the
670 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800671 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800672 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
673 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
674 if (mySrcSwitch == null)
675 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800676
677 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800678 // Delete the Flow Path from the Network Map
679 //
680 if (flowPath.flowPathUserState() ==
681 FlowPathUserState.FP_USER_DELETE) {
682 log.debug("Deleting Flow Path From Database: {}",
683 flowPath.toString());
684
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800685 boolean retry = false;
686 do {
687 retry = false;
688 try {
689 if (! FlowDatabaseOperation.deleteFlow(
690 dbHandlerInner,
691 flowPath.flowId())) {
692 log.error("Cannot delete Flow Path {} from Network Map",
693 flowPath.flowId());
694 retry = true;
695 }
696 } catch (TitanException te) {
697 log.error("Titan Exception deleting Flow Path from Network MAP: {}", te);
698 retry = true;
699 } catch (Exception e) {
700 log.error("Exception deleting Flow Path from Network MAP: {}", e);
701 }
702 } while (retry);
703
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800704 continue;
705 }
706
707 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800708 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800709 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800710 boolean allValid = true;
711 for (FlowEntry flowEntry : flowPath.flowEntries()) {
712 if (flowEntry.flowEntryUserState() ==
713 FlowEntryUserState.FE_USER_DELETE) {
714 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700715 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800716 if (! flowEntry.isValidFlowEntryId()) {
717 allValid = false;
718 break;
719 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800720 if (flowEntry.flowEntrySwitchState() !=
721 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
722 allValid = false;
723 break;
724 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800725 }
726 if (! allValid)
727 continue;
728
729 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
730
731 //
732 // Write the Flow Path to the Network Map
733 //
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800734 boolean retry = false;
735 do {
736 retry = false;
737 try {
738 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
739 String logMsg = "Cannot write to Network Map Flow Path " +
740 flowPath.flowId();
741 log.error(logMsg);
742 retry = true;
743 }
744 } catch (TitanException te) {
745 log.error("Titan Exception writing Flow Path to Network MAP: ", te);
746 retry = true;
747 } catch (Exception e) {
748 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800749 }
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800750 } while (retry);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700751 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700752 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800753}