blob: 82680df86277696bde5e90ed2db09ea509f0da6d [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()) {
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800244 // The Flow Entry switch state
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700245 if (flowEntry.flowEntrySwitchState() ==
246 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
247 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
248 }
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800249 // The Flow Entry ID
250 if (! flowEntry.isValidFlowEntryId()) {
251 long id = getNextFlowEntryId();
252 flowEntry.setFlowEntryId(new FlowEntryId(id));
253 }
254 // The Flow ID
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700255 if (! flowEntry.isValidFlowId())
256 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700257 }
258
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800259 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700260 datagridService.notificationSendFlowAdded(flowPath);
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800261 return flowPath.flowId();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700262 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800263 return null;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800264 }
265
266 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000267 * Delete all previously added flows.
268 *
269 * @return true on success, otherwise false.
270 */
271 @Override
272 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800273 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700274 datagridService.notificationSendAllFlowsRemoved();
275 return true;
276 }
277 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000278 }
279
280 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800281 * Delete a previously added flow.
282 *
283 * @param flowId the Flow ID of the flow to delete.
284 * @return true on success, otherwise false.
285 */
286 @Override
287 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800288 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700289 datagridService.notificationSendFlowRemoved(flowId);
290 return true;
291 }
292 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700293 }
294
295 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800296 * Get a previously added flow.
297 *
298 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800299 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800300 */
301 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800302 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800303 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700304 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800305
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700306 /**
307 * Get all installed flows by all installers.
308 *
309 * @return the Flow Paths if found, otherwise null.
310 */
311 @Override
312 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800313 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800314 }
315
316 /**
admin944ef4f2013-10-08 17:48:37 -0700317 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700318 *
admin944ef4f2013-10-08 17:48:37 -0700319 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700320 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700321 * @return the Flow Paths if found, otherwise null.
322 */
323 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800324 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
325 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800326 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
327 SortedMap<Long, FlowPath> sortedFlowPaths =
328 flowEventHandler.getAllFlowPathsCopy();
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800329
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800330 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800331 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800332 //
333 for (FlowPath flowPath : sortedFlowPaths.values()) {
334 //
335 // TODO: Add only the Flow Paths that have been successfully
336 // installed.
337 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800338 flowPath.setFlowEntryMatch(null);
339 flowPath.setFlowEntryActions(null);
340 for (FlowEntry flowEntry : flowPath.flowEntries()) {
341 flowEntry.setFlowEntryMatch(null);
342 flowEntry.setFlowEntryActions(null);
343 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800344 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800345 }
346
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800347 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700348 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700349
350 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800351 * Get the collection of my switches.
352 *
353 * @return the collection of my switches.
354 */
355 public Map<Long, IOFSwitch> getMySwitches() {
356 return floodlightProvider.getSwitches();
357 }
358
359 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800360 * Get the network topology.
361 *
362 * @return the network topology.
363 */
364 public Topology getTopology() {
365 return flowEventHandler.getTopology();
366 }
367
368 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800369 * Inform the Flow Manager that a Flow Entry on switch expired.
370 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800371 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800372 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
373 */
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800374 public void flowEntryOnSwitchExpired(IOFSwitch sw,
375 FlowEntryId flowEntryId) {
376 // Find the Flow Entry
377 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
Pavlin Radoslavovac0fabc2013-12-13 10:47:56 -0800378 if (flowEntry == null)
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800379 return; // Flow Entry not found
380
381 // Find the Flow Path
382 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
383 if (flowPath == null)
384 return; // Flow Path not found
385
386 //
387 // Remove the Flow if the Flow Entry expired on the first switch
388 //
389 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
390 if (srcDpid.value() != sw.getId())
391 return;
392 deleteFlow(flowPath.flowId());
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800393 }
394
395 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800396 * Inform the Flow Manager that a collection of Flow Entries have been
397 * pushed to a switch.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800398 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800399 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
400 * that have been pushed.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800401 */
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800402 public void flowEntriesPushedToSwitch(
403 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800404
405 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800406 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800407 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800408 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800409 FlowEntry flowEntry = entry.second;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800410
411 //
412 // Mark the Flow Entry that it has been pushed to the switch
413 //
414 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
415
416 //
417 // Write the Flow Entry to the Datagrid
418 //
419 switch (flowEntry.flowEntryUserState()) {
420 case FE_USER_ADD:
421 datagridService.notificationSendFlowEntryAdded(flowEntry);
422 break;
423 case FE_USER_MODIFY:
424 datagridService.notificationSendFlowEntryUpdated(flowEntry);
425 break;
426 case FE_USER_DELETE:
427 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
428 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800429 case FE_USER_UNKNOWN:
430 assert(false);
431 break;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800432 }
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800433 }
434 }
435
436 /**
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800437 * Generate a notification that a collection of Flow Paths has been
438 * installed in the network.
439 *
440 * @param flowPaths the collection of installed Flow Paths.
441 */
442 void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
443 forwardingService.flowsInstalled(flowPaths);
444 }
445
446 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800447 * Push modified Flow-related state as appropriate.
448 *
449 * @param modifiedFlowPaths the collection of modified Flow Paths.
450 * @param modifiedFlowEntries the collection of modified Flow Entries.
451 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800452 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
453 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800454 //
455 // Push the modified Flow state:
456 // - Flow Entries to switches and the datagrid
457 // - Flow Paths to the database
458 //
459 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800460 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800461 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800462 }
463
464 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800465 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700466 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800467 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700468 * are pushed.
469 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800470 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700471 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800472 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800473 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800474 if (modifiedFlowEntries.isEmpty())
475 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700476
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800477 List<Pair<IOFSwitch, FlowEntry>> entries =
478 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
479
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800480 Map<Long, IOFSwitch> mySwitches = getMySwitches();
481
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800482 //
483 // Create a collection of my Flow Entries to push
484 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800485 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800486 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
487 if (mySwitch == null)
488 continue;
489
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800490 //
491 // Assign Flow Entry IDs if missing.
492 //
493 // NOTE: This is an additional safeguard, in case the
494 // mySwitches set has changed (after the Flow Entry IDs
495 // assignments by the caller).
496 //
497 if (! flowEntry.isValidFlowEntryId()) {
498 long id = getNextFlowEntryId();
499 flowEntry.setFlowEntryId(new FlowEntryId(id));
500 }
501
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800502 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800503 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800504 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800505
506 pusher.pushFlowEntries(entries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800507 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700508
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800509 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800510 * Cleanup deleted Flow Entries from the datagrid.
511 *
512 * NOTE: We cleanup only the Flow Entries that are not for our switches.
513 * This is needed to handle the case a switch going down:
514 * It has no Master controller instance, hence no controller instance
515 * will cleanup its flow entries.
516 * This is sub-optimal: we need to elect a controller instance to handle
517 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800518 *
519 * @param modifiedFlowEntries the collection of modified Flow Entries.
520 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800521 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800522 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800523 if (modifiedFlowEntries.isEmpty())
524 return;
525
526 Map<Long, IOFSwitch> mySwitches = getMySwitches();
527
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800528 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800529 //
530 // Process only Flow Entries that should be deleted and have
531 // a valid Flow Entry ID.
532 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800533 if (! flowEntry.isValidFlowEntryId())
534 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800535 if (flowEntry.flowEntryUserState() !=
536 FlowEntryUserState.FE_USER_DELETE) {
537 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800538 }
539
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800540 //
541 // NOTE: The deletion of Flow Entries for my switches is handled
542 // elsewhere.
543 //
544 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
545 if (mySwitch != null)
546 continue;
547
548 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
549
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800550 //
551 // Write the Flow Entry to the Datagrid
552 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800553 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800554 }
555 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700556
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800557 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800558 * Class to implement writing to the database in a separate thread.
559 */
560 class FlowDatabaseWriter extends Thread {
561 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800562 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800563
564 /**
565 * Constructor.
566 *
567 * @param flowManager the Flow Manager to use.
568 * @param blockingQueue the blocking queue to use.
569 */
570 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800571 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800572 this.flowManager = flowManager;
573 this.blockingQueue = blockingQueue;
574 }
575
576 /**
577 * Run the thread.
578 */
579 @Override
580 public void run() {
581 //
582 // The main loop
583 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800584 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800585 try {
586 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800587 FlowPath flowPath = blockingQueue.take();
588 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800589 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800590 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800591 collection.clear();
592 }
593 } catch (Exception exception) {
594 log.debug("Exception writing to the Database: ", exception);
595 }
596 }
597 }
598
599 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800600 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800601 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800602 * NOTE: The complete Flow Paths are pushed only on the instance
603 * responsible for the first switch. This is to avoid database errors
604 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800605 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800606 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800607 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800608 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800609 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800610 List<FlowPath> copiedFlowPaths = new LinkedList<FlowPath>();
611
612 //
613 // Create a copy of the Flow Paths to push, because the pushing
614 // itself will happen on a separate thread.
615 //
616 Kryo kryo = kryoFactory.newKryo();
617 for (FlowPath flowPath : modifiedFlowPaths) {
618 FlowPath copyFlowPath = kryo.copy(flowPath);
619 copiedFlowPaths.add(copyFlowPath);
620 }
621 kryoFactory.deleteKryo(kryo);
622
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800623 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800624 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800625 // The FlowDatabaseWriter thread is responsible for the actual writing.
626 //
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800627 flowPathsToDatabaseQueue.addAll(copiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800628 }
629
630 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800631 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800632 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800633 * NOTE: The complete Flow Paths are pushed only on the instance
634 * responsible for the first switch. This is to avoid database errors
635 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800636 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800637 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800638 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800639 private void writeModifiedFlowPathsToDatabase(
640 Collection<FlowPath> modifiedFlowPaths) {
641 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800642 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700643
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800644 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700645
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800646 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800647 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800648 // Push the changes only on the instance responsible for the
649 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800650 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800651 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
652 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
653 if (mySrcSwitch == null)
654 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800655
656 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800657 // Delete the Flow Path from the Network Map
658 //
659 if (flowPath.flowPathUserState() ==
660 FlowPathUserState.FP_USER_DELETE) {
661 log.debug("Deleting Flow Path From Database: {}",
662 flowPath.toString());
663
664 try {
665 if (! FlowDatabaseOperation.deleteFlow(
666 dbHandlerInner,
667 flowPath.flowId())) {
668 log.error("Cannot delete Flow Path {} from Network Map",
669 flowPath.flowId());
670 }
671 } catch (Exception e) {
672 log.error("Exception deleting Flow Path from Network MAP: {}", e);
673 }
674 continue;
675 }
676
677 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800678 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800679 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800680 boolean allValid = true;
681 for (FlowEntry flowEntry : flowPath.flowEntries()) {
682 if (flowEntry.flowEntryUserState() ==
683 FlowEntryUserState.FE_USER_DELETE) {
684 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700685 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800686 if (! flowEntry.isValidFlowEntryId()) {
687 allValid = false;
688 break;
689 }
690 }
691 if (! allValid)
692 continue;
693
694 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
695
696 //
697 // Write the Flow Path to the Network Map
698 //
699 try {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800700 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800701 String logMsg = "Cannot write to Network Map Flow Path " +
702 flowPath.flowId();
703 log.error(logMsg);
704 }
705 } catch (Exception e) {
706 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700707 }
708 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700709 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800710}