blob: f4664ccbdb278a335e52d885686b0e549014b01e [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;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070027import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080028import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
Pavlin Radoslavovc0862662013-12-10 15:31:49 -080029import net.onrc.onos.ofcontroller.forwarding.IForwardingService;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080030import net.onrc.onos.ofcontroller.networkgraph.INetworkGraphService;
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;
Yuta HIGUCHI2d5ac522014-01-22 10:21:41 -080044import com.esotericsoftware.kryo.Kryo;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080045
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080046import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
admin944ef4f2013-10-08 17:48:37 -070049/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070050 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070051 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070052public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080053
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -080054 private boolean enableOnrc2014MeasurementsFlows = true;
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080055
yoshitomob292c622013-11-23 14:35:58 -080056 protected DBOperation dbHandlerApi;
57 protected DBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080058
Jonathan Hart50a94982013-04-10 14:49:51 -070059 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070060 protected volatile IDatagridService datagridService;
61 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070062 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070063 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080064
Brian O'Connor8c166a72013-11-14 18:41:48 -080065 protected IFlowPusherService pusher;
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080066 protected IForwardingService forwardingService;
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080067
68 private KryoFactory kryoFactory = new KryoFactory();
69
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000070 // Flow Entry ID generation state
71 private static Random randomGenerator = new Random();
72 private static int nextFlowEntryIdPrefix = 0;
73 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070074
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080075 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070076 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080077
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080078 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080079 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
80 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080081 FlowDatabaseWriter flowDatabaseWriter;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080082
admin944ef4f2013-10-08 17:48:37 -070083 /**
84 * Initialize the Flow Manager.
85 *
86 * @param conf the Graph Database configuration string.
87 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080088 @Override
yoshi2fd4c7e2013-11-22 15:47:55 -080089 public void init(final String dbStore, final String conf) {
Yoshi Muroi5804ce92014-02-08 03:58:04 -080090 dbHandlerApi = GraphDBManager.getDBOperation();
91 dbHandlerInner = GraphDBManager.getDBOperation();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080092 }
93
admin944ef4f2013-10-08 17:48:37 -070094 /**
95 * Shutdown the Flow Manager operation.
96 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -080097 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080098 protected void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070099 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800100 }
101
admin944ef4f2013-10-08 17:48:37 -0700102 /**
103 * Shutdown the Flow Manager operation.
104 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800105 @Override
106 public void close() {
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800107 floodlightProvider.removeOFSwitchListener(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700108 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800109 dbHandlerApi.close();
110 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800111 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800112
admin944ef4f2013-10-08 17:48:37 -0700113 /**
114 * Get the collection of offered module services.
115 *
116 * @return the collection of offered module services.
117 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800118 @Override
119 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800120 Collection<Class<? extends IFloodlightService>> l =
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800121 new ArrayList<Class<? extends IFloodlightService>>();
122 l.add(IFlowService.class);
123 return l;
124 }
125
admin944ef4f2013-10-08 17:48:37 -0700126 /**
127 * Get the collection of implemented services.
128 *
129 * @return the collection of implemented services.
130 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800131 @Override
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800132 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800133 getServiceImpls() {
134 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700135 IFloodlightService> m =
136 new HashMap<Class<? extends IFloodlightService>,
137 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800138 m.put(IFlowService.class, this);
139 return m;
140 }
141
admin944ef4f2013-10-08 17:48:37 -0700142 /**
143 * Get the collection of modules this module depends on.
144 *
145 * @return the collection of modules this module depends on.
146 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800147 @Override
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800148 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700149 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800150 Collection<Class<? extends IFloodlightService>> l =
151 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800152 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700153 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800154 l.add(IRestApiService.class);
Pavlin Radoslavovc0862662013-12-10 15:31:49 -0800155 l.add(IFlowPusherService.class);
Pavlin Radoslavov63c2d052013-12-18 18:17:55 -0800156 //
157 // TODO: Comment-out the dependency on the IForwardingService,
158 // because it is an optional module. Apparently, adding the dependency
159 // here automatically enables the module.
160 //
161 // l.add(IForwardingService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800162 return l;
163 }
164
admin944ef4f2013-10-08 17:48:37 -0700165 /**
166 * Initialize the module.
167 *
168 * @param context the module context to use for the initialization.
169 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800170 @Override
171 public void init(FloodlightModuleContext context)
172 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700173 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800174 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700175 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800176 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800177 pusher = context.getServiceImpl(IFlowPusherService.class);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800178 forwardingService = context.getServiceImpl(IForwardingService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800179
yoshi0fee3de2013-11-23 09:13:37 -0800180 this.init("","");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800181 }
182
admin944ef4f2013-10-08 17:48:37 -0700183 /**
184 * Get the next Flow Entry ID to use.
185 *
186 * @return the next Flow Entry ID to use.
187 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800188 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700189 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000190 //
191 // Generate the next Flow Entry ID.
192 // NOTE: For now, the higher 32 bits are random, and
193 // the lower 32 bits are sequential.
194 // In the future, we need a better allocation mechanism.
195 //
196 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
197 nextFlowEntryIdPrefix = randomGenerator.nextInt();
198 nextFlowEntryIdSuffix = 0;
199 } else {
200 nextFlowEntryIdSuffix++;
201 }
202 long result = (long)nextFlowEntryIdPrefix << 32;
203 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
204 return result;
205 }
206
admin944ef4f2013-10-08 17:48:37 -0700207 /**
208 * Startup module operation.
209 *
210 * @param context the module context to use for the startup.
211 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800212 @Override
213 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700214 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700215
admin944ef4f2013-10-08 17:48:37 -0700216 // Initialize the Flow Entry ID generator
217 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800218
219 //
220 // The thread to write to the database
221 //
222 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800223 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800224 flowDatabaseWriter.start();
225
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700226 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800227 // The Flow Event Handler thread:
228 // - create
229 // - register with the Datagrid Service
230 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700231 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700232 flowEventHandler = new FlowEventHandler(this, datagridService);
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800233 floodlightProvider.addOFSwitchListener(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700234 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700235 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800236 }
237
238 /**
239 * Add a flow.
240 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800241 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800242 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800243 */
244 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800245 public FlowId addFlow(FlowPath flowPath) {
246
247 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800248 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800249 long id = getNextFlowEntryId();
250 flowPath.setFlowId(new FlowId(id));
251 }
252
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700253 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700254 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700255 // in case the application didn't do it.
256 //
257 for (FlowEntry flowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800258 // The Flow Entry switch state
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700259 if (flowEntry.flowEntrySwitchState() ==
260 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
261 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800262 }
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800263 // The Flow Entry ID
264 if (! flowEntry.isValidFlowEntryId()) {
265 long id = getNextFlowEntryId();
266 flowEntry.setFlowEntryId(new FlowEntryId(id));
267 }
268 // The Flow ID
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700269 if (! flowEntry.isValidFlowId())
270 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700271 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800272
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800273 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800274 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800275 datagridService.notificationSendFlowIdAdded(flowPath.flowId(),
276 flowPath.dataPath().srcPort().dpid());
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800277 } else {
278 datagridService.notificationSendFlowAdded(flowPath);
279 }
280
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800281 return flowPath.flowId();
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700282 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800283 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700284 }
285
286 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000287 * Delete all previously added flows.
288 *
289 * @return true on success, otherwise false.
290 */
291 @Override
292 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800293 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800294 if (enableOnrc2014MeasurementsFlows) {
295 datagridService.notificationSendAllFlowIdsRemoved();
296 } else {
297 datagridService.notificationSendAllFlowsRemoved();
298 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700299 return true;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000300 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700301 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000302 }
303
304 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800305 * Delete a previously added flow.
306 *
307 * @param flowId the Flow ID of the flow to delete.
308 * @return true on success, otherwise false.
309 */
310 @Override
311 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800312 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800313 if (enableOnrc2014MeasurementsFlows) {
314 datagridService.notificationSendFlowIdRemoved(flowId);
315 } else {
316 datagridService.notificationSendFlowRemoved(flowId);
317 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700318 return true;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700319 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700320 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700321 }
322
323 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800324 * Get a previously added flow.
325 *
326 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800327 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800328 */
329 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800330 public FlowPath getFlow(FlowId flowId) {
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800331 log.debug("FlowID: {}", flowId);
332 if(flowId.value() == -100) {
333 log.debug("Printing results...");
334 PerformanceMonitor.report();
335 PerformanceMonitor.clear();
336 }
337 else if(flowId.value() == -200) {
338 log.debug("Clearing results...");
339 PerformanceMonitor.clear();
340 }
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800341 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700342 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800343
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700344 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800345 * Get a previously added flow entry.
346 *
347 * @param flowEntryId the Flow Entry ID of the flow entry to get.
348 * @return the Flow Entry if found, otherwise null.
349 */
350 public FlowEntry getFlowEntry(FlowEntryId flowEntryId) {
351 return FlowDatabaseOperation.getFlowEntry(dbHandlerApi, flowEntryId);
352 }
353
354 /**
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800355 * Get the source switch DPID of a previously added flow.
356 *
357 * @param flowId the Flow ID of the flow to get.
358 * @return the source switch DPID if found, otherwise null.
359 */
360 public Dpid getFlowSourceDpid(FlowId flowId) {
361 return FlowDatabaseOperation.getFlowSourceDpid(dbHandlerApi, flowId);
362 }
363
364 /**
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700365 * Get all installed flows by all installers.
366 *
367 * @return the Flow Paths if found, otherwise null.
368 */
369 @Override
370 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800371 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800372 }
373
374 /**
Pavlin Radoslavov16b761d2014-01-08 09:47:14 -0800375 * Get all installed flows whose Source Switch is controlled by this
376 * instance.
377 *
378 * @param mySwitches the collection of the switches controlled by this
379 * instance.
380 * @return the Flow Paths if found, otherwise null.
381 */
382 public ArrayList<FlowPath> getAllMyFlows(Map<Long, IOFSwitch> mySwitches) {
383 return FlowDatabaseOperation.getAllMyFlows(dbHandlerApi, mySwitches);
384 }
385
386 /**
admin944ef4f2013-10-08 17:48:37 -0700387 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700388 *
admin944ef4f2013-10-08 17:48:37 -0700389 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700390 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700391 * @return the Flow Paths if found, otherwise null.
392 */
393 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800394 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
395 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800396 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
397 SortedMap<Long, FlowPath> sortedFlowPaths =
Pavlin Radoslavov85f39d32014-01-10 19:14:35 -0800398 new TreeMap<Long, FlowPath>();
399
400 if (enableOnrc2014MeasurementsFlows) {
401 Collection<FlowPath> databaseFlowPaths =
402 ParallelFlowDatabaseOperation.getAllFlows(dbHandlerApi);
403 for (FlowPath flowPath : databaseFlowPaths) {
404 sortedFlowPaths.put(flowPath.flowId().value(), flowPath);
405 }
406 } else {
407 sortedFlowPaths = flowEventHandler.getAllFlowPathsCopy();
408 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700409
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800410 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800411 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800412 //
413 for (FlowPath flowPath : sortedFlowPaths.values()) {
414 //
415 // TODO: Add only the Flow Paths that have been successfully
416 // installed.
417 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800418 flowPath.setFlowEntryMatch(null);
419 flowPath.setFlowEntryActions(null);
420 for (FlowEntry flowEntry : flowPath.flowEntries()) {
421 flowEntry.setFlowEntryMatch(null);
422 flowEntry.setFlowEntryActions(null);
423 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800424 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800425 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700426
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800427 return flowPaths;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700428 }
429
430 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800431 * Get the collection of my switches.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700432 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800433 * @return the collection of my switches.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700434 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800435 public Map<Long, IOFSwitch> getMySwitches() {
436 return floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700437 }
438
439 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800440 * Get the network topology.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700441 *
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800442 * @return the network topology.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700443 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800444 @Override
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800445 public Topology getTopology() {
446 return flowEventHandler.getTopology();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700447 }
448
449 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800450 * Inform the Flow Manager that a Flow Entry on switch expired.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700451 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800452 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800453 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700454 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800455 @Override
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800456 public void flowEntryOnSwitchExpired(IOFSwitch sw,
457 FlowEntryId flowEntryId) {
458 // Find the Flow Entry
459 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
yoshia97632b2013-12-17 15:46:08 -0800460 if (flowEntry == null)
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800461 return; // Flow Entry not found
462
463 // Find the Flow Path
464 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
465 if (flowPath == null)
466 return; // Flow Path not found
467
468 //
469 // Remove the Flow if the Flow Entry expired on the first switch
470 //
471 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
472 if (srcDpid.value() != sw.getId())
473 return;
474 deleteFlow(flowPath.flowId());
Jonathan Hart0444d932014-01-22 15:06:17 -0800475
476 // Send flow deleted notification to the Forwarding module
477 // TODO This is a quick fix for flow-removed notifications. We
478 // should think more about the design of these notifications.
479 notificationFlowPathRemoved(flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700480 }
481
482 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800483 * Inform the Flow Manager that a collection of Flow Entries have been
484 * pushed to a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700485 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800486 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
487 * that have been pushed.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700488 */
Yuta HIGUCHI3ab1fd02013-12-17 11:01:02 -0800489 @Override
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800490 public void flowEntriesPushedToSwitch(
491 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700492
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800493 if (enableOnrc2014MeasurementsFlows)
494 return;
495
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800496 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800497 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800498 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800499 // TODO: For now we have to create an explicit FlowEntry copy so
500 // we don't modify the original FlowEntry.
501 // This should go away after we start using the OpenFlow Barrier
502 // mechnanism in the FlowPusher.
503 //
504 Kryo kryo = kryoFactory.newKryo();
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800505 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800506 FlowEntry flowEntry = entry.second;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800507
508 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800509 // Mark the Flow Entry that it has been pushed to the switch
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800510 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800511 FlowEntry copyFlowEntry = kryo.copy(flowEntry);
512 copyFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700513
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800514 //
515 // Write the Flow Entry to the Datagrid
516 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800517 switch (copyFlowEntry.flowEntryUserState()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800518 case FE_USER_ADD:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800519 datagridService.notificationSendFlowEntryAdded(copyFlowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800520 break;
521 case FE_USER_MODIFY:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800522 datagridService.notificationSendFlowEntryUpdated(copyFlowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800523 break;
524 case FE_USER_DELETE:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800525 datagridService.notificationSendFlowEntryRemoved(copyFlowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800526 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800527 case FE_USER_UNKNOWN:
528 assert(false);
529 break;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800530 }
531 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800532 kryoFactory.deleteKryo(kryo);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800533 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700534
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800535 /**
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800536 * Generate a notification that a collection of Flow Paths has been
537 * installed in the network.
538 *
539 * @param flowPaths the collection of installed Flow Paths.
540 */
541 void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
Pavlin Radoslavov63c2d052013-12-18 18:17:55 -0800542 //
543 // TODO: Add an explicit check for null pointer, because
544 // the IForwardingService is optional. Remove the "if" statement
545 // after hte Forwarding Module becomes mandatory.
546 //
547 if (forwardingService != null)
548 forwardingService.flowsInstalled(flowPaths);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800549 }
550
551 /**
Jonathan Hart0444d932014-01-22 15:06:17 -0800552 * Generate a notification that a FlowPath has been removed from the
553 * network. This means we've received an expiry message for the flow
554 * from the switch, and send flowmods to remove any remaining parts of
555 * the path.
556 *
557 * @param flowPath FlowPath object that was removed from the network.
558 */
559 void notificationFlowPathRemoved(FlowPath flowPath) {
560 if (forwardingService != null) {
561 forwardingService.flowRemoved(flowPath);
562 }
563 }
564
565 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800566 * Push modified Flow-related state as appropriate.
567 *
568 * @param modifiedFlowPaths the collection of modified Flow Paths.
569 * @param modifiedFlowEntries the collection of modified Flow Entries.
570 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800571 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
572 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800573 //
574 // Push the modified Flow state:
575 // - Flow Entries to switches and the datagrid
576 // - Flow Paths to the database
577 //
578 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800579 if (enableOnrc2014MeasurementsFlows) {
580 writeModifiedFlowPathsToDatabase(modifiedFlowPaths);
581 } else {
582 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800583 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
584 }
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800585 }
586
587 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700588 * Push modified Flow Entries to switches.
589 *
590 * NOTE: Only the Flow Entries to switches controlled by this instance
591 * are pushed.
592 *
593 * @param modifiedFlowEntries the collection of modified Flow Entries.
594 */
Pavlin Radoslavov7847db72014-01-10 11:35:21 -0800595 void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800596 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700597 if (modifiedFlowEntries.isEmpty())
598 return;
599
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800600 List<Pair<IOFSwitch, FlowEntry>> entries =
601 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
602
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700603 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700604
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800605 //
606 // Create a collection of my Flow Entries to push
607 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800608 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700609 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
610 if (mySwitch == null)
611 continue;
612
Pavlin Radoslavovd1b728c2013-12-18 21:39:58 -0800613 if (flowEntry.flowEntrySwitchState() ==
614 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
615 //
616 // Don't push again Flow Entries that were already already
617 // installed into the switches.
618 //
619 continue;
620 }
621
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800622 //
623 // Assign Flow Entry IDs if missing.
624 //
625 // NOTE: This is an additional safeguard, in case the
626 // mySwitches set has changed (after the Flow Entry IDs
627 // assignments by the caller).
628 //
629 if (! flowEntry.isValidFlowEntryId()) {
630 long id = getNextFlowEntryId();
631 flowEntry.setFlowEntryId(new FlowEntryId(id));
632 }
633
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800634 log.debug("Pushing Flow Entry To Switch: {}", flowEntry);
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800635 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700636 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800637
638 pusher.pushFlowEntries(entries);
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700639 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700640
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700641 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800642 * Cleanup deleted Flow Entries from the datagrid.
643 *
644 * NOTE: We cleanup only the Flow Entries that are not for our switches.
645 * This is needed to handle the case a switch going down:
646 * It has no Master controller instance, hence no controller instance
647 * will cleanup its flow entries.
648 * This is sub-optimal: we need to elect a controller instance to handle
649 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700650 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800651 * @param modifiedFlowEntries the collection of modified Flow Entries.
652 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800653 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800654 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800655 if (modifiedFlowEntries.isEmpty())
656 return;
657
658 Map<Long, IOFSwitch> mySwitches = getMySwitches();
659
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800660 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800661 //
662 // Process only Flow Entries that should be deleted and have
663 // a valid Flow Entry ID.
664 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800665 if (! flowEntry.isValidFlowEntryId())
666 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800667 if (flowEntry.flowEntryUserState() !=
668 FlowEntryUserState.FE_USER_DELETE) {
669 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700670 }
671
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800672 //
673 // NOTE: The deletion of Flow Entries for my switches is handled
674 // elsewhere.
675 //
676 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
677 if (mySwitch != null)
678 continue;
679
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800680 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800681
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700682 //
683 // Write the Flow Entry to the Datagrid
684 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800685 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700686 }
687 }
688
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800689 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800690 * Class to implement writing to the database in a separate thread.
691 */
692 class FlowDatabaseWriter extends Thread {
693 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800694 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800695
696 /**
697 * Constructor.
698 *
699 * @param flowManager the Flow Manager to use.
700 * @param blockingQueue the blocking queue to use.
701 */
702 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800703 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800704 this.flowManager = flowManager;
705 this.blockingQueue = blockingQueue;
706 }
707
708 /**
709 * Run the thread.
710 */
711 @Override
712 public void run() {
713 //
714 // The main loop
715 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800716 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800717 this.setName("FlowDatabaseWriter " + this.getId() );
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800718 try {
719 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800720 FlowPath flowPath = blockingQueue.take();
721 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800722 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800723 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800724 collection.clear();
725 }
726 } catch (Exception exception) {
727 log.debug("Exception writing to the Database: ", exception);
728 }
729 }
730 }
731
732 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800733 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800734 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800735 * NOTE: The complete Flow Paths are pushed only on the instance
736 * responsible for the first switch. This is to avoid database errors
737 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800738 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800739 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800740 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800741 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800742 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800743 List<FlowPath> copiedFlowPaths = new LinkedList<FlowPath>();
744
745 //
746 // Create a copy of the Flow Paths to push, because the pushing
747 // itself will happen on a separate thread.
748 //
749 Kryo kryo = kryoFactory.newKryo();
750 for (FlowPath flowPath : modifiedFlowPaths) {
751 FlowPath copyFlowPath = kryo.copy(flowPath);
752 copiedFlowPaths.add(copyFlowPath);
753 }
754 kryoFactory.deleteKryo(kryo);
755
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800756 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800757 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800758 // The FlowDatabaseWriter thread is responsible for the actual writing.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800759 //
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800760 flowPathsToDatabaseQueue.addAll(copiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800761 }
762
763 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800764 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800765 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800766 * NOTE: The complete Flow Paths are pushed only on the instance
767 * responsible for the first switch. This is to avoid database errors
768 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800769 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800770 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800771 */
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800772 void writeModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800773 Collection<FlowPath> modifiedFlowPaths) {
774 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800775 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700776
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800777 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700778
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800779 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800780 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800781 // Push the changes only on the instance responsible for the
782 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800783 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800784 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
785 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
786 if (mySrcSwitch == null)
787 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800788
789 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800790 // Delete the Flow Path from the Network Map
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800791 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800792 if (flowPath.flowPathUserState() ==
793 FlowPathUserState.FP_USER_DELETE) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800794 log.debug("Deleting Flow Path From Database: {}", flowPath);
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800795
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800796 boolean retry = false;
797 do {
798 retry = false;
799 try {
800 if (! FlowDatabaseOperation.deleteFlow(
801 dbHandlerInner,
802 flowPath.flowId())) {
803 log.error("Cannot delete Flow Path {} from Network Map",
804 flowPath.flowId());
805 retry = true;
806 }
807 } catch (TitanException te) {
808 log.error("Titan Exception deleting Flow Path from Network MAP: {}", te);
809 retry = true;
810 } catch (Exception e) {
811 log.error("Exception deleting Flow Path from Network MAP: {}", e);
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800812 }
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800813 } while (retry);
814
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800815 continue;
816 }
817
818 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800819 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800820 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800821 boolean allValid = true;
822 for (FlowEntry flowEntry : flowPath.flowEntries()) {
823 if (flowEntry.flowEntryUserState() ==
824 FlowEntryUserState.FE_USER_DELETE) {
825 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700826 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800827 if (! flowEntry.isValidFlowEntryId()) {
828 allValid = false;
829 break;
830 }
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800831 if (! enableOnrc2014MeasurementsFlows) {
832 if (flowEntry.flowEntrySwitchState() !=
833 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
834 allValid = false;
835 break;
836 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800837 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800838 }
839 if (! allValid)
840 continue;
841
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800842 log.debug("Pushing Flow Path To Database: {}", flowPath);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800843
844 //
845 // Write the Flow Path to the Network Map
846 //
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800847 boolean retry = false;
848 do {
849 retry = false;
850 try {
Masayoshi Kobayashi178ead12013-12-19 20:50:19 -0800851 long startTime = System.nanoTime();
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800852 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800853 log.error("Cannot write to Network Map Flow Path {}", flowPath.flowId());
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800854 retry = true;
855 }
Masayoshi Kobayashi178ead12013-12-19 20:50:19 -0800856 // FIXME Flag to turn ON logging
857 //long endTime = System.nanoTime();
858 //log.error("Performance %% Flow path total time {} : {}", endTime - startTime, flowPath.toString());
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800859 } catch (TitanException te) {
860 log.error("Titan Exception writing Flow Path to Network MAP: ", te);
861 retry = true;
Masayoshi Kobayashi178ead12013-12-19 20:50:19 -0800862 // FIXME Flag to turn ON logging
863 //long endTime = System.nanoTime();
864 //log.error("Performance %% Flow path total time {} : {}", endTime - startTime, flowPath.toString());
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800865 } catch (Exception e) {
866 log.error("Exception writing Flow Path to Network MAP: ", e);
Masayoshi Kobayashi178ead12013-12-19 20:50:19 -0800867 // FIXME Flag to turn ON logging
868 //long endTime = System.nanoTime();
869 //log.error("Performance %% Flow path total time {} : {}", endTime - startTime, flowPath.toString());
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800870 }
Pavlin Radoslavov262e6832013-12-18 14:37:35 -0800871 } while (retry);
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800872
873 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavovf4bdf262014-01-09 13:51:40 -0800874 // Send the notifications
Pavlin Radoslavov7847db72014-01-10 11:35:21 -0800875
Pavlin Radoslavovf4bdf262014-01-09 13:51:40 -0800876 for (FlowEntry flowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov8edd4412014-01-10 11:37:32 -0800877 if (flowEntry.flowEntrySwitchState() !=
Pavlin Radoslavovf4bdf262014-01-09 13:51:40 -0800878 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavov8edd4412014-01-10 11:37:32 -0800879 continue;
Pavlin Radoslavovf4bdf262014-01-09 13:51:40 -0800880 }
Pavlin Radoslavov8edd4412014-01-10 11:37:32 -0800881 // datagridService.notificationSendFlowEntryIdAdded(flowEntry.flowEntryId(), flowEntry.dpid());
Pavlin Radoslavov7847db72014-01-10 11:35:21 -0800882
883 //
884 // Write the Flow Entry to the Datagrid
885 //
886 switch (flowEntry.flowEntryUserState()) {
887 case FE_USER_ADD:
888 datagridService.notificationSendFlowEntryAdded(flowEntry);
889 break;
890 case FE_USER_MODIFY:
891 datagridService.notificationSendFlowEntryUpdated(flowEntry);
892 break;
893 case FE_USER_DELETE:
894 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
895 break;
896 case FE_USER_UNKNOWN:
897 assert(false);
898 break;
899 }
Pavlin Radoslavovf4bdf262014-01-09 13:51:40 -0800900 }
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800901 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700902 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800903 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800904}