blob: 25fe60877e96fce2132dab36532e773626add71c [file] [log] [blame]
Jonathan Hart23701d12014-04-03 10:45:48 -07001package net.onrc.onos.core.flowprogrammer;
Brian O'Connora8e49802013-10-30 20:49:59 -07002
3import java.io.IOException;
4import java.util.ArrayList;
Brian O'Connora8e49802013-10-30 20:49:59 -07005import java.util.HashMap;
6import java.util.HashSet;
7import java.util.List;
8import java.util.Map;
9import java.util.Set;
Naoki Shiota2bdda572013-12-09 15:05:21 -080010import java.util.concurrent.Callable;
Brian O'Connora8e49802013-10-30 20:49:59 -070011import java.util.concurrent.ExecutionException;
Brian O'Connora8e49802013-10-30 20:49:59 -070012import java.util.concurrent.Future;
Naoki Shiota2bdda572013-12-09 15:05:21 -080013import java.util.concurrent.FutureTask;
Brian O'Connora8e49802013-10-30 20:49:59 -070014
Jonathan Harta99ec672014-04-03 11:30:34 -070015import net.floodlightcontroller.core.IOFSwitch;
16import net.onrc.onos.core.flowprogrammer.IFlowPusherService.MsgPriority;
17import net.onrc.onos.core.util.Dpid;
18import net.onrc.onos.core.util.FlowEntryId;
19
Brian O'Connor0d6ba512013-11-05 15:17:44 -080020import org.openflow.protocol.OFFlowMod;
Brian O'Connora8e49802013-10-30 20:49:59 -070021import org.openflow.protocol.OFMatch;
Brian O'Connor0d6ba512013-11-05 15:17:44 -080022import org.openflow.protocol.OFPort;
Brian O'Connora8e49802013-10-30 20:49:59 -070023import org.openflow.protocol.OFStatisticsRequest;
24import org.openflow.protocol.statistics.OFFlowStatisticsReply;
25import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
26import org.openflow.protocol.statistics.OFStatistics;
27import org.openflow.protocol.statistics.OFStatisticsType;
28import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
30
Naoki Shiotae3199732013-11-25 16:14:43 -080031/**
Naoki Shiotab485d412013-11-26 12:04:19 -080032 * FlowSynchronizer is an implementation of FlowSyncService.
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -080033 * In addition to IFlowSyncService, FlowSynchronizer periodically reads flow
34 * tables from switches and compare them with GraphDB to drop unnecessary
35 * flows and/or to install missing flows.
Naoki Shiotae3199732013-11-25 16:14:43 -080036 *
Ray Milkey8e5170e2014-04-02 12:09:55 -070037 * @author Brian
Naoki Shiotae3199732013-11-25 16:14:43 -080038 */
Brian O'Connorea1efbe2013-11-25 22:57:43 -080039public class FlowSynchronizer implements IFlowSyncService {
Brian O'Connora8e49802013-10-30 20:49:59 -070040
Brian O'Connorea1efbe2013-11-25 22:57:43 -080041 private static Logger log = LoggerFactory.getLogger(FlowSynchronizer.class);
Brian O'Connore46492e2013-11-14 21:11:50 -080042
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -070043 // TODO: fix when FlowSynchronizer is refactored
Pavlin Radoslavov697f6982014-03-26 15:55:19 -070044 // private DBOperation dbHandler;
Brian O'Connorea1efbe2013-11-25 22:57:43 -080045 protected IFlowPusherService pusher;
Ray Milkey8e5170e2014-04-02 12:09:55 -070046 private Map<IOFSwitch, FutureTask<SyncResult>> switchThreads;
Brian O'Connore46492e2013-11-14 21:11:50 -080047
48 public FlowSynchronizer() {
Ray Milkey8e5170e2014-04-02 12:09:55 -070049 // TODO: fix when FlowSynchronizer is refactored
50 // dbHandler = GraphDBManager.getDBOperation();
51 switchThreads = new HashMap<IOFSwitch, FutureTask<SyncResult>>();
Brian O'Connore46492e2013-11-14 21:11:50 -080052 }
53
Brian O'Connorea1efbe2013-11-25 22:57:43 -080054 @Override
Naoki Shiota2bdda572013-12-09 15:05:21 -080055 public Future<SyncResult> synchronize(IOFSwitch sw) {
Ray Milkey8e5170e2014-04-02 12:09:55 -070056 Synchronizer sync = new Synchronizer(sw);
57 FutureTask<SyncResult> task = new FutureTask<SyncResult>(sync);
58 switchThreads.put(sw, task);
59 task.run();
60 return task;
Brian O'Connore46492e2013-11-14 21:11:50 -080061 }
Ray Milkey8e5170e2014-04-02 12:09:55 -070062
Brian O'Connore46492e2013-11-14 21:11:50 -080063 @Override
Brian O'Connorea1efbe2013-11-25 22:57:43 -080064 public void interrupt(IOFSwitch sw) {
Ray Milkey8e5170e2014-04-02 12:09:55 -070065 FutureTask<SyncResult> t = switchThreads.remove(sw);
66 if (t != null) {
67 t.cancel(true);
68 }
Brian O'Connore46492e2013-11-14 21:11:50 -080069 }
70
Naoki Shiotab485d412013-11-26 12:04:19 -080071 /**
72 * Initialize Synchronizer.
Ray Milkey8e5170e2014-04-02 12:09:55 -070073 *
Naoki Shiotab485d412013-11-26 12:04:19 -080074 * @param pusherService FlowPusherService used for sending messages.
75 */
Brian O'Connorea1efbe2013-11-25 22:57:43 -080076 public void init(IFlowPusherService pusherService) {
Ray Milkey8e5170e2014-04-02 12:09:55 -070077 pusher = pusherService;
Brian O'Connore46492e2013-11-14 21:11:50 -080078 }
79
Naoki Shiotae3199732013-11-25 16:14:43 -080080 /**
81 * Synchronizer represents main thread of synchronization.
Naoki Shiotae3199732013-11-25 16:14:43 -080082 *
Ray Milkey8e5170e2014-04-02 12:09:55 -070083 * @author Brian
Naoki Shiotae3199732013-11-25 16:14:43 -080084 */
Ray Milkey8e5170e2014-04-02 12:09:55 -070085 protected class Synchronizer implements Callable<SyncResult> {
86 IOFSwitch sw;
87 // TODO: fix when FlowSynchronizer is refactored
88 // ISwitchObject swObj;
Brian O'Connore46492e2013-11-14 21:11:50 -080089
Ray Milkey8e5170e2014-04-02 12:09:55 -070090 public Synchronizer(IOFSwitch sw) {
91 this.sw = sw;
92 Dpid dpid = new Dpid(sw.getId());
93 // TODO: fix when FlowSynchronizer is refactored
94 // this.swObj = dbHandler.searchSwitch(dpid.toString());
95 }
Brian O'Connore46492e2013-11-14 21:11:50 -080096
Ray Milkey8e5170e2014-04-02 12:09:55 -070097 double graphIDTime, switchTime, compareTime, graphEntryTime, extractTime, pushTime, totalTime;
Brian O'Connore46492e2013-11-14 21:11:50 -080098
Ray Milkey8e5170e2014-04-02 12:09:55 -070099 @Override
100 public SyncResult call() {
101 pusher.suspend(sw);
102 try {
103 long start = System.nanoTime();
104 Set<FlowEntryWrapper> graphEntries = getFlowEntriesFromGraph();
105 long step1 = System.nanoTime();
106 Set<FlowEntryWrapper> switchEntries = getFlowEntriesFromSwitch();
107 if (switchEntries == null) {
108 log.debug("getFlowEntriesFromSwitch() failed");
109 return null;
110 }
111 long step2 = System.nanoTime();
112 SyncResult result = compare(graphEntries, switchEntries);
113 long step3 = System.nanoTime();
114 graphIDTime = (step1 - start);
115 switchTime = (step2 - step1);
116 compareTime = (step3 - step2);
117 totalTime = (step3 - start);
118 outputTime();
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800119
Ray Milkey8e5170e2014-04-02 12:09:55 -0700120 return result;
121 } finally {
122 pusher.resume(sw);
123 }
124 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800125
Ray Milkey8e5170e2014-04-02 12:09:55 -0700126 private void outputTime() {
127 double div = Math.pow(10, 6); //convert nanoseconds to ms
128 graphIDTime /= div;
129 switchTime /= div;
130 compareTime = (compareTime - graphEntryTime - extractTime - pushTime) / div;
131 graphEntryTime /= div;
132 extractTime /= div;
133 pushTime /= div;
134 totalTime /= div;
135 log.debug("Sync time (ms):{},{},{},{},{},{},{}"
136 , graphIDTime
137 , switchTime
138 , compareTime
139 , graphEntryTime
140 , extractTime
141 , pushTime
142 , totalTime);
143 }
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700144
Ray Milkey8e5170e2014-04-02 12:09:55 -0700145 /**
146 * Compare flows entries in GraphDB and switch to pick up necessary
147 * messages.
148 * After picking up, picked messages are added to FlowPusher.
149 *
150 * @param graphEntries Flow entries in GraphDB.
151 * @param switchEntries Flow entries in switch.
152 */
153 private SyncResult compare(Set<FlowEntryWrapper> graphEntries, Set<FlowEntryWrapper> switchEntries) {
154 int added = 0, removed = 0, skipped = 0;
155 for (FlowEntryWrapper entry : switchEntries) {
156 if (graphEntries.contains(entry)) {
157 graphEntries.remove(entry);
158 skipped++;
159 } else {
160 // remove flow entry from the switch
161 entry.removeFromSwitch(sw);
162 removed++;
163 }
164 }
165 for (FlowEntryWrapper entry : graphEntries) {
166 // add flow entry to switch
167 entry.addToSwitch(sw);
168 graphEntryTime += entry.dbTime;
169 extractTime += entry.extractTime;
170 pushTime += entry.pushTime;
171 added++;
172 }
173 log.debug("Flow entries added {}, " +
174 "Flow entries removed {}, " +
175 "Flow entries skipped {}"
176 , added
177 , removed
178 , skipped);
Brian O'Connore46492e2013-11-14 21:11:50 -0800179
Ray Milkey8e5170e2014-04-02 12:09:55 -0700180 return new SyncResult(added, removed, skipped);
181 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700182
Ray Milkey8e5170e2014-04-02 12:09:55 -0700183 /**
184 * Read GraphDB to get FlowEntries associated with a switch.
185 *
186 * @return set of FlowEntries
187 */
188 private Set<FlowEntryWrapper> getFlowEntriesFromGraph() {
189 Set<FlowEntryWrapper> entries = new HashSet<FlowEntryWrapper>();
Brian O'Connora8e49802013-10-30 20:49:59 -0700190
Ray Milkey8e5170e2014-04-02 12:09:55 -0700191 // TODO: fix when FlowSynchronizer is refactored
192 /*
193 for(IFlowEntry entry : swObj.getFlowEntries()) {
194 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
195 entries.add(fe);
196 }
197 */
198 return entries;
199 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700200
Ray Milkey8e5170e2014-04-02 12:09:55 -0700201 /**
202 * Read flow table from switch and derive FlowEntries from table.
203 *
204 * @return set of FlowEntries
205 */
206 private Set<FlowEntryWrapper> getFlowEntriesFromSwitch() {
Brian O'Connora8e49802013-10-30 20:49:59 -0700207
Ray Milkey8e5170e2014-04-02 12:09:55 -0700208 int lengthU = 0;
209 OFMatch match = new OFMatch();
210 match.setWildcards(OFMatch.OFPFW_ALL);
Brian O'Connore46492e2013-11-14 21:11:50 -0800211
Ray Milkey8e5170e2014-04-02 12:09:55 -0700212 OFFlowStatisticsRequest stat = new OFFlowStatisticsRequest();
213 stat.setOutPort((short) 0xffff); //TODO: OFPort.OFPP_NONE
214 stat.setTableId((byte) 0xff); // TODO: fix this with enum (ALL TABLES)
215 stat.setMatch(match);
216 List<OFStatistics> stats = new ArrayList<OFStatistics>();
217 stats.add(stat);
218 lengthU += stat.getLength();
219
220 OFStatisticsRequest req = new OFStatisticsRequest();
221 req.setStatisticType(OFStatisticsType.FLOW);
222 req.setStatistics(stats);
223 lengthU += req.getLengthU();
224 req.setLengthU(lengthU);
225
226 List<OFStatistics> entries = null;
227 try {
228 Future<List<OFStatistics>> dfuture = sw.getStatistics(req);
229 entries = dfuture.get();
230 } catch (IOException e) {
231 // TODO Auto-generated catch block
232 e.printStackTrace();
233 return null;
234 } catch (InterruptedException e) {
235 // TODO Auto-generated catch block
236 e.printStackTrace();
237 return null;
238 } catch (ExecutionException e) {
239 // TODO Auto-generated catch block
240 e.printStackTrace();
241 return null;
242 }
243
244 Set<FlowEntryWrapper> results = new HashSet<FlowEntryWrapper>();
245 for (OFStatistics result : entries) {
246 OFFlowStatisticsReply entry = (OFFlowStatisticsReply) result;
247 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
248 results.add(fe);
249 }
250 return results;
251 }
Brian O'Connor8c166a72013-11-14 18:41:48 -0800252
Brian O'Connora8e49802013-10-30 20:49:59 -0700253 }
254
Naoki Shiotae3199732013-11-25 16:14:43 -0800255 /**
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800256 * FlowEntryWrapper represents abstract FlowEntry which is embodied
257 * by FlowEntryId (from GraphDB) or OFFlowStatisticsReply (from switch).
Naoki Shiotae3199732013-11-25 16:14:43 -0800258 *
Ray Milkey8e5170e2014-04-02 12:09:55 -0700259 * @author Brian
Naoki Shiotae3199732013-11-25 16:14:43 -0800260 */
Brian O'Connore46492e2013-11-14 21:11:50 -0800261 class FlowEntryWrapper {
Ray Milkey8e5170e2014-04-02 12:09:55 -0700262 FlowEntryId flowEntryId;
263 // TODO: fix when FlowSynchronizer is refactored
264 // IFlowEntry iFlowEntry;
265 OFFlowStatisticsReply statisticsReply;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800266
Brian O'Connore46492e2013-11-14 21:11:50 -0800267
Ray Milkey8e5170e2014-04-02 12:09:55 -0700268 // TODO: fix when FlowSynchronizer is refactored
269 /*
270 public FlowEntryWrapper(IFlowEntry entry) {
271 flowEntryId = new FlowEntryId(entry.getFlowEntryId());
272 iFlowEntry = entry;
273 }
274 */
Brian O'Connora8e49802013-10-30 20:49:59 -0700275
Ray Milkey8e5170e2014-04-02 12:09:55 -0700276 public FlowEntryWrapper(OFFlowStatisticsReply entry) {
277 flowEntryId = new FlowEntryId(entry.getCookie());
278 statisticsReply = entry;
279 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700280
Ray Milkey8e5170e2014-04-02 12:09:55 -0700281 /**
282 * Install this FlowEntry to a switch via FlowPusher.
283 *
284 * @param sw Switch to which flow will be installed.
285 */
286 double dbTime, extractTime, pushTime;
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800287
Ray Milkey8e5170e2014-04-02 12:09:55 -0700288 public void addToSwitch(IOFSwitch sw) {
289 if (statisticsReply != null) {
290 log.error("Error adding existing flow entry {} to sw {}",
291 statisticsReply.getCookie(), sw.getId());
292 return;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800293 }
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800294
Ray Milkey8e5170e2014-04-02 12:09:55 -0700295 double startDB = System.nanoTime();
296 // Get the Flow Entry state from the Network Graph
297 // TODO: fix when FlowSynchronizer is refactored
298 /*
299 if (iFlowEntry == null) {
300 try {
301 // TODO: fix when FlowSynchronizer is refactored
302 iFlowEntry = dbHandler.searchFlowEntry(flowEntryId);
303 } catch (Exception e) {
304 log.error("Error finding flow entry {} in Network Graph",
305 flowEntryId);
306 return;
307 }
308 }
309 */
310 dbTime = System.nanoTime() - startDB;
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800311
Ray Milkey8e5170e2014-04-02 12:09:55 -0700312 //
313 // TODO: The old FlowDatabaseOperation class is gone, so the code
314 //
315 /*
316 double startExtract = System.nanoTime();
317 FlowEntry flowEntry =
318 FlowDatabaseOperation.extractFlowEntry(iFlowEntry);
319 if (flowEntry == null) {
320 log.error("Cannot add flow entry {} to sw {} : flow entry cannot be extracted",
321 flowEntryId, sw.getId());
322 return;
323 }
324 extractTime = System.nanoTime() - startExtract;
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800325
Ray Milkey8e5170e2014-04-02 12:09:55 -0700326 double startPush = System.nanoTime();
327 pusher.pushFlowEntry(sw, flowEntry, MsgPriority.HIGH);
328 pushTime = System.nanoTime() - startPush;
329 */
330 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700331
Ray Milkey8e5170e2014-04-02 12:09:55 -0700332 /**
333 * Remove this FlowEntry from a switch via FlowPusher.
334 *
335 * @param sw Switch from which flow will be removed.
336 */
337 public void removeFromSwitch(IOFSwitch sw) {
338 if (statisticsReply == null) {
339 log.error("Error removing non-existent flow entry {} from sw {}",
340 flowEntryId, sw.getId());
341 return;
342 }
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800343
Ray Milkey8e5170e2014-04-02 12:09:55 -0700344 // Convert Statistics Reply to Flow Mod, then write it
345 OFFlowMod fm = new OFFlowMod();
346 fm.setCookie(statisticsReply.getCookie());
347 fm.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
348 fm.setLengthU(OFFlowMod.MINIMUM_LENGTH);
349 fm.setMatch(statisticsReply.getMatch());
350 fm.setPriority(statisticsReply.getPriority());
351 fm.setOutPort(OFPort.OFPP_NONE);
Brian O'Connora8e49802013-10-30 20:49:59 -0700352
Ray Milkey8e5170e2014-04-02 12:09:55 -0700353 pusher.add(sw, fm, MsgPriority.HIGH);
354 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700355
Ray Milkey8e5170e2014-04-02 12:09:55 -0700356 /**
357 * Return the hash code of the Flow Entry ID
358 */
359 @Override
360 public int hashCode() {
361 return flowEntryId.hashCode();
362 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800363
Ray Milkey8e5170e2014-04-02 12:09:55 -0700364 /**
365 * Returns true of the object is another Flow Entry ID with
366 * the same value; otherwise, returns false.
367 *
368 * @param Object to compare
369 * @return true if the object has the same Flow Entry ID.
370 */
371 @Override
372 public boolean equals(Object obj) {
373 if (obj != null && obj.getClass() == this.getClass()) {
374 FlowEntryWrapper entry = (FlowEntryWrapper) obj;
375 // TODO: we need to actually compare the match + actions
376 return this.flowEntryId.equals(entry.flowEntryId);
377 }
378 return false;
379 }
380
381 @Override
382 public String toString() {
383 return flowEntryId.toString();
384 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800385 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800386}