blob: f1e67400123650e04e1d5e16708972cb14e613c6 [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 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -080090 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080091 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070092 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080093 }
94
admin944ef4f2013-10-08 17:48:37 -070095 /**
96 * Shutdown the Flow Manager operation.
97 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080098 @Override
99 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700100 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800101 dbHandlerApi.close();
102 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800103 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800104
admin944ef4f2013-10-08 17:48:37 -0700105 /**
106 * Get the collection of offered module services.
107 *
108 * @return the collection of offered module services.
109 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800110 @Override
111 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800112 Collection<Class<? extends IFloodlightService>> l =
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800113 new ArrayList<Class<? extends IFloodlightService>>();
114 l.add(IFlowService.class);
115 return l;
116 }
117
admin944ef4f2013-10-08 17:48:37 -0700118 /**
119 * Get the collection of implemented services.
120 *
121 * @return the collection of implemented services.
122 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800123 @Override
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800124 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800125 getServiceImpls() {
126 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700127 IFloodlightService> m =
128 new HashMap<Class<? extends IFloodlightService>,
129 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800130 m.put(IFlowService.class, this);
131 return m;
132 }
133
admin944ef4f2013-10-08 17:48:37 -0700134 /**
135 * Get the collection of modules this module depends on.
136 *
137 * @return the collection of modules this module depends on.
138 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800139 @Override
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800140 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700141 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800142 Collection<Class<? extends IFloodlightService>> l =
143 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800144 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700145 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700146 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800147 l.add(IRestApiService.class);
Pavlin Radoslavovc0862662013-12-10 15:31:49 -0800148 l.add(IFlowPusherService.class);
149 l.add(IForwardingService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800150 return l;
151 }
152
admin944ef4f2013-10-08 17:48:37 -0700153 /**
154 * Initialize the module.
155 *
156 * @param context the module context to use for the initialization.
157 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800158 @Override
159 public void init(FloodlightModuleContext context)
160 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700161 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800162 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700163 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800164 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800165 pusher = context.getServiceImpl(IFlowPusherService.class);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800166 forwardingService = context.getServiceImpl(IForwardingService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800167
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700168 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800169 }
170
admin944ef4f2013-10-08 17:48:37 -0700171 /**
172 * Get the next Flow Entry ID to use.
173 *
174 * @return the next Flow Entry ID to use.
175 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800176 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700177 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000178 //
179 // Generate the next Flow Entry ID.
180 // NOTE: For now, the higher 32 bits are random, and
181 // the lower 32 bits are sequential.
182 // In the future, we need a better allocation mechanism.
183 //
184 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
185 nextFlowEntryIdPrefix = randomGenerator.nextInt();
186 nextFlowEntryIdSuffix = 0;
187 } else {
188 nextFlowEntryIdSuffix++;
189 }
190 long result = (long)nextFlowEntryIdPrefix << 32;
191 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
192 return result;
193 }
194
admin944ef4f2013-10-08 17:48:37 -0700195 /**
196 * Startup module operation.
197 *
198 * @param context the module context to use for the startup.
199 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800200 @Override
201 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700202 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700203
admin944ef4f2013-10-08 17:48:37 -0700204 // Initialize the Flow Entry ID generator
205 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800206
207 //
208 // The thread to write to the database
209 //
210 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800211 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800212 flowDatabaseWriter.start();
213
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700214 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800215 // The Flow Event Handler thread:
216 // - create
217 // - register with the Datagrid Service
218 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700219 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700220 flowEventHandler = new FlowEventHandler(this, datagridService);
221 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700222 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800223 }
224
225 /**
226 * Add a flow.
227 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800228 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800229 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800230 */
231 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800232 public FlowId addFlow(FlowPath flowPath) {
233
234 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800235 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800236 long id = getNextFlowEntryId();
237 flowPath.setFlowId(new FlowId(id));
238 }
239
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700240 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700241 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700242 // in case the application didn't do it.
243 //
244 for (FlowEntry flowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800245 // The Flow Entry switch state
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700246 if (flowEntry.flowEntrySwitchState() ==
247 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
248 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
249 }
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800250 // The Flow Entry ID
251 if (! flowEntry.isValidFlowEntryId()) {
252 long id = getNextFlowEntryId();
253 flowEntry.setFlowEntryId(new FlowEntryId(id));
254 }
255 // The Flow ID
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700256 if (! flowEntry.isValidFlowId())
257 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700258 }
259
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800260 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700261 datagridService.notificationSendFlowAdded(flowPath);
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800262 return flowPath.flowId();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700263 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800264 return null;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800265 }
266
267 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000268 * Delete all previously added flows.
269 *
270 * @return true on success, otherwise false.
271 */
272 @Override
273 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800274 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700275 datagridService.notificationSendAllFlowsRemoved();
276 return true;
277 }
278 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000279 }
280
281 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800282 * Delete a previously added flow.
283 *
284 * @param flowId the Flow ID of the flow to delete.
285 * @return true on success, otherwise false.
286 */
287 @Override
288 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800289 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700290 datagridService.notificationSendFlowRemoved(flowId);
291 return true;
292 }
293 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700294 }
295
296 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800297 * Get a previously added flow.
298 *
299 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800300 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800301 */
302 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800303 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800304 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700305 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800306
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700307 /**
308 * Get all installed flows by all installers.
309 *
310 * @return the Flow Paths if found, otherwise null.
311 */
312 @Override
313 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800314 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800315 }
316
317 /**
admin944ef4f2013-10-08 17:48:37 -0700318 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700319 *
admin944ef4f2013-10-08 17:48:37 -0700320 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700321 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700322 * @return the Flow Paths if found, otherwise null.
323 */
324 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800325 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
326 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800327 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
328 SortedMap<Long, FlowPath> sortedFlowPaths =
329 flowEventHandler.getAllFlowPathsCopy();
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800330
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800331 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800332 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800333 //
334 for (FlowPath flowPath : sortedFlowPaths.values()) {
335 //
336 // TODO: Add only the Flow Paths that have been successfully
337 // installed.
338 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800339 flowPath.setFlowEntryMatch(null);
340 flowPath.setFlowEntryActions(null);
341 for (FlowEntry flowEntry : flowPath.flowEntries()) {
342 flowEntry.setFlowEntryMatch(null);
343 flowEntry.setFlowEntryActions(null);
344 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800345 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800346 }
347
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800348 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700349 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700350
351 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800352 * Get the collection of my switches.
353 *
354 * @return the collection of my switches.
355 */
356 public Map<Long, IOFSwitch> getMySwitches() {
357 return floodlightProvider.getSwitches();
358 }
359
360 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800361 * Get the network topology.
362 *
363 * @return the network topology.
364 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800365 @Override
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800366 public Topology getTopology() {
367 return flowEventHandler.getTopology();
368 }
369
370 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800371 * Inform the Flow Manager that a Flow Entry on switch expired.
372 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800373 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800374 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
375 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800376 @Override
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800377 public void flowEntryOnSwitchExpired(IOFSwitch sw,
378 FlowEntryId flowEntryId) {
379 // Find the Flow Entry
380 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
Pavlin Radoslavovac0fabc2013-12-13 10:47:56 -0800381 if (flowEntry == null)
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800382 return; // Flow Entry not found
383
384 // Find the Flow Path
385 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
386 if (flowPath == null)
387 return; // Flow Path not found
388
389 //
390 // Remove the Flow if the Flow Entry expired on the first switch
391 //
392 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
393 if (srcDpid.value() != sw.getId())
394 return;
395 deleteFlow(flowPath.flowId());
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800396 }
397
398 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800399 * Inform the Flow Manager that a collection of Flow Entries have been
400 * pushed to a switch.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800401 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800402 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
403 * that have been pushed.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800404 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800405 @Override
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800406 public void flowEntriesPushedToSwitch(
407 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800408
409 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800410 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800411 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800412 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800413 FlowEntry flowEntry = entry.second;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800414
415 //
416 // Mark the Flow Entry that it has been pushed to the switch
417 //
418 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
419
420 //
421 // Write the Flow Entry to the Datagrid
422 //
423 switch (flowEntry.flowEntryUserState()) {
424 case FE_USER_ADD:
425 datagridService.notificationSendFlowEntryAdded(flowEntry);
426 break;
427 case FE_USER_MODIFY:
428 datagridService.notificationSendFlowEntryUpdated(flowEntry);
429 break;
430 case FE_USER_DELETE:
431 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
432 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800433 case FE_USER_UNKNOWN:
434 assert(false);
435 break;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800436 }
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800437 }
438 }
439
440 /**
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800441 * Generate a notification that a collection of Flow Paths has been
442 * installed in the network.
443 *
444 * @param flowPaths the collection of installed Flow Paths.
445 */
446 void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
447 forwardingService.flowsInstalled(flowPaths);
448 }
449
450 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800451 * Push modified Flow-related state as appropriate.
452 *
453 * @param modifiedFlowPaths the collection of modified Flow Paths.
454 * @param modifiedFlowEntries the collection of modified Flow Entries.
455 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800456 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
457 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800458 //
459 // Push the modified Flow state:
460 // - Flow Entries to switches and the datagrid
461 // - Flow Paths to the database
462 //
463 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800464 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800465 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800466 }
467
468 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800469 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700470 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800471 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700472 * are pushed.
473 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800474 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700475 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800476 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800477 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800478 if (modifiedFlowEntries.isEmpty())
479 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700480
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800481 List<Pair<IOFSwitch, FlowEntry>> entries =
482 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
483
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800484 Map<Long, IOFSwitch> mySwitches = getMySwitches();
485
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800486 //
487 // Create a collection of my Flow Entries to push
488 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800489 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800490 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
491 if (mySwitch == null)
492 continue;
493
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800494 //
495 // Assign Flow Entry IDs if missing.
496 //
497 // NOTE: This is an additional safeguard, in case the
498 // mySwitches set has changed (after the Flow Entry IDs
499 // assignments by the caller).
500 //
501 if (! flowEntry.isValidFlowEntryId()) {
502 long id = getNextFlowEntryId();
503 flowEntry.setFlowEntryId(new FlowEntryId(id));
504 }
505
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800506 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800507 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800508 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800509
510 pusher.pushFlowEntries(entries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800511 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700512
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800513 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800514 * Cleanup deleted Flow Entries from the datagrid.
515 *
516 * NOTE: We cleanup only the Flow Entries that are not for our switches.
517 * This is needed to handle the case a switch going down:
518 * It has no Master controller instance, hence no controller instance
519 * will cleanup its flow entries.
520 * This is sub-optimal: we need to elect a controller instance to handle
521 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800522 *
523 * @param modifiedFlowEntries the collection of modified Flow Entries.
524 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800525 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800526 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800527 if (modifiedFlowEntries.isEmpty())
528 return;
529
530 Map<Long, IOFSwitch> mySwitches = getMySwitches();
531
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800532 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800533 //
534 // Process only Flow Entries that should be deleted and have
535 // a valid Flow Entry ID.
536 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800537 if (! flowEntry.isValidFlowEntryId())
538 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800539 if (flowEntry.flowEntryUserState() !=
540 FlowEntryUserState.FE_USER_DELETE) {
541 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800542 }
543
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800544 //
545 // NOTE: The deletion of Flow Entries for my switches is handled
546 // elsewhere.
547 //
548 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
549 if (mySwitch != null)
550 continue;
551
552 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
553
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800554 //
555 // Write the Flow Entry to the Datagrid
556 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800557 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800558 }
559 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700560
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800561 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800562 * Class to implement writing to the database in a separate thread.
563 */
564 class FlowDatabaseWriter extends Thread {
565 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800566 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800567
568 /**
569 * Constructor.
570 *
571 * @param flowManager the Flow Manager to use.
572 * @param blockingQueue the blocking queue to use.
573 */
574 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800575 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800576 this.flowManager = flowManager;
577 this.blockingQueue = blockingQueue;
578 }
579
580 /**
581 * Run the thread.
582 */
583 @Override
584 public void run() {
585 //
586 // The main loop
587 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800588 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800589 this.setName("FlowDatabaseWriter " + this.getId() );
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800590 try {
591 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800592 FlowPath flowPath = blockingQueue.take();
593 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800594 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800595 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800596 collection.clear();
597 }
598 } catch (Exception exception) {
599 log.debug("Exception writing to the Database: ", exception);
600 }
601 }
602 }
603
604 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800605 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800606 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800607 * NOTE: The complete Flow Paths are pushed only on the instance
608 * responsible for the first switch. This is to avoid database errors
609 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800610 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800611 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800612 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800613 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800614 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800615 List<FlowPath> copiedFlowPaths = new LinkedList<FlowPath>();
616
617 //
618 // Create a copy of the Flow Paths to push, because the pushing
619 // itself will happen on a separate thread.
620 //
621 Kryo kryo = kryoFactory.newKryo();
622 for (FlowPath flowPath : modifiedFlowPaths) {
623 FlowPath copyFlowPath = kryo.copy(flowPath);
624 copiedFlowPaths.add(copyFlowPath);
625 }
626 kryoFactory.deleteKryo(kryo);
627
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800628 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800629 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800630 // The FlowDatabaseWriter thread is responsible for the actual writing.
631 //
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800632 flowPathsToDatabaseQueue.addAll(copiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800633 }
634
635 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800636 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800637 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800638 * NOTE: The complete Flow Paths are pushed only on the instance
639 * responsible for the first switch. This is to avoid database errors
640 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800641 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800642 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800643 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800644 private void writeModifiedFlowPathsToDatabase(
645 Collection<FlowPath> modifiedFlowPaths) {
646 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800647 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700648
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800649 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700650
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800651 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800652 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800653 // Push the changes only on the instance responsible for the
654 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800655 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800656 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
657 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
658 if (mySrcSwitch == null)
659 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800660
661 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800662 // Delete the Flow Path from the Network Map
663 //
664 if (flowPath.flowPathUserState() ==
665 FlowPathUserState.FP_USER_DELETE) {
666 log.debug("Deleting Flow Path From Database: {}",
667 flowPath.toString());
668
669 try {
670 if (! FlowDatabaseOperation.deleteFlow(
671 dbHandlerInner,
672 flowPath.flowId())) {
673 log.error("Cannot delete Flow Path {} from Network Map",
674 flowPath.flowId());
675 }
676 } catch (Exception e) {
677 log.error("Exception deleting Flow Path from Network MAP: {}", e);
678 }
679 continue;
680 }
681
682 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800683 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800684 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800685 boolean allValid = true;
686 for (FlowEntry flowEntry : flowPath.flowEntries()) {
687 if (flowEntry.flowEntryUserState() ==
688 FlowEntryUserState.FE_USER_DELETE) {
689 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700690 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800691 if (! flowEntry.isValidFlowEntryId()) {
692 allValid = false;
693 break;
694 }
695 }
696 if (! allValid)
697 continue;
698
699 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
700
701 //
702 // Write the Flow Path to the Network Map
703 //
704 try {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800705 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800706 String logMsg = "Cannot write to Network Map Flow Path " +
707 flowPath.flowId();
708 log.error(logMsg);
709 }
710 } catch (Exception e) {
711 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700712 }
713 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700714 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800715}