blob: 18c34de9050ed518d2774a682792a434cbdd1cc9 [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
40import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080042import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
admin944ef4f2013-10-08 17:48:37 -070045/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070046 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070047 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070048public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080049 protected GraphDBOperation dbHandlerApi;
50 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080051
Jonathan Hart50a94982013-04-10 14:49:51 -070052 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070053 protected volatile IDatagridService datagridService;
54 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070055 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070056 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080057
Brian O'Connor8c166a72013-11-14 18:41:48 -080058 protected IFlowPusherService pusher;
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080059 protected IForwardingService forwardingService;
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080060
61 private KryoFactory kryoFactory = new KryoFactory();
62
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000063 // Flow Entry ID generation state
64 private static Random randomGenerator = new Random();
65 private static int nextFlowEntryIdPrefix = 0;
66 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000067
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080068 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070069 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080071 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080072 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
73 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080074 FlowDatabaseWriter flowDatabaseWriter;
75
admin944ef4f2013-10-08 17:48:37 -070076 /**
77 * Initialize the Flow Manager.
78 *
79 * @param conf the Graph Database configuration string.
80 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080081 @Override
82 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080083 dbHandlerApi = new GraphDBOperation(conf);
84 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080085 }
86
admin944ef4f2013-10-08 17:48:37 -070087 /**
88 * Shutdown the Flow Manager operation.
89 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080090 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070091 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080092 }
93
admin944ef4f2013-10-08 17:48:37 -070094 /**
95 * Shutdown the Flow Manager operation.
96 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080097 @Override
98 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070099 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800100 dbHandlerApi.close();
101 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800102 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800103
admin944ef4f2013-10-08 17:48:37 -0700104 /**
105 * Get the collection of offered module services.
106 *
107 * @return the collection of offered module services.
108 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800109 @Override
110 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
111 Collection<Class<? extends IFloodlightService>> l =
112 new ArrayList<Class<? extends IFloodlightService>>();
113 l.add(IFlowService.class);
114 return l;
115 }
116
admin944ef4f2013-10-08 17:48:37 -0700117 /**
118 * Get the collection of implemented services.
119 *
120 * @return the collection of implemented services.
121 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800122 @Override
123 public Map<Class<? extends IFloodlightService>, IFloodlightService>
124 getServiceImpls() {
125 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700126 IFloodlightService> m =
127 new HashMap<Class<? extends IFloodlightService>,
128 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800129 m.put(IFlowService.class, this);
130 return m;
131 }
132
admin944ef4f2013-10-08 17:48:37 -0700133 /**
134 * Get the collection of modules this module depends on.
135 *
136 * @return the collection of modules this module depends on.
137 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800138 @Override
139 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700140 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800141 Collection<Class<? extends IFloodlightService>> l =
142 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800143 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700144 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700145 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800146 l.add(IRestApiService.class);
Pavlin Radoslavovc0862662013-12-10 15:31:49 -0800147 l.add(IFlowPusherService.class);
148 l.add(IForwardingService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800149 return l;
150 }
151
admin944ef4f2013-10-08 17:48:37 -0700152 /**
153 * Initialize the module.
154 *
155 * @param context the module context to use for the initialization.
156 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800157 @Override
158 public void init(FloodlightModuleContext context)
159 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700160 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800161 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700162 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800163 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800164 pusher = context.getServiceImpl(IFlowPusherService.class);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800165 forwardingService = context.getServiceImpl(IForwardingService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800166
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700167 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800168 }
169
admin944ef4f2013-10-08 17:48:37 -0700170 /**
171 * Get the next Flow Entry ID to use.
172 *
173 * @return the next Flow Entry ID to use.
174 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800175 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700176 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000177 //
178 // Generate the next Flow Entry ID.
179 // NOTE: For now, the higher 32 bits are random, and
180 // the lower 32 bits are sequential.
181 // In the future, we need a better allocation mechanism.
182 //
183 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
184 nextFlowEntryIdPrefix = randomGenerator.nextInt();
185 nextFlowEntryIdSuffix = 0;
186 } else {
187 nextFlowEntryIdSuffix++;
188 }
189 long result = (long)nextFlowEntryIdPrefix << 32;
190 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
191 return result;
192 }
193
admin944ef4f2013-10-08 17:48:37 -0700194 /**
195 * Startup module operation.
196 *
197 * @param context the module context to use for the startup.
198 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800199 @Override
200 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700201 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700202
admin944ef4f2013-10-08 17:48:37 -0700203 // Initialize the Flow Entry ID generator
204 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800205
206 //
207 // The thread to write to the database
208 //
209 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800210 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800211 flowDatabaseWriter.start();
212
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700213 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800214 // The Flow Event Handler thread:
215 // - create
216 // - register with the Datagrid Service
217 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700218 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700219 flowEventHandler = new FlowEventHandler(this, datagridService);
220 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700221 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800222 }
223
224 /**
225 * Add a flow.
226 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800227 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800228 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800229 */
230 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800231 public FlowId addFlow(FlowPath flowPath) {
232
233 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800234 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800235 long id = getNextFlowEntryId();
236 flowPath.setFlowId(new FlowId(id));
237 }
238
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700239 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700240 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700241 // in case the application didn't do it.
242 //
243 for (FlowEntry flowEntry : flowPath.flowEntries()) {
244 if (flowEntry.flowEntrySwitchState() ==
245 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
246 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
247 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700248 if (! flowEntry.isValidFlowId())
249 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700250 }
251
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800252 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700253 datagridService.notificationSendFlowAdded(flowPath);
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800254 return flowPath.flowId();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700255 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800256 return null;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800257 }
258
259 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000260 * Delete all previously added flows.
261 *
262 * @return true on success, otherwise false.
263 */
264 @Override
265 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800266 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700267 datagridService.notificationSendAllFlowsRemoved();
268 return true;
269 }
270 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000271 }
272
273 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800274 * Delete a previously added flow.
275 *
276 * @param flowId the Flow ID of the flow to delete.
277 * @return true on success, otherwise false.
278 */
279 @Override
280 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800281 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700282 datagridService.notificationSendFlowRemoved(flowId);
283 return true;
284 }
285 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700286 }
287
288 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800289 * Get a previously added flow.
290 *
291 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800292 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800293 */
294 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800295 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800296 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700297 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800298
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700299 /**
300 * Get all installed flows by all installers.
301 *
302 * @return the Flow Paths if found, otherwise null.
303 */
304 @Override
305 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800306 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800307 }
308
309 /**
admin944ef4f2013-10-08 17:48:37 -0700310 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700311 *
admin944ef4f2013-10-08 17:48:37 -0700312 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700313 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700314 * @return the Flow Paths if found, otherwise null.
315 */
316 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800317 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
318 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800319 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
320 SortedMap<Long, FlowPath> sortedFlowPaths =
321 flowEventHandler.getAllFlowPathsCopy();
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800322
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800323 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800324 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800325 //
326 for (FlowPath flowPath : sortedFlowPaths.values()) {
327 //
328 // TODO: Add only the Flow Paths that have been successfully
329 // installed.
330 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800331 flowPath.setFlowEntryMatch(null);
332 flowPath.setFlowEntryActions(null);
333 for (FlowEntry flowEntry : flowPath.flowEntries()) {
334 flowEntry.setFlowEntryMatch(null);
335 flowEntry.setFlowEntryActions(null);
336 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800337 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800338 }
339
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800340 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700341 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700342
343 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800344 * Get the collection of my switches.
345 *
346 * @return the collection of my switches.
347 */
348 public Map<Long, IOFSwitch> getMySwitches() {
349 return floodlightProvider.getSwitches();
350 }
351
352 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800353 * Get the network topology.
354 *
355 * @return the network topology.
356 */
357 public Topology getTopology() {
358 return flowEventHandler.getTopology();
359 }
360
361 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800362 * Inform the Flow Manager that a Flow Entry on switch expired.
363 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800364 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800365 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
366 */
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800367 public void flowEntryOnSwitchExpired(IOFSwitch sw,
368 FlowEntryId flowEntryId) {
369 // Find the Flow Entry
370 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
Pavlin Radoslavovac0fabc2013-12-13 10:47:56 -0800371 if (flowEntry == null)
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800372 return; // Flow Entry not found
373
374 // Find the Flow Path
375 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
376 if (flowPath == null)
377 return; // Flow Path not found
378
379 //
380 // Remove the Flow if the Flow Entry expired on the first switch
381 //
382 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
383 if (srcDpid.value() != sw.getId())
384 return;
385 deleteFlow(flowPath.flowId());
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800386 }
387
388 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800389 * Inform the Flow Manager that a collection of Flow Entries have been
390 * pushed to a switch.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800391 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800392 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
393 * that have been pushed.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800394 */
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800395 public void flowEntriesPushedToSwitch(
396 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800397
398 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800399 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800400 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800401 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800402 FlowEntry flowEntry = entry.second;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800403
404 //
405 // Mark the Flow Entry that it has been pushed to the switch
406 //
407 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
408
409 //
410 // Write the Flow Entry to the Datagrid
411 //
412 switch (flowEntry.flowEntryUserState()) {
413 case FE_USER_ADD:
414 datagridService.notificationSendFlowEntryAdded(flowEntry);
415 break;
416 case FE_USER_MODIFY:
417 datagridService.notificationSendFlowEntryUpdated(flowEntry);
418 break;
419 case FE_USER_DELETE:
420 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
421 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800422 case FE_USER_UNKNOWN:
423 assert(false);
424 break;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800425 }
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800426 }
427 }
428
429 /**
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800430 * Generate a notification that a collection of Flow Paths has been
431 * installed in the network.
432 *
433 * @param flowPaths the collection of installed Flow Paths.
434 */
435 void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
436 forwardingService.flowsInstalled(flowPaths);
437 }
438
439 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800440 * Push modified Flow-related state as appropriate.
441 *
442 * @param modifiedFlowPaths the collection of modified Flow Paths.
443 * @param modifiedFlowEntries the collection of modified Flow Entries.
444 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800445 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
446 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800447 //
448 // Push the modified Flow state:
449 // - Flow Entries to switches and the datagrid
450 // - Flow Paths to the database
451 //
452 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800453 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800454 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800455 }
456
457 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800458 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700459 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800460 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700461 * are pushed.
462 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800463 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700464 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800465 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800466 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800467 if (modifiedFlowEntries.isEmpty())
468 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700469
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800470 List<Pair<IOFSwitch, FlowEntry>> entries =
471 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
472
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800473 Map<Long, IOFSwitch> mySwitches = getMySwitches();
474
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800475 //
476 // Create a collection of my Flow Entries to push
477 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800478 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800479 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
480 if (mySwitch == null)
481 continue;
482
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800483 //
484 // Assign Flow Entry IDs if missing.
485 //
486 // NOTE: This is an additional safeguard, in case the
487 // mySwitches set has changed (after the Flow Entry IDs
488 // assignments by the caller).
489 //
490 if (! flowEntry.isValidFlowEntryId()) {
491 long id = getNextFlowEntryId();
492 flowEntry.setFlowEntryId(new FlowEntryId(id));
493 }
494
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800495 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800496 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800497 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800498
499 pusher.pushFlowEntries(entries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800500 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700501
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800502 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800503 * Cleanup deleted Flow Entries from the datagrid.
504 *
505 * NOTE: We cleanup only the Flow Entries that are not for our switches.
506 * This is needed to handle the case a switch going down:
507 * It has no Master controller instance, hence no controller instance
508 * will cleanup its flow entries.
509 * This is sub-optimal: we need to elect a controller instance to handle
510 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800511 *
512 * @param modifiedFlowEntries the collection of modified Flow Entries.
513 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800514 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800515 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800516 if (modifiedFlowEntries.isEmpty())
517 return;
518
519 Map<Long, IOFSwitch> mySwitches = getMySwitches();
520
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800521 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800522 //
523 // Process only Flow Entries that should be deleted and have
524 // a valid Flow Entry ID.
525 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800526 if (! flowEntry.isValidFlowEntryId())
527 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800528 if (flowEntry.flowEntryUserState() !=
529 FlowEntryUserState.FE_USER_DELETE) {
530 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800531 }
532
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800533 //
534 // NOTE: The deletion of Flow Entries for my switches is handled
535 // elsewhere.
536 //
537 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
538 if (mySwitch != null)
539 continue;
540
541 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
542
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800543 //
544 // Write the Flow Entry to the Datagrid
545 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800546 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800547 }
548 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700549
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800550 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800551 * Class to implement writing to the database in a separate thread.
552 */
553 class FlowDatabaseWriter extends Thread {
554 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800555 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800556
557 /**
558 * Constructor.
559 *
560 * @param flowManager the Flow Manager to use.
561 * @param blockingQueue the blocking queue to use.
562 */
563 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800564 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800565 this.flowManager = flowManager;
566 this.blockingQueue = blockingQueue;
567 }
568
569 /**
570 * Run the thread.
571 */
572 @Override
573 public void run() {
574 //
575 // The main loop
576 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800577 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800578 try {
579 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800580 FlowPath flowPath = blockingQueue.take();
581 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800582 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800583 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800584 collection.clear();
585 }
586 } catch (Exception exception) {
587 log.debug("Exception writing to the Database: ", exception);
588 }
589 }
590 }
591
592 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800593 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800594 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800595 * NOTE: The complete Flow Paths are pushed only on the instance
596 * responsible for the first switch. This is to avoid database errors
597 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800598 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800599 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800600 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800601 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800602 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800603 List<FlowPath> copiedFlowPaths = new LinkedList<FlowPath>();
604
605 //
606 // Create a copy of the Flow Paths to push, because the pushing
607 // itself will happen on a separate thread.
608 //
609 Kryo kryo = kryoFactory.newKryo();
610 for (FlowPath flowPath : modifiedFlowPaths) {
611 FlowPath copyFlowPath = kryo.copy(flowPath);
612 copiedFlowPaths.add(copyFlowPath);
613 }
614 kryoFactory.deleteKryo(kryo);
615
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800616 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800617 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800618 // The FlowDatabaseWriter thread is responsible for the actual writing.
619 //
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800620 flowPathsToDatabaseQueue.addAll(copiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800621 }
622
623 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800624 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800625 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800626 * NOTE: The complete Flow Paths are pushed only on the instance
627 * responsible for the first switch. This is to avoid database errors
628 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800629 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800630 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800631 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800632 private void writeModifiedFlowPathsToDatabase(
633 Collection<FlowPath> modifiedFlowPaths) {
634 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800635 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700636
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800637 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700638
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800639 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800640 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800641 // Push the changes only on the instance responsible for the
642 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800643 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800644 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
645 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
646 if (mySrcSwitch == null)
647 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800648
649 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800650 // Delete the Flow Path from the Network Map
651 //
652 if (flowPath.flowPathUserState() ==
653 FlowPathUserState.FP_USER_DELETE) {
654 log.debug("Deleting Flow Path From Database: {}",
655 flowPath.toString());
656
657 try {
658 if (! FlowDatabaseOperation.deleteFlow(
659 dbHandlerInner,
660 flowPath.flowId())) {
661 log.error("Cannot delete Flow Path {} from Network Map",
662 flowPath.flowId());
663 }
664 } catch (Exception e) {
665 log.error("Exception deleting Flow Path from Network MAP: {}", e);
666 }
667 continue;
668 }
669
670 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800671 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800672 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800673 boolean allValid = true;
674 for (FlowEntry flowEntry : flowPath.flowEntries()) {
675 if (flowEntry.flowEntryUserState() ==
676 FlowEntryUserState.FE_USER_DELETE) {
677 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700678 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800679 if (! flowEntry.isValidFlowEntryId()) {
680 allValid = false;
681 break;
682 }
683 }
684 if (! allValid)
685 continue;
686
687 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
688
689 //
690 // Write the Flow Path to the Network Map
691 //
692 try {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800693 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800694 String logMsg = "Cannot write to Network Map Flow Path " +
695 flowPath.flowId();
696 log.error(logMsg);
697 }
698 } catch (Exception e) {
699 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700700 }
701 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700702 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800703}