blob: 072e34fa2ece7c118393d9bdd5c331abd44927f3 [file] [log] [blame]
HIGUCHI Yuta60a10142013-06-14 15:50:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00006import java.util.LinkedList;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -08007import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08008import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +00009import java.util.Random;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080010import java.util.SortedMap;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080011import java.util.concurrent.BlockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080012import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080013
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080016import net.floodlightcontroller.core.module.FloodlightModuleContext;
17import net.floodlightcontroller.core.module.FloodlightModuleException;
18import net.floodlightcontroller.core.module.IFloodlightModule;
19import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.util.OFMessageDamper;
yoshi2fd4c7e2013-11-22 15:47:55 -080022import net.onrc.onos.graph.DBOperation;
23import net.onrc.onos.graph.GraphDBManager;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070024import net.onrc.onos.datagrid.IDatagridService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070025import net.onrc.onos.ofcontroller.core.INetMapStorage;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070026import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
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;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070030import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov63e42602013-12-12 12:54:05 -080031import net.onrc.onos.ofcontroller.util.Dpid;
32import net.onrc.onos.ofcontroller.util.FlowEntry;
33import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
34import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
35import net.onrc.onos.ofcontroller.util.FlowEntryId;
36import net.onrc.onos.ofcontroller.util.FlowId;
37import net.onrc.onos.ofcontroller.util.FlowPath;
38import net.onrc.onos.ofcontroller.util.FlowPathUserState;
39import net.onrc.onos.ofcontroller.util.Pair;
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080040import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080042import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080044import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
admin944ef4f2013-10-08 17:48:37 -070047/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070048 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070049 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070050public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Naoki Shiota1a37ca12013-11-18 10:55:23 -080051 // flag to use FlowPusher instead of FlowSwitchOperation/MessageDamper
52 private final static boolean enableFlowPusher = false;
yoshitomob292c622013-11-23 14:35:58 -080053 protected DBOperation dbHandlerApi;
54 protected DBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080055
Jonathan Hart50a94982013-04-10 14:49:51 -070056 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070057 protected volatile IDatagridService datagridService;
58 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070059 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070060 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080061
Brian O'Connor8c166a72013-11-14 18:41:48 -080062 protected IFlowPusherService pusher;
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080063 protected IForwardingService forwardingService;
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080064
65 private KryoFactory kryoFactory = new KryoFactory();
66
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000067 // Flow Entry ID generation state
68 private static Random randomGenerator = new Random();
69 private static int nextFlowEntryIdPrefix = 0;
70 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070071
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080072 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070073 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080074
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080075 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080076 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
77 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080078 FlowDatabaseWriter flowDatabaseWriter;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080079
admin944ef4f2013-10-08 17:48:37 -070080 /**
81 * Initialize the Flow Manager.
82 *
83 * @param conf the Graph Database configuration string.
84 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080085 @Override
yoshi2fd4c7e2013-11-22 15:47:55 -080086 public void init(final String dbStore, final String conf) {
yoshid38cd312013-12-02 19:54:44 -080087 dbHandlerApi = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
88 dbHandlerInner = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
89
90 //dbHandlerApi = GraphDBManager.getDBOperation(dbStore, conf);
91 //dbHandlerInner = GraphDBManager.getDBOperation(dbStore, conf);
yoshitomob292c622013-11-23 14:35:58 -080092
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080093 }
94
admin944ef4f2013-10-08 17:48:37 -070095 /**
96 * Shutdown the Flow Manager operation.
97 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080098 public 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 Radoslavov9a859022013-10-30 10:08:24 -0700107 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800108 dbHandlerApi.close();
109 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800110 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800111
admin944ef4f2013-10-08 17:48:37 -0700112 /**
113 * Get the collection of offered module services.
114 *
115 * @return the collection of offered module services.
116 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800117 @Override
118 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
119 Collection<Class<? extends IFloodlightService>> l =
120 new ArrayList<Class<? extends IFloodlightService>>();
121 l.add(IFlowService.class);
122 return l;
123 }
124
admin944ef4f2013-10-08 17:48:37 -0700125 /**
126 * Get the collection of implemented services.
127 *
128 * @return the collection of implemented services.
129 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800130 @Override
131 public Map<Class<? extends IFloodlightService>, IFloodlightService>
132 getServiceImpls() {
133 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700134 IFloodlightService> m =
135 new HashMap<Class<? extends IFloodlightService>,
136 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800137 m.put(IFlowService.class, this);
138 return m;
139 }
140
admin944ef4f2013-10-08 17:48:37 -0700141 /**
142 * Get the collection of modules this module depends on.
143 *
144 * @return the collection of modules this module depends on.
145 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800146 @Override
147 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700148 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800149 Collection<Class<? extends IFloodlightService>> l =
150 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800151 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700152 l.add(INetworkGraphService.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);
156 l.add(IForwardingService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800157 return l;
158 }
159
admin944ef4f2013-10-08 17:48:37 -0700160 /**
161 * Initialize the module.
162 *
163 * @param context the module context to use for the initialization.
164 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800165 @Override
166 public void init(FloodlightModuleContext context)
167 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700168 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800169 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700170 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800171 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800172 pusher = context.getServiceImpl(IFlowPusherService.class);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800173 forwardingService = context.getServiceImpl(IForwardingService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800174
yoshi0fee3de2013-11-23 09:13:37 -0800175 this.init("","");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800176 }
177
admin944ef4f2013-10-08 17:48:37 -0700178 /**
179 * Get the next Flow Entry ID to use.
180 *
181 * @return the next Flow Entry ID to use.
182 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800183 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700184 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000185 //
186 // Generate the next Flow Entry ID.
187 // NOTE: For now, the higher 32 bits are random, and
188 // the lower 32 bits are sequential.
189 // In the future, we need a better allocation mechanism.
190 //
191 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
192 nextFlowEntryIdPrefix = randomGenerator.nextInt();
193 nextFlowEntryIdSuffix = 0;
194 } else {
195 nextFlowEntryIdSuffix++;
196 }
197 long result = (long)nextFlowEntryIdPrefix << 32;
198 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
199 return result;
200 }
201
admin944ef4f2013-10-08 17:48:37 -0700202 /**
203 * Startup module operation.
204 *
205 * @param context the module context to use for the startup.
206 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800207 @Override
208 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700209 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700210
admin944ef4f2013-10-08 17:48:37 -0700211 // Initialize the Flow Entry ID generator
212 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800213
214 //
215 // The thread to write to the database
216 //
217 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800218 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800219 flowDatabaseWriter.start();
220
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700221 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800222 // The Flow Event Handler thread:
223 // - create
224 // - register with the Datagrid Service
225 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700226 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700227 flowEventHandler = new FlowEventHandler(this, datagridService);
228 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700229 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800230 }
231
232 /**
233 * Add a flow.
234 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800235 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800236 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800237 */
238 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800239 public FlowId addFlow(FlowPath flowPath) {
240
241 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800242 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800243 long id = getNextFlowEntryId();
244 flowPath.setFlowId(new FlowId(id));
245 }
246
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700247 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700248 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700249 // in case the application didn't do it.
250 //
251 for (FlowEntry flowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800252 // The Flow Entry switch state
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700253 if (flowEntry.flowEntrySwitchState() ==
254 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
255 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800256 }
Pavlin Radoslavov07d22b42013-12-15 16:33:33 -0800257 // The Flow Entry ID
258 if (! flowEntry.isValidFlowEntryId()) {
259 long id = getNextFlowEntryId();
260 flowEntry.setFlowEntryId(new FlowEntryId(id));
261 }
262 // The Flow ID
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700263 if (! flowEntry.isValidFlowId())
264 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700265 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800266
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800267 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700268 datagridService.notificationSendFlowAdded(flowPath);
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800269 return flowPath.flowId();
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700270 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800271 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700272 }
273
274 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000275 * Delete all previously added flows.
276 *
277 * @return true on success, otherwise false.
278 */
279 @Override
280 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800281 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700282 datagridService.notificationSendAllFlowsRemoved();
283 return true;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000284 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700285 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000286 }
287
288 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800289 * Delete a previously added flow.
290 *
291 * @param flowId the Flow ID of the flow to delete.
292 * @return true on success, otherwise false.
293 */
294 @Override
295 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800296 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700297 datagridService.notificationSendFlowRemoved(flowId);
298 return true;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700299 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700300 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700301 }
302
303 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800304 * Get a previously added flow.
305 *
306 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800307 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800308 */
309 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800310 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800311 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700312 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800313
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700314 /**
315 * Get all installed flows by all installers.
316 *
317 * @return the Flow Paths if found, otherwise null.
318 */
319 @Override
320 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800321 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800322 }
323
324 /**
admin944ef4f2013-10-08 17:48:37 -0700325 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700326 *
admin944ef4f2013-10-08 17:48:37 -0700327 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700328 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700329 * @return the Flow Paths if found, otherwise null.
330 */
331 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800332 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
333 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800334 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
335 SortedMap<Long, FlowPath> sortedFlowPaths =
336 flowEventHandler.getAllFlowPathsCopy();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700337
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800338 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800339 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800340 //
341 for (FlowPath flowPath : sortedFlowPaths.values()) {
342 //
343 // TODO: Add only the Flow Paths that have been successfully
344 // installed.
345 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800346 flowPath.setFlowEntryMatch(null);
347 flowPath.setFlowEntryActions(null);
348 for (FlowEntry flowEntry : flowPath.flowEntries()) {
349 flowEntry.setFlowEntryMatch(null);
350 flowEntry.setFlowEntryActions(null);
351 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800352 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800353 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700354
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800355 return flowPaths;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700356 }
357
358 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800359 * Get the collection of my switches.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700360 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800361 * @return the collection of my switches.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700362 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800363 public Map<Long, IOFSwitch> getMySwitches() {
364 return floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700365 }
366
367 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800368 * Get the network topology.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700369 *
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800370 * @return the network topology.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700371 */
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800372 public Topology getTopology() {
373 return flowEventHandler.getTopology();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700374 }
375
376 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800377 * Inform the Flow Manager that a Flow Entry on switch expired.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700378 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800379 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800380 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700381 */
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800382 public void flowEntryOnSwitchExpired(IOFSwitch sw,
383 FlowEntryId flowEntryId) {
384 // Find the Flow Entry
385 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
yoshia97632b2013-12-17 15:46:08 -0800386 if (flowEntry == null)
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800387 return; // Flow Entry not found
388
389 // Find the Flow Path
390 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
391 if (flowPath == null)
392 return; // Flow Path not found
393
394 //
395 // Remove the Flow if the Flow Entry expired on the first switch
396 //
397 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
398 if (srcDpid.value() != sw.getId())
399 return;
400 deleteFlow(flowPath.flowId());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700401 }
402
403 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800404 * Inform the Flow Manager that a collection of Flow Entries have been
405 * pushed to a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700406 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800407 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
408 * that have been pushed.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700409 */
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800410 public void flowEntriesPushedToSwitch(
411 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700412
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800413 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800414 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800415 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800416 // TODO: For now we have to create an explicit FlowEntry copy so
417 // we don't modify the original FlowEntry.
418 // This should go away after we start using the OpenFlow Barrier
419 // mechnanism in the FlowPusher.
420 //
421 Kryo kryo = kryoFactory.newKryo();
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800422 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800423 FlowEntry flowEntry = entry.second;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800424
425 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800426 // Mark the Flow Entry that it has been pushed to the switch
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800427 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800428 FlowEntry copyFlowEntry = kryo.copy(flowEntry);
429 copyFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700430
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800431 //
432 // Write the Flow Entry to the Datagrid
433 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800434 switch (copyFlowEntry.flowEntryUserState()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800435 case FE_USER_ADD:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800436 datagridService.notificationSendFlowEntryAdded(copyFlowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800437 break;
438 case FE_USER_MODIFY:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800439 datagridService.notificationSendFlowEntryUpdated(copyFlowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800440 break;
441 case FE_USER_DELETE:
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800442 datagridService.notificationSendFlowEntryRemoved(copyFlowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800443 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800444 case FE_USER_UNKNOWN:
445 assert(false);
446 break;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800447 }
448 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800449 kryoFactory.deleteKryo(kryo);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800450 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700451
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800452 /**
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800453 * Generate a notification that a collection of Flow Paths has been
454 * installed in the network.
455 *
456 * @param flowPaths the collection of installed Flow Paths.
457 */
458 void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
459 forwardingService.flowsInstalled(flowPaths);
460 }
461
462 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800463 * Push modified Flow-related state as appropriate.
464 *
465 * @param modifiedFlowPaths the collection of modified Flow Paths.
466 * @param modifiedFlowEntries the collection of modified Flow Entries.
467 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800468 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
469 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800470 //
471 // Push the modified Flow state:
472 // - Flow Entries to switches and the datagrid
473 // - Flow Paths to the database
474 //
475 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800476 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800477 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800478 }
479
480 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700481 * Push modified Flow Entries to switches.
482 *
483 * NOTE: Only the Flow Entries to switches controlled by this instance
484 * are pushed.
485 *
486 * @param modifiedFlowEntries the collection of modified Flow Entries.
487 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800488 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800489 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700490 if (modifiedFlowEntries.isEmpty())
491 return;
492
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800493 List<Pair<IOFSwitch, FlowEntry>> entries =
494 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
495
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700496 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700497
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800498 //
499 // Create a collection of my Flow Entries to push
500 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800501 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700502 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
503 if (mySwitch == null)
504 continue;
505
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800506 //
507 // Assign Flow Entry IDs if missing.
508 //
509 // NOTE: This is an additional safeguard, in case the
510 // mySwitches set has changed (after the Flow Entry IDs
511 // assignments by the caller).
512 //
513 if (! flowEntry.isValidFlowEntryId()) {
514 long id = getNextFlowEntryId();
515 flowEntry.setFlowEntryId(new FlowEntryId(id));
516 }
517
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700518 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800519 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700520 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800521
522 pusher.pushFlowEntries(entries);
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700523 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700524
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700525 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800526 * Cleanup deleted Flow Entries from the datagrid.
527 *
528 * NOTE: We cleanup only the Flow Entries that are not for our switches.
529 * This is needed to handle the case a switch going down:
530 * It has no Master controller instance, hence no controller instance
531 * will cleanup its flow entries.
532 * This is sub-optimal: we need to elect a controller instance to handle
533 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700534 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800535 * @param modifiedFlowEntries the collection of modified Flow Entries.
536 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800537 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800538 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800539 if (modifiedFlowEntries.isEmpty())
540 return;
541
542 Map<Long, IOFSwitch> mySwitches = getMySwitches();
543
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800544 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800545 //
546 // Process only Flow Entries that should be deleted and have
547 // a valid Flow Entry ID.
548 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800549 if (! flowEntry.isValidFlowEntryId())
550 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800551 if (flowEntry.flowEntryUserState() !=
552 FlowEntryUserState.FE_USER_DELETE) {
553 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700554 }
555
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800556 //
557 // NOTE: The deletion of Flow Entries for my switches is handled
558 // elsewhere.
559 //
560 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
561 if (mySwitch != null)
562 continue;
563
564 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
565
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700566 //
567 // Write the Flow Entry to the Datagrid
568 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800569 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700570 }
571 }
572
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800573 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800574 * Class to implement writing to the database in a separate thread.
575 */
576 class FlowDatabaseWriter extends Thread {
577 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800578 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800579
580 /**
581 * Constructor.
582 *
583 * @param flowManager the Flow Manager to use.
584 * @param blockingQueue the blocking queue to use.
585 */
586 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800587 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800588 this.flowManager = flowManager;
589 this.blockingQueue = blockingQueue;
590 }
591
592 /**
593 * Run the thread.
594 */
595 @Override
596 public void run() {
597 //
598 // The main loop
599 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800600 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800601 try {
602 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800603 FlowPath flowPath = blockingQueue.take();
604 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800605 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800606 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800607 collection.clear();
608 }
609 } catch (Exception exception) {
610 log.debug("Exception writing to the Database: ", exception);
611 }
612 }
613 }
614
615 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800616 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800617 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800618 * NOTE: The complete Flow Paths are pushed only on the instance
619 * responsible for the first switch. This is to avoid database errors
620 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800621 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800622 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800623 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800624 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800625 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800626 List<FlowPath> copiedFlowPaths = new LinkedList<FlowPath>();
627
628 //
629 // Create a copy of the Flow Paths to push, because the pushing
630 // itself will happen on a separate thread.
631 //
632 Kryo kryo = kryoFactory.newKryo();
633 for (FlowPath flowPath : modifiedFlowPaths) {
634 FlowPath copyFlowPath = kryo.copy(flowPath);
635 copiedFlowPaths.add(copyFlowPath);
636 }
637 kryoFactory.deleteKryo(kryo);
638
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800639 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800640 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800641 // The FlowDatabaseWriter thread is responsible for the actual writing.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800642 //
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800643 flowPathsToDatabaseQueue.addAll(copiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800644 }
645
646 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800647 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800648 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800649 * NOTE: The complete Flow Paths are pushed only on the instance
650 * responsible for the first switch. This is to avoid database errors
651 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800652 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800653 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800654 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800655 private void writeModifiedFlowPathsToDatabase(
656 Collection<FlowPath> modifiedFlowPaths) {
657 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800658 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700659
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800660 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700661
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800662 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800663 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800664 // Push the changes only on the instance responsible for the
665 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800666 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800667 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
668 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
669 if (mySrcSwitch == null)
670 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800671
672 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800673 // Delete the Flow Path from the Network Map
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800674 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800675 if (flowPath.flowPathUserState() ==
676 FlowPathUserState.FP_USER_DELETE) {
677 log.debug("Deleting Flow Path From Database: {}",
678 flowPath.toString());
679
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700680 try {
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800681 if (! FlowDatabaseOperation.deleteFlow(
682 dbHandlerInner,
683 flowPath.flowId())) {
684 log.error("Cannot delete Flow Path {} from Network Map",
685 flowPath.flowId());
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700686 }
687 } catch (Exception e) {
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800688 log.error("Exception deleting Flow Path from Network MAP: {}", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700689 }
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800690 continue;
691 }
692
693 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800694 // Test whether all Flow Entries are valid
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700695 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800696 boolean allValid = true;
697 for (FlowEntry flowEntry : flowPath.flowEntries()) {
698 if (flowEntry.flowEntryUserState() ==
699 FlowEntryUserState.FE_USER_DELETE) {
700 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700701 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800702 if (! flowEntry.isValidFlowEntryId()) {
703 allValid = false;
704 break;
705 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800706 if (flowEntry.flowEntrySwitchState() !=
707 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
708 allValid = false;
709 break;
710 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800711 }
712 if (! allValid)
713 continue;
714
715 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
716
717 //
718 // Write the Flow Path to the Network Map
719 //
720 try {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800721 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800722 String logMsg = "Cannot write to Network Map Flow Path " +
723 flowPath.flowId();
724 log.error(logMsg);
725 }
726 } catch (Exception e) {
727 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700728 }
729 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800730 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800731}