blob: de847de00d30ece4e3254c54a5d5e602f32b9e7a [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 Radoslavov85f39d32014-01-10 19:14:35 -080011import java.util.TreeMap;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080012import java.util.concurrent.BlockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080013import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080014
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080017import net.floodlightcontroller.core.module.FloodlightModuleContext;
18import net.floodlightcontroller.core.module.FloodlightModuleException;
19import net.floodlightcontroller.core.module.IFloodlightModule;
20import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080021import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080022import net.floodlightcontroller.util.OFMessageDamper;
yoshi2fd4c7e2013-11-22 15:47:55 -080023import net.onrc.onos.graph.DBOperation;
24import net.onrc.onos.graph.GraphDBManager;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070025import net.onrc.onos.datagrid.IDatagridService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070026import net.onrc.onos.ofcontroller.core.INetMapStorage;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070027import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070028import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080029import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
Pavlin Radoslavovc0862662013-12-10 15:31:49 -080030import net.onrc.onos.ofcontroller.forwarding.IForwardingService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070031import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov63e42602013-12-12 12:54:05 -080032import net.onrc.onos.ofcontroller.util.Dpid;
33import net.onrc.onos.ofcontroller.util.FlowEntry;
34import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
35import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
36import net.onrc.onos.ofcontroller.util.FlowEntryId;
37import net.onrc.onos.ofcontroller.util.FlowId;
38import net.onrc.onos.ofcontroller.util.FlowPath;
39import net.onrc.onos.ofcontroller.util.FlowPathUserState;
40import net.onrc.onos.ofcontroller.util.Pair;
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080041import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080042
Pavlin Radoslavov262e6832013-12-18 14:37:35 -080043import com.thinkaurelius.titan.core.TitanException;
44
Yuta HIGUCHI2d5ac522014-01-22 10:21:41 -080045import com.esotericsoftware.kryo.Kryo;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080047import org.slf4j.Logger;
48import org.slf4j.LoggerFactory;
49
admin944ef4f2013-10-08 17:48:37 -070050/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070051 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070052 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070053public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080054
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -080055 private boolean enableOnrc2014MeasurementsFlows = true;
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080056
yoshitomob292c622013-11-23 14:35:58 -080057 protected DBOperation dbHandlerApi;
58 protected DBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080059
Jonathan Hart50a94982013-04-10 14:49:51 -070060 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070061 protected volatile IDatagridService datagridService;
62 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070063 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070064 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080065
Brian O'Connor8c166a72013-11-14 18:41:48 -080066 protected IFlowPusherService pusher;
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080067 protected IForwardingService forwardingService;
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080068
69 private KryoFactory kryoFactory = new KryoFactory();
70
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000071 // Flow Entry ID generation state
72 private static Random randomGenerator = new Random();
73 private static int nextFlowEntryIdPrefix = 0;
74 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070075
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080076 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070077 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080078
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080079 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080080 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
81 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080082 FlowDatabaseWriter flowDatabaseWriter;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080083
admin944ef4f2013-10-08 17:48:37 -070084 /**
85 * Initialize the Flow Manager.
86 *
87 * @param conf the Graph Database configuration string.
88 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080089 @Override
yoshi2fd4c7e2013-11-22 15:47:55 -080090 public void init(final String dbStore, final String conf) {
yoshib1f40702014-01-22 13:07:52 -080091 dbHandlerApi = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloud.conf");
92 dbHandlerInner = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloud.conf");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080093 }
94
admin944ef4f2013-10-08 17:48:37 -070095 /**
96 * Shutdown the Flow Manager operation.
97 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -080098 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080099 protected void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700100 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800101 }
102
admin944ef4f2013-10-08 17:48:37 -0700103 /**
104 * Shutdown the Flow Manager operation.
105 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800106 @Override
107 public void close() {
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800108 floodlightProvider.removeOFSwitchListener(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700109 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800110 dbHandlerApi.close();
111 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800112 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800113
admin944ef4f2013-10-08 17:48:37 -0700114 /**
115 * Get the collection of offered module services.
116 *
117 * @return the collection of offered module services.
118 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800119 @Override
120 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800121 Collection<Class<? extends IFloodlightService>> l =
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800122 new ArrayList<Class<? extends IFloodlightService>>();
123 l.add(IFlowService.class);
124 return l;
125 }
126
admin944ef4f2013-10-08 17:48:37 -0700127 /**
128 * Get the collection of implemented services.
129 *
130 * @return the collection of implemented services.
131 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800132 @Override
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800133 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800134 getServiceImpls() {
135 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700136 IFloodlightService> m =
137 new HashMap<Class<? extends IFloodlightService>,
138 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800139 m.put(IFlowService.class, this);
140 return m;
141 }
142
admin944ef4f2013-10-08 17:48:37 -0700143 /**
144 * Get the collection of modules this module depends on.
145 *
146 * @return the collection of modules this module depends on.
147 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800148 @Override
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800149 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700150 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800151 Collection<Class<? extends IFloodlightService>> l =
152 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800153 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700154 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700155 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800156 l.add(IRestApiService.class);
Pavlin Radoslavovc0862662013-12-10 15:31:49 -0800157 l.add(IFlowPusherService.class);
Pavlin Radoslavov63c2d052013-12-18 18:17:55 -0800158 //
159 // TODO: Comment-out the dependency on the IForwardingService,
160 // because it is an optional module. Apparently, adding the dependency
161 // here automatically enables the module.
162 //
163 // l.add(IForwardingService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800164 return l;
165 }
166
admin944ef4f2013-10-08 17:48:37 -0700167 /**
168 * Initialize the module.
169 *
170 * @param context the module context to use for the initialization.
171 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800172 @Override
173 public void init(FloodlightModuleContext context)
174 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700175 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800176 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700177 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800178 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800179 pusher = context.getServiceImpl(IFlowPusherService.class);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800180 forwardingService = context.getServiceImpl(IForwardingService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800181
yoshi0fee3de2013-11-23 09:13:37 -0800182 this.init("","");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800183 }
184
admin944ef4f2013-10-08 17:48:37 -0700185 /**
186 * Get the next Flow Entry ID to use.
187 *
188 * @return the next Flow Entry ID to use.
189 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800190 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700191 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000192 //
193 // Generate the next Flow Entry ID.
194 // NOTE: For now, the higher 32 bits are random, and
195 // the lower 32 bits are sequential.
196 // In the future, we need a better allocation mechanism.
197 //
198 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
199 nextFlowEntryIdPrefix = randomGenerator.nextInt();
200 nextFlowEntryIdSuffix = 0;
201 } else {
202 nextFlowEntryIdSuffix++;
203 }
204 long result = (long)nextFlowEntryIdPrefix << 32;
205 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
206 return result;
207 }
208
admin944ef4f2013-10-08 17:48:37 -0700209 /**
210 * Startup module operation.
211 *
212 * @param context the module context to use for the startup.
213 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800214 @Override
215 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700216 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700217
admin944ef4f2013-10-08 17:48:37 -0700218 // Initialize the Flow Entry ID generator
219 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800220
221 //
222 // The thread to write to the database
223 //
224 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800225 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800226 flowDatabaseWriter.start();
227
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700228 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800229 // The Flow Event Handler thread:
230 // - create
231 // - register with the Datagrid Service
232 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700233 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700234 flowEventHandler = new FlowEventHandler(this, datagridService);
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800235 floodlightProvider.addOFSwitchListener(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700236 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700237 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800238 }
239
240 /**
241 * Add a flow.
242 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800243 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800244 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800245 */
246 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800247 public FlowId addFlow(FlowPath flowPath) {
248
249 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800250 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800251 long id = getNextFlowEntryId();
252 flowPath.setFlowId(new FlowId(id));
253 }
254
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700255 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700256 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700257 // in case the application didn't do it.
258 //
259 for (FlowEntry flowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800260 // The Flow Entry switch state
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700261 if (flowEntry.flowEntrySwitchState() ==
262 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
263 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800264 }
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800265 // The Flow Entry ID
266 if (! flowEntry.isValidFlowEntryId()) {
267 long id = getNextFlowEntryId();
268 flowEntry.setFlowEntryId(new FlowEntryId(id));
269 }
270 // The Flow ID
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700271 if (! flowEntry.isValidFlowId())
272 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700273 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800274
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800275 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800276 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800277 datagridService.notificationSendFlowIdAdded(flowPath.flowId(),
278 flowPath.dataPath().srcPort().dpid());
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800279 } else {
280 datagridService.notificationSendFlowAdded(flowPath);
281 }
282
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800283 return flowPath.flowId();
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700284 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800285 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700286 }
287
288 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000289 * Delete all previously added flows.
290 *
291 * @return true on success, otherwise false.
292 */
293 @Override
294 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800295 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800296 if (enableOnrc2014MeasurementsFlows) {
297 datagridService.notificationSendAllFlowIdsRemoved();
298 } else {
299 datagridService.notificationSendAllFlowsRemoved();
300 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700301 return true;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000302 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700303 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000304 }
305
306 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800307 * Delete a previously added flow.
308 *
309 * @param flowId the Flow ID of the flow to delete.
310 * @return true on success, otherwise false.
311 */
312 @Override
313 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800314 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800315 if (enableOnrc2014MeasurementsFlows) {
316 datagridService.notificationSendFlowIdRemoved(flowId);
317 } else {
318 datagridService.notificationSendFlowRemoved(flowId);
319 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700320 return true;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700321 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700322 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700323 }
324
325 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800326 * Get a previously added flow.
327 *
328 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800329 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800330 */
331 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800332 public FlowPath getFlow(FlowId flowId) {
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800333 log.debug("FlowID: {}", flowId);
334 if(flowId.value() == -100) {
335 log.debug("Printing results...");
336 PerformanceMonitor.report();
337 PerformanceMonitor.clear();
338 }
339 else if(flowId.value() == -200) {
340 log.debug("Clearing results...");
341 PerformanceMonitor.clear();
342 }
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800343 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700344 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800345
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700346 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800347 * Get a previously added flow entry.
348 *
349 * @param flowEntryId the Flow Entry ID of the flow entry to get.
350 * @return the Flow Entry if found, otherwise null.
351 */
352 public FlowEntry getFlowEntry(FlowEntryId flowEntryId) {
353 return FlowDatabaseOperation.getFlowEntry(dbHandlerApi, flowEntryId);
354 }
355
356 /**
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800357 * Get the source switch DPID of a previously added flow.
358 *
359 * @param flowId the Flow ID of the flow to get.
360 * @return the source switch DPID if found, otherwise null.
361 */
362 public Dpid getFlowSourceDpid(FlowId flowId) {
363 return FlowDatabaseOperation.getFlowSourceDpid(dbHandlerApi, flowId);
364 }
365
366 /**
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700367 * Get all installed flows by all installers.
368 *
369 * @return the Flow Paths if found, otherwise null.
370 */
371 @Override
372 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800373 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800374 }
375
376 /**
Pavlin Radoslavov16b761d2014-01-08 09:47:14 -0800377 * Get all installed flows whose Source Switch is controlled by this
378 * instance.
379 *
380 * @param mySwitches the collection of the switches controlled by this
381 * instance.
382 * @return the Flow Paths if found, otherwise null.
383 */
384 public ArrayList<FlowPath> getAllMyFlows(Map<Long, IOFSwitch> mySwitches) {
385 return FlowDatabaseOperation.getAllMyFlows(dbHandlerApi, mySwitches);
386 }
387
388 /**
admin944ef4f2013-10-08 17:48:37 -0700389 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700390 *
admin944ef4f2013-10-08 17:48:37 -0700391 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700392 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700393 * @return the Flow Paths if found, otherwise null.
394 */
395 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800396 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
397 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800398 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
399 SortedMap<Long, FlowPath> sortedFlowPaths =
Pavlin Radoslavov85f39d32014-01-10 19:14:35 -0800400 new TreeMap<Long, FlowPath>();
401
402 if (enableOnrc2014MeasurementsFlows) {
403 Collection<FlowPath> databaseFlowPaths =
404 ParallelFlowDatabaseOperation.getAllFlows(dbHandlerApi);
405 for (FlowPath flowPath : databaseFlowPaths) {
406 sortedFlowPaths.put(flowPath.flowId().value(), flowPath);
407 }
408 } else {
409 sortedFlowPaths = flowEventHandler.getAllFlowPathsCopy();
410 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700411
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800412 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800413 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800414 //
415 for (FlowPath flowPath : sortedFlowPaths.values()) {
416 //
417 // TODO: Add only the Flow Paths that have been successfully
418 // installed.
419 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800420 flowPath.setFlowEntryMatch(null);
421 flowPath.setFlowEntryActions(null);
422 for (FlowEntry flowEntry : flowPath.flowEntries()) {
423 flowEntry.setFlowEntryMatch(null);
424 flowEntry.setFlowEntryActions(null);
425 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800426 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800427 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700428
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800429 return flowPaths;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700430 }
431
432 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800433 * Get the collection of my switches.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700434 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800435 * @return the collection of my switches.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700436 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800437 public Map<Long, IOFSwitch> getMySwitches() {
438 return floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700439 }
440
441 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800442 * Get the network topology.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700443 *
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800444 * @return the network topology.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700445 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800446 @Override
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800447 public Topology getTopology() {
448 return flowEventHandler.getTopology();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700449 }
450
451 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800452 * Inform the Flow Manager that a Flow Entry on switch expired.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700453 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800454 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800455 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700456 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800457 @Override
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800458 public void flowEntryOnSwitchExpired(IOFSwitch sw,
459 FlowEntryId flowEntryId) {
460 // Find the Flow Entry
461 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
yoshia97632b2013-12-17 15:46:08 -0800462 if (flowEntry == null)
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800463 return; // Flow Entry not found
464
465 // Find the Flow Path
466 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
467 if (flowPath == null)
468 return; // Flow Path not found
469
470 //
471 // Remove the Flow if the Flow Entry expired on the first switch
472 //
473 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
474 if (srcDpid.value() != sw.getId())
475 return;
476 deleteFlow(flowPath.flowId());
Jonathan Hart0444d932014-01-22 15:06:17 -0800477
478 // Send flow deleted notification to the Forwarding module
479 // TODO This is a quick fix for flow-removed notifications. We
480 // should think more about the design of these notifications.
481 notificationFlowPathRemoved(flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700482 }
483
484 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800485 * Inform the Flow Manager that a collection of Flow Entries have been
486 * pushed to a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700487 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800488 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
489 * that have been pushed.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700490 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800491 @Override
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800492 public void flowEntriesPushedToSwitch(
493 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700494
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800495 if (enableOnrc2014MeasurementsFlows)
496 return;
497
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800498 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800499 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800500 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800501 // TODO: For now we have to create an explicit FlowEntry copy so
502 // we don't modify the original FlowEntry.
503 // This should go away after we start using the OpenFlow Barrier
504 // mechnanism in the FlowPusher.
505 //
506 Kryo kryo = kryoFactory.newKryo();
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800507 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800508 FlowEntry flowEntry = entry.second;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800509
510 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800511 // Mark the Flow Entry that it has been pushed to the switch
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800512 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800513 FlowEntry copyFlowEntry = kryo.copy(flowEntry);
514 copyFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700515
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800516 //
517 // Write the Flow Entry to the Datagrid
518 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800519 switch (copyFlowEntry.flowEntryUserState()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800520 case FE_USER_ADD:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800521 datagridService.notificationSendFlowEntryAdded(copyFlowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800522 break;
523 case FE_USER_MODIFY:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800524 datagridService.notificationSendFlowEntryUpdated(copyFlowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800525 break;
526 case FE_USER_DELETE:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800527 datagridService.notificationSendFlowEntryRemoved(copyFlowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800528 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800529 case FE_USER_UNKNOWN:
530 assert(false);
531 break;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800532 }
533 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800534 kryoFactory.deleteKryo(kryo);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800535 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700536
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800537 /**
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800538 * Generate a notification that a collection of Flow Paths has been
539 * installed in the network.
540 *
541 * @param flowPaths the collection of installed Flow Paths.
542 */
543 void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
Pavlin Radoslavov63c2d052013-12-18 18:17:55 -0800544 //
545 // TODO: Add an explicit check for null pointer, because
546 // the IForwardingService is optional. Remove the "if" statement
547 // after hte Forwarding Module becomes mandatory.
548 //
549 if (forwardingService != null)
550 forwardingService.flowsInstalled(flowPaths);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800551 }
552
553 /**
Jonathan Hart0444d932014-01-22 15:06:17 -0800554 * Generate a notification that a FlowPath has been removed from the
555 * network. This means we've received an expiry message for the flow
556 * from the switch, and send flowmods to remove any remaining parts of
557 * the path.
558 *
559 * @param flowPath FlowPath object that was removed from the network.
560 */
561 void notificationFlowPathRemoved(FlowPath flowPath) {
562 if (forwardingService != null) {
563 forwardingService.flowRemoved(flowPath);
564 }
565 }
566
567 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800568 * Push modified Flow-related state as appropriate.
569 *
570 * @param modifiedFlowPaths the collection of modified Flow Paths.
571 * @param modifiedFlowEntries the collection of modified Flow Entries.
572 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800573 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
574 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800575 //
576 // Push the modified Flow state:
577 // - Flow Entries to switches and the datagrid
578 // - Flow Paths to the database
579 //
580 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800581 if (enableOnrc2014MeasurementsFlows) {
582 writeModifiedFlowPathsToDatabase(modifiedFlowPaths);
583 } else {
584 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800585 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
586 }
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800587 }
588
589 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700590 * Push modified Flow Entries to switches.
591 *
592 * NOTE: Only the Flow Entries to switches controlled by this instance
593 * are pushed.
594 *
595 * @param modifiedFlowEntries the collection of modified Flow Entries.
596 */
Pavlin Radoslavov7847db72014-01-10 11:35:21 -0800597 void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800598 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700599 if (modifiedFlowEntries.isEmpty())
600 return;
601
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800602 List<Pair<IOFSwitch, FlowEntry>> entries =
603 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
604
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700605 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700606
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800607 //
608 // Create a collection of my Flow Entries to push
609 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800610 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700611 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
612 if (mySwitch == null)
613 continue;
614
Pavlin Radoslavovd1b728c2013-12-18 21:39:58 -0800615 if (flowEntry.flowEntrySwitchState() ==
616 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
617 //
618 // Don't push again Flow Entries that were already already
619 // installed into the switches.
620 //
621 continue;
622 }
623
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800624 //
625 // Assign Flow Entry IDs if missing.
626 //
627 // NOTE: This is an additional safeguard, in case the
628 // mySwitches set has changed (after the Flow Entry IDs
629 // assignments by the caller).
630 //
631 if (! flowEntry.isValidFlowEntryId()) {
632 long id = getNextFlowEntryId();
633 flowEntry.setFlowEntryId(new FlowEntryId(id));
634 }
635
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800636 log.debug("Pushing Flow Entry To Switch: {}", flowEntry);
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800637 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700638 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800639
640 pusher.pushFlowEntries(entries);
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700641 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700642
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700643 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800644 * Cleanup deleted Flow Entries from the datagrid.
645 *
646 * NOTE: We cleanup only the Flow Entries that are not for our switches.
647 * This is needed to handle the case a switch going down:
648 * It has no Master controller instance, hence no controller instance
649 * will cleanup its flow entries.
650 * This is sub-optimal: we need to elect a controller instance to handle
651 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700652 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800653 * @param modifiedFlowEntries the collection of modified Flow Entries.
654 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800655 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800656 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800657 if (modifiedFlowEntries.isEmpty())
658 return;
659
660 Map<Long, IOFSwitch> mySwitches = getMySwitches();
661
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800662 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800663 //
664 // Process only Flow Entries that should be deleted and have
665 // a valid Flow Entry ID.
666 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800667 if (! flowEntry.isValidFlowEntryId())
668 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800669 if (flowEntry.flowEntryUserState() !=
670 FlowEntryUserState.FE_USER_DELETE) {
671 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700672 }
673
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800674 //
675 // NOTE: The deletion of Flow Entries for my switches is handled
676 // elsewhere.
677 //
678 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
679 if (mySwitch != null)
680 continue;
681
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800682 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800683
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700684 //
685 // Write the Flow Entry to the Datagrid
686 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800687 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700688 }
689 }
690
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800691 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800692 * Class to implement writing to the database in a separate thread.
693 */
694 class FlowDatabaseWriter extends Thread {
695 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800696 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800697
698 /**
699 * Constructor.
700 *
701 * @param flowManager the Flow Manager to use.
702 * @param blockingQueue the blocking queue to use.
703 */
704 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800705 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800706 this.flowManager = flowManager;
707 this.blockingQueue = blockingQueue;
708 }
709
710 /**
711 * Run the thread.
712 */
713 @Override
714 public void run() {
715 //
716 // The main loop
717 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800718 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800719 this.setName("FlowDatabaseWriter " + this.getId() );
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800720 try {
721 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800722 FlowPath flowPath = blockingQueue.take();
723 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800724 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800725 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800726 collection.clear();
727 }
728 } catch (Exception exception) {
729 log.debug("Exception writing to the Database: ", exception);
730 }
731 }
732 }
733
734 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800735 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800736 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800737 * NOTE: The complete Flow Paths are pushed only on the instance
738 * responsible for the first switch. This is to avoid database errors
739 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800740 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800741 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800742 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800743 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800744 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800745 List<FlowPath> copiedFlowPaths = new LinkedList<FlowPath>();
746
747 //
748 // Create a copy of the Flow Paths to push, because the pushing
749 // itself will happen on a separate thread.
750 //
751 Kryo kryo = kryoFactory.newKryo();
752 for (FlowPath flowPath : modifiedFlowPaths) {
753 FlowPath copyFlowPath = kryo.copy(flowPath);
754 copiedFlowPaths.add(copyFlowPath);
755 }
756 kryoFactory.deleteKryo(kryo);
757
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800758 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800759 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800760 // The FlowDatabaseWriter thread is responsible for the actual writing.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800761 //
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800762 flowPathsToDatabaseQueue.addAll(copiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800763 }
764
765 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800766 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800767 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800768 * NOTE: The complete Flow Paths are pushed only on the instance
769 * responsible for the first switch. This is to avoid database errors
770 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800771 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800772 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800773 */
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800774 void writeModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800775 Collection<FlowPath> modifiedFlowPaths) {
776 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800777 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700778
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800779 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700780
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800781 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800782 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800783 // Push the changes only on the instance responsible for the
784 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800785 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800786 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
787 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
788 if (mySrcSwitch == null)
789 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800790
791 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800792 // Delete the Flow Path from the Network Map
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800793 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800794 if (flowPath.flowPathUserState() ==
795 FlowPathUserState.FP_USER_DELETE) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800796 log.debug("Deleting Flow Path From Database: {}", flowPath);
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800797
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800798 boolean retry = false;
799 do {
800 retry = false;
801 try {
802 if (! FlowDatabaseOperation.deleteFlow(
803 dbHandlerInner,
804 flowPath.flowId())) {
805 log.error("Cannot delete Flow Path {} from Network Map",
806 flowPath.flowId());
807 retry = true;
808 }
809 } catch (TitanException te) {
810 log.error("Titan Exception deleting Flow Path from Network MAP: {}", te);
811 retry = true;
812 } catch (Exception e) {
813 log.error("Exception deleting Flow Path from Network MAP: {}", e);
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800814 }
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800815 } while (retry);
816
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800817 continue;
818 }
819
820 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800821 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800822 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800823 boolean allValid = true;
824 for (FlowEntry flowEntry : flowPath.flowEntries()) {
825 if (flowEntry.flowEntryUserState() ==
826 FlowEntryUserState.FE_USER_DELETE) {
827 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700828 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800829 if (! flowEntry.isValidFlowEntryId()) {
830 allValid = false;
831 break;
832 }
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800833 if (! enableOnrc2014MeasurementsFlows) {
834 if (flowEntry.flowEntrySwitchState() !=
835 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
836 allValid = false;
837 break;
838 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800839 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800840 }
841 if (! allValid)
842 continue;
843
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800844 log.debug("Pushing Flow Path To Database: {}", flowPath);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800845
846 //
847 // Write the Flow Path to the Network Map
848 //
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800849 boolean retry = false;
850 do {
851 retry = false;
852 try {
Masayoshi Kobayashi178ead12013-12-19 20:50:19 -0800853 long startTime = System.nanoTime();
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800854 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800855 log.error("Cannot write to Network Map Flow Path {}", flowPath.flowId());
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800856 retry = true;
857 }
Masayoshi Kobayashi178ead12013-12-19 20:50:19 -0800858 // FIXME Flag to turn ON logging
859 //long endTime = System.nanoTime();
860 //log.error("Performance %% Flow path total time {} : {}", endTime - startTime, flowPath.toString());
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800861 } catch (TitanException te) {
862 log.error("Titan Exception writing Flow Path to Network MAP: ", te);
863 retry = true;
Masayoshi Kobayashi178ead12013-12-19 20:50:19 -0800864 // FIXME Flag to turn ON logging
865 //long endTime = System.nanoTime();
866 //log.error("Performance %% Flow path total time {} : {}", endTime - startTime, flowPath.toString());
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800867 } catch (Exception e) {
868 log.error("Exception writing Flow Path to Network MAP: ", e);
Masayoshi Kobayashi178ead12013-12-19 20:50:19 -0800869 // FIXME Flag to turn ON logging
870 //long endTime = System.nanoTime();
871 //log.error("Performance %% Flow path total time {} : {}", endTime - startTime, flowPath.toString());
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800872 }
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800873 } while (retry);
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800874
875 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavovf4bdf262014-01-09 13:51:40 -0800876 // Send the notifications
Pavlin Radoslavov7847db72014-01-10 11:35:21 -0800877
Pavlin Radoslavovf4bdf262014-01-09 13:51:40 -0800878 for (FlowEntry flowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov8edd4412014-01-10 11:37:32 -0800879 if (flowEntry.flowEntrySwitchState() !=
Pavlin Radoslavovf4bdf262014-01-09 13:51:40 -0800880 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavov8edd4412014-01-10 11:37:32 -0800881 continue;
Pavlin Radoslavovf4bdf262014-01-09 13:51:40 -0800882 }
Pavlin Radoslavov8edd4412014-01-10 11:37:32 -0800883 // datagridService.notificationSendFlowEntryIdAdded(flowEntry.flowEntryId(), flowEntry.dpid());
Pavlin Radoslavov7847db72014-01-10 11:35:21 -0800884
885 //
886 // Write the Flow Entry to the Datagrid
887 //
888 switch (flowEntry.flowEntryUserState()) {
889 case FE_USER_ADD:
890 datagridService.notificationSendFlowEntryAdded(flowEntry);
891 break;
892 case FE_USER_MODIFY:
893 datagridService.notificationSendFlowEntryUpdated(flowEntry);
894 break;
895 case FE_USER_DELETE:
896 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
897 break;
898 case FE_USER_UNKNOWN:
899 assert(false);
900 break;
901 }
Pavlin Radoslavovf4bdf262014-01-09 13:51:40 -0800902 }
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800903 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700904 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800905 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800906}