blob: acfb6647f341420ccc689f67a6d2d4ed69308490 [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
Brian O'Connora8e49802013-10-30 20:49:59 -07003import java.util.HashMap;
4import java.util.HashSet;
Brian O'Connora8e49802013-10-30 20:49:59 -07005import java.util.Map;
6import java.util.Set;
Naoki Shiota2bdda572013-12-09 15:05:21 -08007import java.util.concurrent.Callable;
Brian O'Connora8e49802013-10-30 20:49:59 -07008import java.util.concurrent.Future;
Naoki Shiota2bdda572013-12-09 15:05:21 -08009import java.util.concurrent.FutureTask;
Brian O'Connora8e49802013-10-30 20:49:59 -070010
Jonathan Harta99ec672014-04-03 11:30:34 -070011import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart5302b6c2014-08-13 15:57:59 -070012import net.onrc.onos.core.util.Dpid;
Jonathan Harta99ec672014-04-03 11:30:34 -070013
Brian O'Connora8e49802013-10-30 20:49:59 -070014import org.slf4j.Logger;
15import org.slf4j.LoggerFactory;
16
Naoki Shiotae3199732013-11-25 16:14:43 -080017/**
Naoki Shiotab485d412013-11-26 12:04:19 -080018 * FlowSynchronizer is an implementation of FlowSyncService.
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -080019 * In addition to IFlowSyncService, FlowSynchronizer periodically reads flow
20 * tables from switches and compare them with GraphDB to drop unnecessary
21 * flows and/or to install missing flows.
Naoki Shiotae3199732013-11-25 16:14:43 -080022 */
Brian O'Connorea1efbe2013-11-25 22:57:43 -080023public class FlowSynchronizer implements IFlowSyncService {
Brian O'Connora8e49802013-10-30 20:49:59 -070024
Brian O'Connorea1efbe2013-11-25 22:57:43 -080025 private static Logger log = LoggerFactory.getLogger(FlowSynchronizer.class);
Brian O'Connore46492e2013-11-14 21:11:50 -080026
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -070027 // TODO: fix when FlowSynchronizer is refactored
Pavlin Radoslavov697f6982014-03-26 15:55:19 -070028 // private DBOperation dbHandler;
Brian O'Connorea1efbe2013-11-25 22:57:43 -080029 protected IFlowPusherService pusher;
Ray Milkey8e5170e2014-04-02 12:09:55 -070030 private Map<IOFSwitch, FutureTask<SyncResult>> switchThreads;
Brian O'Connore46492e2013-11-14 21:11:50 -080031
32 public FlowSynchronizer() {
Ray Milkey8e5170e2014-04-02 12:09:55 -070033 // TODO: fix when FlowSynchronizer is refactored
34 // dbHandler = GraphDBManager.getDBOperation();
35 switchThreads = new HashMap<IOFSwitch, FutureTask<SyncResult>>();
Brian O'Connore46492e2013-11-14 21:11:50 -080036 }
37
Brian O'Connorea1efbe2013-11-25 22:57:43 -080038 @Override
Naoki Shiota2bdda572013-12-09 15:05:21 -080039 public Future<SyncResult> synchronize(IOFSwitch sw) {
Ray Milkey8e5170e2014-04-02 12:09:55 -070040 Synchronizer sync = new Synchronizer(sw);
41 FutureTask<SyncResult> task = new FutureTask<SyncResult>(sync);
42 switchThreads.put(sw, task);
43 task.run();
44 return task;
Brian O'Connore46492e2013-11-14 21:11:50 -080045 }
Ray Milkey8e5170e2014-04-02 12:09:55 -070046
Brian O'Connore46492e2013-11-14 21:11:50 -080047 @Override
Brian O'Connorea1efbe2013-11-25 22:57:43 -080048 public void interrupt(IOFSwitch sw) {
Ray Milkey8e5170e2014-04-02 12:09:55 -070049 FutureTask<SyncResult> t = switchThreads.remove(sw);
50 if (t != null) {
51 t.cancel(true);
52 }
Brian O'Connore46492e2013-11-14 21:11:50 -080053 }
54
Naoki Shiotab485d412013-11-26 12:04:19 -080055 /**
56 * Initialize Synchronizer.
Ray Milkey8e5170e2014-04-02 12:09:55 -070057 *
Naoki Shiotab485d412013-11-26 12:04:19 -080058 * @param pusherService FlowPusherService used for sending messages.
59 */
Brian O'Connorea1efbe2013-11-25 22:57:43 -080060 public void init(IFlowPusherService pusherService) {
Ray Milkey8e5170e2014-04-02 12:09:55 -070061 pusher = pusherService;
Brian O'Connore46492e2013-11-14 21:11:50 -080062 }
63
Naoki Shiotae3199732013-11-25 16:14:43 -080064 /**
65 * Synchronizer represents main thread of synchronization.
Naoki Shiotae3199732013-11-25 16:14:43 -080066 */
Ray Milkey8e5170e2014-04-02 12:09:55 -070067 protected class Synchronizer implements Callable<SyncResult> {
68 IOFSwitch sw;
69 // TODO: fix when FlowSynchronizer is refactored
70 // ISwitchObject swObj;
Brian O'Connore46492e2013-11-14 21:11:50 -080071
Ray Milkey8e5170e2014-04-02 12:09:55 -070072 public Synchronizer(IOFSwitch sw) {
73 this.sw = sw;
Ray Milkey8e5170e2014-04-02 12:09:55 -070074 // TODO: fix when FlowSynchronizer is refactored
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -070075 // Dpid dpid = new Dpid(sw.getId());
Ray Milkey8e5170e2014-04-02 12:09:55 -070076 // this.swObj = dbHandler.searchSwitch(dpid.toString());
77 }
Brian O'Connore46492e2013-11-14 21:11:50 -080078
Ray Milkey8e5170e2014-04-02 12:09:55 -070079 double graphIDTime, switchTime, compareTime, graphEntryTime, extractTime, pushTime, totalTime;
Brian O'Connore46492e2013-11-14 21:11:50 -080080
Ray Milkey8e5170e2014-04-02 12:09:55 -070081 @Override
82 public SyncResult call() {
Jonathan Hart5302b6c2014-08-13 15:57:59 -070083 pusher.suspend(new Dpid(sw.getId()));
Ray Milkey8e5170e2014-04-02 12:09:55 -070084 try {
85 long start = System.nanoTime();
86 Set<FlowEntryWrapper> graphEntries = getFlowEntriesFromGraph();
87 long step1 = System.nanoTime();
88 Set<FlowEntryWrapper> switchEntries = getFlowEntriesFromSwitch();
Ray Milkey8e5170e2014-04-02 12:09:55 -070089 long step2 = System.nanoTime();
90 SyncResult result = compare(graphEntries, switchEntries);
91 long step3 = System.nanoTime();
92 graphIDTime = (step1 - start);
93 switchTime = (step2 - step1);
94 compareTime = (step3 - step2);
95 totalTime = (step3 - start);
96 outputTime();
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -080097
Ray Milkey8e5170e2014-04-02 12:09:55 -070098 return result;
99 } finally {
Jonathan Hart5302b6c2014-08-13 15:57:59 -0700100 pusher.resume(new Dpid(sw.getId()));
Ray Milkey8e5170e2014-04-02 12:09:55 -0700101 }
102 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800103
Ray Milkey8e5170e2014-04-02 12:09:55 -0700104 private void outputTime() {
105 double div = Math.pow(10, 6); //convert nanoseconds to ms
106 graphIDTime /= div;
107 switchTime /= div;
108 compareTime = (compareTime - graphEntryTime - extractTime - pushTime) / div;
109 graphEntryTime /= div;
110 extractTime /= div;
111 pushTime /= div;
112 totalTime /= div;
113 log.debug("Sync time (ms):{},{},{},{},{},{},{}"
114 , graphIDTime
115 , switchTime
116 , compareTime
117 , graphEntryTime
118 , extractTime
119 , pushTime
120 , totalTime);
121 }
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700122
Ray Milkey8e5170e2014-04-02 12:09:55 -0700123 /**
124 * Compare flows entries in GraphDB and switch to pick up necessary
125 * messages.
126 * After picking up, picked messages are added to FlowPusher.
127 *
128 * @param graphEntries Flow entries in GraphDB.
129 * @param switchEntries Flow entries in switch.
130 */
131 private SyncResult compare(Set<FlowEntryWrapper> graphEntries, Set<FlowEntryWrapper> switchEntries) {
132 int added = 0, removed = 0, skipped = 0;
133 for (FlowEntryWrapper entry : switchEntries) {
134 if (graphEntries.contains(entry)) {
135 graphEntries.remove(entry);
136 skipped++;
137 } else {
138 // remove flow entry from the switch
139 entry.removeFromSwitch(sw);
140 removed++;
141 }
142 }
143 for (FlowEntryWrapper entry : graphEntries) {
144 // add flow entry to switch
145 entry.addToSwitch(sw);
146 graphEntryTime += entry.dbTime;
147 extractTime += entry.extractTime;
148 pushTime += entry.pushTime;
149 added++;
150 }
151 log.debug("Flow entries added {}, " +
152 "Flow entries removed {}, " +
153 "Flow entries skipped {}"
154 , added
155 , removed
156 , skipped);
Brian O'Connore46492e2013-11-14 21:11:50 -0800157
Ray Milkey8e5170e2014-04-02 12:09:55 -0700158 return new SyncResult(added, removed, skipped);
159 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700160
Ray Milkey8e5170e2014-04-02 12:09:55 -0700161 /**
162 * Read GraphDB to get FlowEntries associated with a switch.
163 *
164 * @return set of FlowEntries
165 */
166 private Set<FlowEntryWrapper> getFlowEntriesFromGraph() {
167 Set<FlowEntryWrapper> entries = new HashSet<FlowEntryWrapper>();
Brian O'Connora8e49802013-10-30 20:49:59 -0700168
Ray Milkey8e5170e2014-04-02 12:09:55 -0700169 // TODO: fix when FlowSynchronizer is refactored
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700170 /*
Ray Milkey8e5170e2014-04-02 12:09:55 -0700171 for(IFlowEntry entry : swObj.getFlowEntries()) {
172 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
173 entries.add(fe);
174 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700175 */
Ray Milkey8e5170e2014-04-02 12:09:55 -0700176 return entries;
177 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700178
Ray Milkey8e5170e2014-04-02 12:09:55 -0700179 /**
180 * Read flow table from switch and derive FlowEntries from table.
181 *
182 * @return set of FlowEntries
183 */
184 private Set<FlowEntryWrapper> getFlowEntriesFromSwitch() {
Brian O'Connora8e49802013-10-30 20:49:59 -0700185
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700186 /*int lengthU = 0;
Ray Milkey8e5170e2014-04-02 12:09:55 -0700187 OFMatch match = new OFMatch();
188 match.setWildcards(OFMatch.OFPFW_ALL);
Brian O'Connore46492e2013-11-14 21:11:50 -0800189
Ray Milkey8e5170e2014-04-02 12:09:55 -0700190 OFFlowStatisticsRequest stat = new OFFlowStatisticsRequest();
191 stat.setOutPort((short) 0xffff); //TODO: OFPort.OFPP_NONE
192 stat.setTableId((byte) 0xff); // TODO: fix this with enum (ALL TABLES)
193 stat.setMatch(match);
194 List<OFStatistics> stats = new ArrayList<OFStatistics>();
195 stats.add(stat);
196 lengthU += stat.getLength();
197
198 OFStatisticsRequest req = new OFStatisticsRequest();
199 req.setStatisticType(OFStatisticsType.FLOW);
200 req.setStatistics(stats);
201 lengthU += req.getLengthU();
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700202 req.setLengthU(lengthU);*/
Ray Milkey8e5170e2014-04-02 12:09:55 -0700203
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700204 //List<OFStatistics> entries = null;
205 // XXX S when we fix stats, we fix this
206 /*try {
Ray Milkey8e5170e2014-04-02 12:09:55 -0700207 Future<List<OFStatistics>> dfuture = sw.getStatistics(req);
208 entries = dfuture.get();
209 } catch (IOException e) {
Yuta HIGUCHIe933a282014-07-13 21:02:29 -0700210 log.error("Error getting statistics", e);
Ray Milkey8e5170e2014-04-02 12:09:55 -0700211 return null;
212 } catch (InterruptedException e) {
Yuta HIGUCHIe933a282014-07-13 21:02:29 -0700213 log.error("Error getting statistics", e);
Ray Milkey8e5170e2014-04-02 12:09:55 -0700214 return null;
215 } catch (ExecutionException e) {
Yuta HIGUCHIe933a282014-07-13 21:02:29 -0700216 log.error("Error getting statistics", e);
Ray Milkey8e5170e2014-04-02 12:09:55 -0700217 return null;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700218 }*/
Ray Milkey8e5170e2014-04-02 12:09:55 -0700219
220 Set<FlowEntryWrapper> results = new HashSet<FlowEntryWrapper>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700221 /*
Ray Milkey8e5170e2014-04-02 12:09:55 -0700222 for (OFStatistics result : entries) {
223 OFFlowStatisticsReply entry = (OFFlowStatisticsReply) result;
224 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
225 results.add(fe);
226 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700227 */
Ray Milkey8e5170e2014-04-02 12:09:55 -0700228 return results;
229 }
Brian O'Connor8c166a72013-11-14 18:41:48 -0800230
Brian O'Connora8e49802013-10-30 20:49:59 -0700231 }
232
Naoki Shiotae3199732013-11-25 16:14:43 -0800233 /**
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800234 * FlowEntryWrapper represents abstract FlowEntry which is embodied
235 * by FlowEntryId (from GraphDB) or OFFlowStatisticsReply (from switch).
Naoki Shiotae3199732013-11-25 16:14:43 -0800236 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700237 static class FlowEntryWrapper {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700238 //FlowEntryId flowEntryId;
Ray Milkey8e5170e2014-04-02 12:09:55 -0700239 // TODO: fix when FlowSynchronizer is refactored
240 // IFlowEntry iFlowEntry;
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700241 //OFFlowStatisticsReply statisticsReply;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800242
Brian O'Connore46492e2013-11-14 21:11:50 -0800243
Ray Milkey8e5170e2014-04-02 12:09:55 -0700244 // TODO: fix when FlowSynchronizer is refactored
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700245 /*
Ray Milkey8e5170e2014-04-02 12:09:55 -0700246 public FlowEntryWrapper(IFlowEntry entry) {
247 flowEntryId = new FlowEntryId(entry.getFlowEntryId());
248 iFlowEntry = entry;
249 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700250 */
Brian O'Connora8e49802013-10-30 20:49:59 -0700251
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700252 /*public FlowEntryWrapper(OFFlowStatisticsReply entry) {
Ray Milkey8e5170e2014-04-02 12:09:55 -0700253 flowEntryId = new FlowEntryId(entry.getCookie());
254 statisticsReply = entry;
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700255 }*/
Brian O'Connora8e49802013-10-30 20:49:59 -0700256
Ray Milkey8e5170e2014-04-02 12:09:55 -0700257 /**
258 * Install this FlowEntry to a switch via FlowPusher.
259 *
260 * @param sw Switch to which flow will be installed.
261 */
262 double dbTime, extractTime, pushTime;
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800263
Ray Milkey8e5170e2014-04-02 12:09:55 -0700264 public void addToSwitch(IOFSwitch sw) {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700265 /*if (statisticsReply != null) {
Ray Milkey8e5170e2014-04-02 12:09:55 -0700266 log.error("Error adding existing flow entry {} to sw {}",
267 statisticsReply.getCookie(), sw.getId());
268 return;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800269 }
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800270
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700271 double startDB = System.nanoTime();*/
Ray Milkey8e5170e2014-04-02 12:09:55 -0700272 // Get the Flow Entry state from the Network Graph
273 // TODO: fix when FlowSynchronizer is refactored
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700274 /*
Ray Milkey8e5170e2014-04-02 12:09:55 -0700275 if (iFlowEntry == null) {
276 try {
277 // TODO: fix when FlowSynchronizer is refactored
278 iFlowEntry = dbHandler.searchFlowEntry(flowEntryId);
279 } catch (Exception e) {
280 log.error("Error finding flow entry {} in Network Graph",
281 flowEntryId);
282 return;
283 }
284 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700285 */
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700286 //dbTime = System.nanoTime() - startDB;
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800287
Ray Milkey8e5170e2014-04-02 12:09:55 -0700288 //
289 // TODO: The old FlowDatabaseOperation class is gone, so the code
290 //
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700291 /*
Ray Milkey8e5170e2014-04-02 12:09:55 -0700292 double startExtract = System.nanoTime();
293 FlowEntry flowEntry =
294 FlowDatabaseOperation.extractFlowEntry(iFlowEntry);
295 if (flowEntry == null) {
296 log.error("Cannot add flow entry {} to sw {} : flow entry cannot be extracted",
297 flowEntryId, sw.getId());
298 return;
299 }
300 extractTime = System.nanoTime() - startExtract;
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800301
Ray Milkey8e5170e2014-04-02 12:09:55 -0700302 double startPush = System.nanoTime();
303 pusher.pushFlowEntry(sw, flowEntry, MsgPriority.HIGH);
304 pushTime = System.nanoTime() - startPush;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700305 */
Ray Milkey8e5170e2014-04-02 12:09:55 -0700306 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700307
Ray Milkey8e5170e2014-04-02 12:09:55 -0700308 /**
309 * Remove this FlowEntry from a switch via FlowPusher.
310 *
311 * @param sw Switch from which flow will be removed.
312 */
313 public void removeFromSwitch(IOFSwitch sw) {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700314 /*if (statisticsReply == null) {
Ray Milkey8e5170e2014-04-02 12:09:55 -0700315 log.error("Error removing non-existent flow entry {} from sw {}",
316 flowEntryId, sw.getId());
317 return;
318 }
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800319
Ray Milkey8e5170e2014-04-02 12:09:55 -0700320 // Convert Statistics Reply to Flow Mod, then write it
321 OFFlowMod fm = new OFFlowMod();
322 fm.setCookie(statisticsReply.getCookie());
323 fm.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
324 fm.setLengthU(OFFlowMod.MINIMUM_LENGTH);
325 fm.setMatch(statisticsReply.getMatch());
326 fm.setPriority(statisticsReply.getPriority());
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700327 fm.setOutPort(OFPort.OFPP_NONE);*/
Brian O'Connora8e49802013-10-30 20:49:59 -0700328
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700329 // XXX BOC commented out pending FlowSync refactor
330 //pusher.add(sw, fm, MsgPriority.HIGH);
Ray Milkey8e5170e2014-04-02 12:09:55 -0700331 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700332
Ray Milkey8e5170e2014-04-02 12:09:55 -0700333 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700334 * Return the hash code of the Flow Entry ID.
Ray Milkey8e5170e2014-04-02 12:09:55 -0700335 */
336 @Override
337 public int hashCode() {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700338 //return flowEntryId.hashCode();
339 return 0;
Ray Milkey8e5170e2014-04-02 12:09:55 -0700340 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800341
Ray Milkey8e5170e2014-04-02 12:09:55 -0700342 /**
343 * Returns true of the object is another Flow Entry ID with
344 * the same value; otherwise, returns false.
345 *
Sho SHIMIZUa1199fa2014-06-10 18:11:12 -0700346 * @param obj to compare
Ray Milkey8e5170e2014-04-02 12:09:55 -0700347 * @return true if the object has the same Flow Entry ID.
348 */
349 @Override
350 public boolean equals(Object obj) {
351 if (obj != null && obj.getClass() == this.getClass()) {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700352 //FlowEntryWrapper entry = (FlowEntryWrapper) obj;
Ray Milkey8e5170e2014-04-02 12:09:55 -0700353 // TODO: we need to actually compare the match + actions
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700354 //return this.flowEntryId.equals(entry.flowEntryId);
355 return true;
Ray Milkey8e5170e2014-04-02 12:09:55 -0700356 }
357 return false;
358 }
359
360 @Override
361 public String toString() {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700362 //return flowEntryId.toString();
363 return "";
Ray Milkey8e5170e2014-04-02 12:09:55 -0700364 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800365 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800366}