blob: 0441ddc9214c90ac421382d5b9289fcd8ce8f17e [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 Harta99ec672014-04-03 11:30:34 -070012
Brian O'Connora8e49802013-10-30 20:49:59 -070013import org.slf4j.Logger;
14import org.slf4j.LoggerFactory;
15
Naoki Shiotae3199732013-11-25 16:14:43 -080016/**
Naoki Shiotab485d412013-11-26 12:04:19 -080017 * FlowSynchronizer is an implementation of FlowSyncService.
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -080018 * In addition to IFlowSyncService, FlowSynchronizer periodically reads flow
19 * tables from switches and compare them with GraphDB to drop unnecessary
20 * flows and/or to install missing flows.
Naoki Shiotae3199732013-11-25 16:14:43 -080021 */
Brian O'Connorea1efbe2013-11-25 22:57:43 -080022public class FlowSynchronizer implements IFlowSyncService {
Brian O'Connora8e49802013-10-30 20:49:59 -070023
Brian O'Connorea1efbe2013-11-25 22:57:43 -080024 private static Logger log = LoggerFactory.getLogger(FlowSynchronizer.class);
Brian O'Connore46492e2013-11-14 21:11:50 -080025
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -070026 // TODO: fix when FlowSynchronizer is refactored
Pavlin Radoslavov697f6982014-03-26 15:55:19 -070027 // private DBOperation dbHandler;
Brian O'Connorea1efbe2013-11-25 22:57:43 -080028 protected IFlowPusherService pusher;
Ray Milkey8e5170e2014-04-02 12:09:55 -070029 private Map<IOFSwitch, FutureTask<SyncResult>> switchThreads;
Brian O'Connore46492e2013-11-14 21:11:50 -080030
31 public FlowSynchronizer() {
Ray Milkey8e5170e2014-04-02 12:09:55 -070032 // TODO: fix when FlowSynchronizer is refactored
33 // dbHandler = GraphDBManager.getDBOperation();
34 switchThreads = new HashMap<IOFSwitch, FutureTask<SyncResult>>();
Brian O'Connore46492e2013-11-14 21:11:50 -080035 }
36
Brian O'Connorea1efbe2013-11-25 22:57:43 -080037 @Override
Naoki Shiota2bdda572013-12-09 15:05:21 -080038 public Future<SyncResult> synchronize(IOFSwitch sw) {
Ray Milkey8e5170e2014-04-02 12:09:55 -070039 Synchronizer sync = new Synchronizer(sw);
40 FutureTask<SyncResult> task = new FutureTask<SyncResult>(sync);
41 switchThreads.put(sw, task);
42 task.run();
43 return task;
Brian O'Connore46492e2013-11-14 21:11:50 -080044 }
Ray Milkey8e5170e2014-04-02 12:09:55 -070045
Brian O'Connore46492e2013-11-14 21:11:50 -080046 @Override
Brian O'Connorea1efbe2013-11-25 22:57:43 -080047 public void interrupt(IOFSwitch sw) {
Ray Milkey8e5170e2014-04-02 12:09:55 -070048 FutureTask<SyncResult> t = switchThreads.remove(sw);
49 if (t != null) {
50 t.cancel(true);
51 }
Brian O'Connore46492e2013-11-14 21:11:50 -080052 }
53
Naoki Shiotab485d412013-11-26 12:04:19 -080054 /**
55 * Initialize Synchronizer.
Ray Milkey8e5170e2014-04-02 12:09:55 -070056 *
Naoki Shiotab485d412013-11-26 12:04:19 -080057 * @param pusherService FlowPusherService used for sending messages.
58 */
Brian O'Connorea1efbe2013-11-25 22:57:43 -080059 public void init(IFlowPusherService pusherService) {
Ray Milkey8e5170e2014-04-02 12:09:55 -070060 pusher = pusherService;
Brian O'Connore46492e2013-11-14 21:11:50 -080061 }
62
Naoki Shiotae3199732013-11-25 16:14:43 -080063 /**
64 * Synchronizer represents main thread of synchronization.
Naoki Shiotae3199732013-11-25 16:14:43 -080065 */
Ray Milkey8e5170e2014-04-02 12:09:55 -070066 protected class Synchronizer implements Callable<SyncResult> {
67 IOFSwitch sw;
68 // TODO: fix when FlowSynchronizer is refactored
69 // ISwitchObject swObj;
Brian O'Connore46492e2013-11-14 21:11:50 -080070
Ray Milkey8e5170e2014-04-02 12:09:55 -070071 public Synchronizer(IOFSwitch sw) {
72 this.sw = sw;
Ray Milkey8e5170e2014-04-02 12:09:55 -070073 // TODO: fix when FlowSynchronizer is refactored
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -070074 // Dpid dpid = new Dpid(sw.getId());
Ray Milkey8e5170e2014-04-02 12:09:55 -070075 // this.swObj = dbHandler.searchSwitch(dpid.toString());
76 }
Brian O'Connore46492e2013-11-14 21:11:50 -080077
Ray Milkey8e5170e2014-04-02 12:09:55 -070078 double graphIDTime, switchTime, compareTime, graphEntryTime, extractTime, pushTime, totalTime;
Brian O'Connore46492e2013-11-14 21:11:50 -080079
Ray Milkey8e5170e2014-04-02 12:09:55 -070080 @Override
81 public SyncResult call() {
82 pusher.suspend(sw);
83 try {
84 long start = System.nanoTime();
85 Set<FlowEntryWrapper> graphEntries = getFlowEntriesFromGraph();
86 long step1 = System.nanoTime();
87 Set<FlowEntryWrapper> switchEntries = getFlowEntriesFromSwitch();
Ray Milkey8e5170e2014-04-02 12:09:55 -070088 long step2 = System.nanoTime();
89 SyncResult result = compare(graphEntries, switchEntries);
90 long step3 = System.nanoTime();
91 graphIDTime = (step1 - start);
92 switchTime = (step2 - step1);
93 compareTime = (step3 - step2);
94 totalTime = (step3 - start);
95 outputTime();
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -080096
Ray Milkey8e5170e2014-04-02 12:09:55 -070097 return result;
98 } finally {
99 pusher.resume(sw);
100 }
101 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800102
Ray Milkey8e5170e2014-04-02 12:09:55 -0700103 private void outputTime() {
104 double div = Math.pow(10, 6); //convert nanoseconds to ms
105 graphIDTime /= div;
106 switchTime /= div;
107 compareTime = (compareTime - graphEntryTime - extractTime - pushTime) / div;
108 graphEntryTime /= div;
109 extractTime /= div;
110 pushTime /= div;
111 totalTime /= div;
112 log.debug("Sync time (ms):{},{},{},{},{},{},{}"
113 , graphIDTime
114 , switchTime
115 , compareTime
116 , graphEntryTime
117 , extractTime
118 , pushTime
119 , totalTime);
120 }
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700121
Ray Milkey8e5170e2014-04-02 12:09:55 -0700122 /**
123 * Compare flows entries in GraphDB and switch to pick up necessary
124 * messages.
125 * After picking up, picked messages are added to FlowPusher.
126 *
127 * @param graphEntries Flow entries in GraphDB.
128 * @param switchEntries Flow entries in switch.
129 */
130 private SyncResult compare(Set<FlowEntryWrapper> graphEntries, Set<FlowEntryWrapper> switchEntries) {
131 int added = 0, removed = 0, skipped = 0;
132 for (FlowEntryWrapper entry : switchEntries) {
133 if (graphEntries.contains(entry)) {
134 graphEntries.remove(entry);
135 skipped++;
136 } else {
137 // remove flow entry from the switch
138 entry.removeFromSwitch(sw);
139 removed++;
140 }
141 }
142 for (FlowEntryWrapper entry : graphEntries) {
143 // add flow entry to switch
144 entry.addToSwitch(sw);
145 graphEntryTime += entry.dbTime;
146 extractTime += entry.extractTime;
147 pushTime += entry.pushTime;
148 added++;
149 }
150 log.debug("Flow entries added {}, " +
151 "Flow entries removed {}, " +
152 "Flow entries skipped {}"
153 , added
154 , removed
155 , skipped);
Brian O'Connore46492e2013-11-14 21:11:50 -0800156
Ray Milkey8e5170e2014-04-02 12:09:55 -0700157 return new SyncResult(added, removed, skipped);
158 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700159
Ray Milkey8e5170e2014-04-02 12:09:55 -0700160 /**
161 * Read GraphDB to get FlowEntries associated with a switch.
162 *
163 * @return set of FlowEntries
164 */
165 private Set<FlowEntryWrapper> getFlowEntriesFromGraph() {
166 Set<FlowEntryWrapper> entries = new HashSet<FlowEntryWrapper>();
Brian O'Connora8e49802013-10-30 20:49:59 -0700167
Ray Milkey8e5170e2014-04-02 12:09:55 -0700168 // TODO: fix when FlowSynchronizer is refactored
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700169 /*
Ray Milkey8e5170e2014-04-02 12:09:55 -0700170 for(IFlowEntry entry : swObj.getFlowEntries()) {
171 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
172 entries.add(fe);
173 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700174 */
Ray Milkey8e5170e2014-04-02 12:09:55 -0700175 return entries;
176 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700177
Ray Milkey8e5170e2014-04-02 12:09:55 -0700178 /**
179 * Read flow table from switch and derive FlowEntries from table.
180 *
181 * @return set of FlowEntries
182 */
183 private Set<FlowEntryWrapper> getFlowEntriesFromSwitch() {
Brian O'Connora8e49802013-10-30 20:49:59 -0700184
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700185 /*int lengthU = 0;
Ray Milkey8e5170e2014-04-02 12:09:55 -0700186 OFMatch match = new OFMatch();
187 match.setWildcards(OFMatch.OFPFW_ALL);
Brian O'Connore46492e2013-11-14 21:11:50 -0800188
Ray Milkey8e5170e2014-04-02 12:09:55 -0700189 OFFlowStatisticsRequest stat = new OFFlowStatisticsRequest();
190 stat.setOutPort((short) 0xffff); //TODO: OFPort.OFPP_NONE
191 stat.setTableId((byte) 0xff); // TODO: fix this with enum (ALL TABLES)
192 stat.setMatch(match);
193 List<OFStatistics> stats = new ArrayList<OFStatistics>();
194 stats.add(stat);
195 lengthU += stat.getLength();
196
197 OFStatisticsRequest req = new OFStatisticsRequest();
198 req.setStatisticType(OFStatisticsType.FLOW);
199 req.setStatistics(stats);
200 lengthU += req.getLengthU();
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700201 req.setLengthU(lengthU);*/
Ray Milkey8e5170e2014-04-02 12:09:55 -0700202
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700203 //List<OFStatistics> entries = null;
204 // XXX S when we fix stats, we fix this
205 /*try {
Ray Milkey8e5170e2014-04-02 12:09:55 -0700206 Future<List<OFStatistics>> dfuture = sw.getStatistics(req);
207 entries = dfuture.get();
208 } catch (IOException e) {
Yuta HIGUCHIe933a282014-07-13 21:02:29 -0700209 log.error("Error getting statistics", e);
Ray Milkey8e5170e2014-04-02 12:09:55 -0700210 return null;
211 } catch (InterruptedException e) {
Yuta HIGUCHIe933a282014-07-13 21:02:29 -0700212 log.error("Error getting statistics", e);
Ray Milkey8e5170e2014-04-02 12:09:55 -0700213 return null;
214 } catch (ExecutionException e) {
Yuta HIGUCHIe933a282014-07-13 21:02:29 -0700215 log.error("Error getting statistics", e);
Ray Milkey8e5170e2014-04-02 12:09:55 -0700216 return null;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700217 }*/
Ray Milkey8e5170e2014-04-02 12:09:55 -0700218
219 Set<FlowEntryWrapper> results = new HashSet<FlowEntryWrapper>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700220 /*
Ray Milkey8e5170e2014-04-02 12:09:55 -0700221 for (OFStatistics result : entries) {
222 OFFlowStatisticsReply entry = (OFFlowStatisticsReply) result;
223 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
224 results.add(fe);
225 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700226 */
Ray Milkey8e5170e2014-04-02 12:09:55 -0700227 return results;
228 }
Brian O'Connor8c166a72013-11-14 18:41:48 -0800229
Brian O'Connora8e49802013-10-30 20:49:59 -0700230 }
231
Naoki Shiotae3199732013-11-25 16:14:43 -0800232 /**
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800233 * FlowEntryWrapper represents abstract FlowEntry which is embodied
234 * by FlowEntryId (from GraphDB) or OFFlowStatisticsReply (from switch).
Naoki Shiotae3199732013-11-25 16:14:43 -0800235 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700236 static class FlowEntryWrapper {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700237 //FlowEntryId flowEntryId;
Ray Milkey8e5170e2014-04-02 12:09:55 -0700238 // TODO: fix when FlowSynchronizer is refactored
239 // IFlowEntry iFlowEntry;
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700240 //OFFlowStatisticsReply statisticsReply;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800241
Brian O'Connore46492e2013-11-14 21:11:50 -0800242
Ray Milkey8e5170e2014-04-02 12:09:55 -0700243 // TODO: fix when FlowSynchronizer is refactored
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700244 /*
Ray Milkey8e5170e2014-04-02 12:09:55 -0700245 public FlowEntryWrapper(IFlowEntry entry) {
246 flowEntryId = new FlowEntryId(entry.getFlowEntryId());
247 iFlowEntry = entry;
248 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700249 */
Brian O'Connora8e49802013-10-30 20:49:59 -0700250
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700251 /*public FlowEntryWrapper(OFFlowStatisticsReply entry) {
Ray Milkey8e5170e2014-04-02 12:09:55 -0700252 flowEntryId = new FlowEntryId(entry.getCookie());
253 statisticsReply = entry;
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700254 }*/
Brian O'Connora8e49802013-10-30 20:49:59 -0700255
Ray Milkey8e5170e2014-04-02 12:09:55 -0700256 /**
257 * Install this FlowEntry to a switch via FlowPusher.
258 *
259 * @param sw Switch to which flow will be installed.
260 */
261 double dbTime, extractTime, pushTime;
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800262
Ray Milkey8e5170e2014-04-02 12:09:55 -0700263 public void addToSwitch(IOFSwitch sw) {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700264 /*if (statisticsReply != null) {
Ray Milkey8e5170e2014-04-02 12:09:55 -0700265 log.error("Error adding existing flow entry {} to sw {}",
266 statisticsReply.getCookie(), sw.getId());
267 return;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800268 }
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800269
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700270 double startDB = System.nanoTime();*/
Ray Milkey8e5170e2014-04-02 12:09:55 -0700271 // Get the Flow Entry state from the Network Graph
272 // TODO: fix when FlowSynchronizer is refactored
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700273 /*
Ray Milkey8e5170e2014-04-02 12:09:55 -0700274 if (iFlowEntry == null) {
275 try {
276 // TODO: fix when FlowSynchronizer is refactored
277 iFlowEntry = dbHandler.searchFlowEntry(flowEntryId);
278 } catch (Exception e) {
279 log.error("Error finding flow entry {} in Network Graph",
280 flowEntryId);
281 return;
282 }
283 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700284 */
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700285 //dbTime = System.nanoTime() - startDB;
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800286
Ray Milkey8e5170e2014-04-02 12:09:55 -0700287 //
288 // TODO: The old FlowDatabaseOperation class is gone, so the code
289 //
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700290 /*
Ray Milkey8e5170e2014-04-02 12:09:55 -0700291 double startExtract = System.nanoTime();
292 FlowEntry flowEntry =
293 FlowDatabaseOperation.extractFlowEntry(iFlowEntry);
294 if (flowEntry == null) {
295 log.error("Cannot add flow entry {} to sw {} : flow entry cannot be extracted",
296 flowEntryId, sw.getId());
297 return;
298 }
299 extractTime = System.nanoTime() - startExtract;
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800300
Ray Milkey8e5170e2014-04-02 12:09:55 -0700301 double startPush = System.nanoTime();
302 pusher.pushFlowEntry(sw, flowEntry, MsgPriority.HIGH);
303 pushTime = System.nanoTime() - startPush;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700304 */
Ray Milkey8e5170e2014-04-02 12:09:55 -0700305 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700306
Ray Milkey8e5170e2014-04-02 12:09:55 -0700307 /**
308 * Remove this FlowEntry from a switch via FlowPusher.
309 *
310 * @param sw Switch from which flow will be removed.
311 */
312 public void removeFromSwitch(IOFSwitch sw) {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700313 /*if (statisticsReply == null) {
Ray Milkey8e5170e2014-04-02 12:09:55 -0700314 log.error("Error removing non-existent flow entry {} from sw {}",
315 flowEntryId, sw.getId());
316 return;
317 }
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800318
Ray Milkey8e5170e2014-04-02 12:09:55 -0700319 // Convert Statistics Reply to Flow Mod, then write it
320 OFFlowMod fm = new OFFlowMod();
321 fm.setCookie(statisticsReply.getCookie());
322 fm.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
323 fm.setLengthU(OFFlowMod.MINIMUM_LENGTH);
324 fm.setMatch(statisticsReply.getMatch());
325 fm.setPriority(statisticsReply.getPriority());
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700326 fm.setOutPort(OFPort.OFPP_NONE);*/
Brian O'Connora8e49802013-10-30 20:49:59 -0700327
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700328 // XXX BOC commented out pending FlowSync refactor
329 //pusher.add(sw, fm, MsgPriority.HIGH);
Ray Milkey8e5170e2014-04-02 12:09:55 -0700330 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700331
Ray Milkey8e5170e2014-04-02 12:09:55 -0700332 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700333 * Return the hash code of the Flow Entry ID.
Ray Milkey8e5170e2014-04-02 12:09:55 -0700334 */
335 @Override
336 public int hashCode() {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700337 //return flowEntryId.hashCode();
338 return 0;
Ray Milkey8e5170e2014-04-02 12:09:55 -0700339 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800340
Ray Milkey8e5170e2014-04-02 12:09:55 -0700341 /**
342 * Returns true of the object is another Flow Entry ID with
343 * the same value; otherwise, returns false.
344 *
Sho SHIMIZUa1199fa2014-06-10 18:11:12 -0700345 * @param obj to compare
Ray Milkey8e5170e2014-04-02 12:09:55 -0700346 * @return true if the object has the same Flow Entry ID.
347 */
348 @Override
349 public boolean equals(Object obj) {
350 if (obj != null && obj.getClass() == this.getClass()) {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700351 //FlowEntryWrapper entry = (FlowEntryWrapper) obj;
Ray Milkey8e5170e2014-04-02 12:09:55 -0700352 // TODO: we need to actually compare the match + actions
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700353 //return this.flowEntryId.equals(entry.flowEntryId);
354 return true;
Ray Milkey8e5170e2014-04-02 12:09:55 -0700355 }
356 return false;
357 }
358
359 @Override
360 public String toString() {
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700361 //return flowEntryId.toString();
362 return "";
Ray Milkey8e5170e2014-04-02 12:09:55 -0700363 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800364 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800365}