blob: 1f426b302c104bbb83970406305218f22719ec7d [file] [log] [blame]
Brian O'Connor8c166a72013-11-14 18:41:48 -08001package net.onrc.onos.ofcontroller.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
Brian O'Connor0d6ba512013-11-05 15:17:44 -080015import org.openflow.protocol.OFFlowMod;
Brian O'Connora8e49802013-10-30 20:49:59 -070016import org.openflow.protocol.OFMatch;
Brian O'Connor0d6ba512013-11-05 15:17:44 -080017import org.openflow.protocol.OFPort;
Brian O'Connora8e49802013-10-30 20:49:59 -070018import org.openflow.protocol.OFStatisticsRequest;
19import org.openflow.protocol.statistics.OFFlowStatisticsReply;
20import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
21import org.openflow.protocol.statistics.OFStatistics;
22import org.openflow.protocol.statistics.OFStatisticsType;
23import org.slf4j.Logger;
24import org.slf4j.LoggerFactory;
25
Brian O'Connora8e49802013-10-30 20:49:59 -070026import net.floodlightcontroller.core.IOFSwitch;
Naoki Shiota8df97bc2014-03-13 18:42:23 -070027import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService.MsgPriority;
Brian O'Connora8e49802013-10-30 20:49:59 -070028import net.onrc.onos.ofcontroller.util.Dpid;
Pavlin Radoslavov6bfaea62013-12-03 14:55:57 -080029import net.onrc.onos.ofcontroller.util.FlowEntry;
Brian O'Connora8e49802013-10-30 20:49:59 -070030import net.onrc.onos.ofcontroller.util.FlowEntryId;
31
Naoki Shiotae3199732013-11-25 16:14:43 -080032/**
Naoki Shiotab485d412013-11-26 12:04:19 -080033 * FlowSynchronizer is an implementation of FlowSyncService.
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -080034 * In addition to IFlowSyncService, FlowSynchronizer periodically reads flow
35 * tables from switches and compare them with GraphDB to drop unnecessary
36 * flows and/or to install missing flows.
Naoki Shiotae3199732013-11-25 16:14:43 -080037 * @author Brian
38 *
39 */
Brian O'Connorea1efbe2013-11-25 22:57:43 -080040public class FlowSynchronizer implements IFlowSyncService {
Brian O'Connora8e49802013-10-30 20:49:59 -070041
Brian O'Connorea1efbe2013-11-25 22:57:43 -080042 private static Logger log = LoggerFactory.getLogger(FlowSynchronizer.class);
Brian O'Connore46492e2013-11-14 21:11:50 -080043
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -070044 // TODO: fix when FlowSynchronizer is refactored
Pavlin Radoslavov697f6982014-03-26 15:55:19 -070045 // private DBOperation dbHandler;
Brian O'Connorea1efbe2013-11-25 22:57:43 -080046 protected IFlowPusherService pusher;
Naoki Shiota2bdda572013-12-09 15:05:21 -080047 private Map<IOFSwitch, FutureTask<SyncResult>> switchThreads;
Brian O'Connore46492e2013-11-14 21:11:50 -080048
49 public FlowSynchronizer() {
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -070050 // TODO: fix when FlowSynchronizer is refactored
Pavlin Radoslavov697f6982014-03-26 15:55:19 -070051 // dbHandler = GraphDBManager.getDBOperation();
Naoki Shiota2bdda572013-12-09 15:05:21 -080052 switchThreads = new HashMap<IOFSwitch, FutureTask<SyncResult>>();
Brian O'Connore46492e2013-11-14 21:11:50 -080053 }
54
Brian O'Connorea1efbe2013-11-25 22:57:43 -080055 @Override
Naoki Shiota2bdda572013-12-09 15:05:21 -080056 public Future<SyncResult> synchronize(IOFSwitch sw) {
Pavlin Radoslavovf8c78552013-11-26 10:56:59 -080057 Synchronizer sync = new Synchronizer(sw);
Naoki Shiota2bdda572013-12-09 15:05:21 -080058 FutureTask<SyncResult> task = new FutureTask<SyncResult>(sync);
59 switchThreads.put(sw, task);
60 task.run();
61 return task;
Brian O'Connore46492e2013-11-14 21:11:50 -080062 }
Brian O'Connorea1efbe2013-11-25 22:57:43 -080063
Brian O'Connore46492e2013-11-14 21:11:50 -080064 @Override
Brian O'Connorea1efbe2013-11-25 22:57:43 -080065 public void interrupt(IOFSwitch sw) {
Naoki Shiota2bdda572013-12-09 15:05:21 -080066 FutureTask<SyncResult> t = switchThreads.remove(sw);
Brian O'Connore46492e2013-11-14 21:11:50 -080067 if(t != null) {
Naoki Shiota2bdda572013-12-09 15:05:21 -080068 t.cancel(true);
Brian O'Connorea1efbe2013-11-25 22:57:43 -080069 }
Brian O'Connore46492e2013-11-14 21:11:50 -080070 }
71
Naoki Shiotab485d412013-11-26 12:04:19 -080072 /**
73 * Initialize Synchronizer.
74 * @param pusherService FlowPusherService used for sending messages.
75 */
Brian O'Connorea1efbe2013-11-25 22:57:43 -080076 public void init(IFlowPusherService pusherService) {
77 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.
82 * @author Brian
83 *
84 */
Naoki Shiota2bdda572013-12-09 15:05:21 -080085 protected class Synchronizer implements Callable<SyncResult> {
Brian O'Connora8e49802013-10-30 20:49:59 -070086 IOFSwitch sw;
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -070087 // TODO: fix when FlowSynchronizer is refactored
88 // ISwitchObject swObj;
Brian O'Connore46492e2013-11-14 21:11:50 -080089
Pavlin Radoslavovf8c78552013-11-26 10:56:59 -080090 public Synchronizer(IOFSwitch sw) {
Brian O'Connora8e49802013-10-30 20:49:59 -070091 this.sw = sw;
92 Dpid dpid = new Dpid(sw.getId());
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -070093 // TODO: fix when FlowSynchronizer is refactored
Pavlin Radoslavov697f6982014-03-26 15:55:19 -070094 // this.swObj = dbHandler.searchSwitch(dpid.toString());
Brian O'Connora8e49802013-10-30 20:49:59 -070095 }
Brian O'Connore46492e2013-11-14 21:11:50 -080096
Brian O'Connor321a5d32013-12-09 18:11:35 -080097 double graphIDTime, switchTime, compareTime, graphEntryTime, extractTime, pushTime, totalTime;
Brian O'Connora8e49802013-10-30 20:49:59 -070098 @Override
Naoki Shiota2bdda572013-12-09 15:05:21 -080099 public SyncResult call() {
Naoki Shiota8df97bc2014-03-13 18:42:23 -0700100 pusher.suspend(sw);
Naoki Shiota277dbd22014-03-20 19:06:48 -0700101 try {
102 long start = System.nanoTime();
103 Set<FlowEntryWrapper> graphEntries = getFlowEntriesFromGraph();
104 long step1 = System.nanoTime();
105 Set<FlowEntryWrapper> switchEntries = getFlowEntriesFromSwitch();
106 if (switchEntries == null) {
107 log.debug("getFlowEntriesFromSwitch() failed");
108 return null;
109 }
110 long step2 = System.nanoTime();
111 SyncResult result = compare(graphEntries, switchEntries);
112 long step3 = System.nanoTime();
113 graphIDTime = (step1 - start);
114 switchTime = (step2 - step1);
115 compareTime = (step3 - step2);
116 totalTime = (step3 - start);
117 outputTime();
118
119 return result;
120 } finally {
121 pusher.resume(sw);
Naoki Shiotadf051d42014-01-20 16:12:41 -0800122 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700123 }
Brian O'Connor321a5d32013-12-09 18:11:35 -0800124
125 private void outputTime() {
126 double div = Math.pow(10, 6); //convert nanoseconds to ms
127 graphIDTime /= div;
128 switchTime /= div;
129 compareTime = (compareTime - graphEntryTime - extractTime - pushTime) / div;
130 graphEntryTime /= div;
131 extractTime /= div;
132 pushTime /= div;
Brian O'Connor8f7f8582013-12-11 15:48:07 -0800133 totalTime /= div;
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800134 log.debug("Sync time (ms):{},{},{},{},{},{},{}"
135 , graphIDTime
136 , switchTime
137 , compareTime
138 , graphEntryTime
139 , extractTime
140 , pushTime
141 , totalTime);
Brian O'Connora8e49802013-10-30 20:49:59 -0700142 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800143
Naoki Shiotae3199732013-11-25 16:14:43 -0800144 /**
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800145 * Compare flows entries in GraphDB and switch to pick up necessary
146 * messages.
Naoki Shiotae3199732013-11-25 16:14:43 -0800147 * After picking up, picked messages are added to FlowPusher.
148 * @param graphEntries Flow entries in GraphDB.
149 * @param switchEntries Flow entries in switch.
150 */
Naoki Shiota2bdda572013-12-09 15:05:21 -0800151 private SyncResult compare(Set<FlowEntryWrapper> graphEntries, Set<FlowEntryWrapper> switchEntries) {
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800152 int added = 0, removed = 0, skipped = 0;
153 for(FlowEntryWrapper entry : switchEntries) {
Brian O'Connore46492e2013-11-14 21:11:50 -0800154 if(graphEntries.contains(entry)) {
155 graphEntries.remove(entry);
156 skipped++;
157 }
158 else {
159 // remove flow entry from the switch
160 entry.removeFromSwitch(sw);
161 removed++;
162 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700163 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800164 for(FlowEntryWrapper entry : graphEntries) {
Brian O'Connore46492e2013-11-14 21:11:50 -0800165 // add flow entry to switch
166 entry.addToSwitch(sw);
Brian O'Connor321a5d32013-12-09 18:11:35 -0800167 graphEntryTime += entry.dbTime;
168 extractTime += entry.extractTime;
169 pushTime += entry.pushTime;
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800170 added++;
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800171 }
172 log.debug("Flow entries added {}, " +
173 "Flow entries removed {}, " +
174 "Flow entries skipped {}"
175 , added
176 , removed
177 , skipped );
178
Naoki Shiota2bdda572013-12-09 15:05:21 -0800179 return new SyncResult(added, removed, skipped);
Brian O'Connora8e49802013-10-30 20:49:59 -0700180 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800181
Naoki Shiotae3199732013-11-25 16:14:43 -0800182 /**
183 * Read GraphDB to get FlowEntries associated with a switch.
184 * @return set of FlowEntries
185 */
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800186 private Set<FlowEntryWrapper> getFlowEntriesFromGraph() {
187 Set<FlowEntryWrapper> entries = new HashSet<FlowEntryWrapper>();
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700188
189 // TODO: fix when FlowSynchronizer is refactored
190 /*
Brian O'Connora8e49802013-10-30 20:49:59 -0700191 for(IFlowEntry entry : swObj.getFlowEntries()) {
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800192 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
193 entries.add(fe);
Brian O'Connora8e49802013-10-30 20:49:59 -0700194 }
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700195 */
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800196 return entries;
Brian O'Connora8e49802013-10-30 20:49:59 -0700197 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800198
Naoki Shiotae3199732013-11-25 16:14:43 -0800199 /**
200 * Read flow table from switch and derive FlowEntries from table.
201 * @return set of FlowEntries
202 */
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800203 private Set<FlowEntryWrapper> getFlowEntriesFromSwitch() {
Brian O'Connora8e49802013-10-30 20:49:59 -0700204
205 int lengthU = 0;
206 OFMatch match = new OFMatch();
207 match.setWildcards(OFMatch.OFPFW_ALL);
208
209 OFFlowStatisticsRequest stat = new OFFlowStatisticsRequest();
210 stat.setOutPort((short) 0xffff); //TODO: OFPort.OFPP_NONE
211 stat.setTableId((byte) 0xff); // TODO: fix this with enum (ALL TABLES)
212 stat.setMatch(match);
213 List<OFStatistics> stats = new ArrayList<OFStatistics>();
214 stats.add(stat);
215 lengthU += stat.getLength();
216
217 OFStatisticsRequest req = new OFStatisticsRequest();
218 req.setStatisticType(OFStatisticsType.FLOW);
219 req.setStatistics(stats);
220 lengthU += req.getLengthU();
221 req.setLengthU(lengthU);
222
223 List<OFStatistics> entries = null;
224 try {
225 Future<List<OFStatistics>> dfuture = sw.getStatistics(req);
226 entries = dfuture.get();
227 } catch (IOException e) {
228 // TODO Auto-generated catch block
229 e.printStackTrace();
Naoki Shiotadf051d42014-01-20 16:12:41 -0800230 return null;
Brian O'Connora8e49802013-10-30 20:49:59 -0700231 } catch (InterruptedException e) {
232 // TODO Auto-generated catch block
233 e.printStackTrace();
Naoki Shiotadf051d42014-01-20 16:12:41 -0800234 return null;
Brian O'Connora8e49802013-10-30 20:49:59 -0700235 } catch (ExecutionException e) {
236 // TODO Auto-generated catch block
237 e.printStackTrace();
Naoki Shiotadf051d42014-01-20 16:12:41 -0800238 return null;
Brian O'Connora8e49802013-10-30 20:49:59 -0700239 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800240
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800241 Set<FlowEntryWrapper> results = new HashSet<FlowEntryWrapper>();
Brian O'Connora8e49802013-10-30 20:49:59 -0700242 for(OFStatistics result : entries){
Brian O'Connora8e49802013-10-30 20:49:59 -0700243 OFFlowStatisticsReply entry = (OFFlowStatisticsReply) result;
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800244 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
245 results.add(fe);
Brian O'Connora8e49802013-10-30 20:49:59 -0700246 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800247 return results;
Brian O'Connora8e49802013-10-30 20:49:59 -0700248 }
Brian O'Connor8c166a72013-11-14 18:41:48 -0800249
Brian O'Connora8e49802013-10-30 20:49:59 -0700250 }
251
Naoki Shiotae3199732013-11-25 16:14:43 -0800252 /**
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800253 * FlowEntryWrapper represents abstract FlowEntry which is embodied
254 * by FlowEntryId (from GraphDB) or OFFlowStatisticsReply (from switch).
Naoki Shiotae3199732013-11-25 16:14:43 -0800255 * @author Brian
256 *
257 */
Brian O'Connore46492e2013-11-14 21:11:50 -0800258 class FlowEntryWrapper {
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800259 FlowEntryId flowEntryId;
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700260 // TODO: fix when FlowSynchronizer is refactored
261 // IFlowEntry iFlowEntry;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800262 OFFlowStatisticsReply statisticsReply;
263
Brian O'Connore46492e2013-11-14 21:11:50 -0800264
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700265 // TODO: fix when FlowSynchronizer is refactored
266 /*
Brian O'Connore46492e2013-11-14 21:11:50 -0800267 public FlowEntryWrapper(IFlowEntry entry) {
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800268 flowEntryId = new FlowEntryId(entry.getFlowEntryId());
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800269 iFlowEntry = entry;
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700270 }
271 */
Brian O'Connora8e49802013-10-30 20:49:59 -0700272
Brian O'Connore46492e2013-11-14 21:11:50 -0800273 public FlowEntryWrapper(OFFlowStatisticsReply entry) {
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800274 flowEntryId = new FlowEntryId(entry.getCookie());
Brian O'Connore46492e2013-11-14 21:11:50 -0800275 statisticsReply = entry;
Brian O'Connore46492e2013-11-14 21:11:50 -0800276 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700277
Naoki Shiotae3199732013-11-25 16:14:43 -0800278 /**
279 * Install this FlowEntry to a switch via FlowPusher.
Naoki Shiotab485d412013-11-26 12:04:19 -0800280 * @param sw Switch to which flow will be installed.
Naoki Shiotae3199732013-11-25 16:14:43 -0800281 */
Brian O'Connor321a5d32013-12-09 18:11:35 -0800282 double dbTime, extractTime, pushTime;
Brian O'Connore46492e2013-11-14 21:11:50 -0800283 public void addToSwitch(IOFSwitch sw) {
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800284 if (statisticsReply != null) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800285 log.error("Error adding existing flow entry {} to sw {}",
Brian O'Connore46492e2013-11-14 21:11:50 -0800286 statisticsReply.getCookie(), sw.getId());
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800287 return;
Brian O'Connore46492e2013-11-14 21:11:50 -0800288 }
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800289
Brian O'Connor321a5d32013-12-09 18:11:35 -0800290 double startDB = System.nanoTime();
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800291 // Get the Flow Entry state from the Network Graph
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700292 // TODO: fix when FlowSynchronizer is refactored
293 /*
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800294 if (iFlowEntry == null) {
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800295 try {
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700296 // TODO: fix when FlowSynchronizer is refactored
297 iFlowEntry = dbHandler.searchFlowEntry(flowEntryId);
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800298 } catch (Exception e) {
299 log.error("Error finding flow entry {} in Network Graph",
300 flowEntryId);
301 return;
302 }
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800303 }
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700304 */
Brian O'Connor321a5d32013-12-09 18:11:35 -0800305 dbTime = System.nanoTime() - startDB;
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800306
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700307 //
308 // TODO: The old FlowDatabaseOperation class is gone, so the code
309 //
310 /*
Brian O'Connor321a5d32013-12-09 18:11:35 -0800311 double startExtract = System.nanoTime();
Pavlin Radoslavov6bfaea62013-12-03 14:55:57 -0800312 FlowEntry flowEntry =
313 FlowDatabaseOperation.extractFlowEntry(iFlowEntry);
314 if (flowEntry == null) {
315 log.error("Cannot add flow entry {} to sw {} : flow entry cannot be extracted",
316 flowEntryId, sw.getId());
317 return;
318 }
Brian O'Connor321a5d32013-12-09 18:11:35 -0800319 extractTime = System.nanoTime() - startExtract;
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800320
Brian O'Connor321a5d32013-12-09 18:11:35 -0800321 double startPush = System.nanoTime();
Naoki Shiota8df97bc2014-03-13 18:42:23 -0700322 pusher.pushFlowEntry(sw, flowEntry, MsgPriority.HIGH);
Brian O'Connor321a5d32013-12-09 18:11:35 -0800323 pushTime = System.nanoTime() - startPush;
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700324 */
Brian O'Connore46492e2013-11-14 21:11:50 -0800325 }
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800326
Naoki Shiotae3199732013-11-25 16:14:43 -0800327 /**
328 * Remove this FlowEntry from a switch via FlowPusher.
Naoki Shiotab485d412013-11-26 12:04:19 -0800329 * @param sw Switch from which flow will be removed.
Naoki Shiotae3199732013-11-25 16:14:43 -0800330 */
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800331 public void removeFromSwitch(IOFSwitch sw) {
332 if (statisticsReply == null) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800333 log.error("Error removing non-existent flow entry {} from sw {}",
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800334 flowEntryId, sw.getId());
335 return;
336 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700337
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800338 // Convert Statistics Reply to Flow Mod, then write it
339 OFFlowMod fm = new OFFlowMod();
340 fm.setCookie(statisticsReply.getCookie());
341 fm.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
342 fm.setLengthU(OFFlowMod.MINIMUM_LENGTH);
343 fm.setMatch(statisticsReply.getMatch());
344 fm.setPriority(statisticsReply.getPriority());
345 fm.setOutPort(OFPort.OFPP_NONE);
346
Naoki Shiota8df97bc2014-03-13 18:42:23 -0700347 pusher.add(sw, fm, MsgPriority.HIGH);
Brian O'Connore46492e2013-11-14 21:11:50 -0800348 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700349
Brian O'Connore46492e2013-11-14 21:11:50 -0800350 /**
351 * Return the hash code of the Flow Entry ID
352 */
353 @Override
354 public int hashCode() {
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800355 return flowEntryId.hashCode();
Brian O'Connore46492e2013-11-14 21:11:50 -0800356 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700357
Brian O'Connore46492e2013-11-14 21:11:50 -0800358 /**
359 * Returns true of the object is another Flow Entry ID with
360 * the same value; otherwise, returns false.
361 *
362 * @param Object to compare
Naoki Shiotab485d412013-11-26 12:04:19 -0800363 * @return true if the object has the same Flow Entry ID.
Brian O'Connore46492e2013-11-14 21:11:50 -0800364 */
365 @Override
366 public boolean equals(Object obj){
Naoki Shiotadf051d42014-01-20 16:12:41 -0800367 if(obj != null && obj.getClass() == this.getClass()) {
Brian O'Connore46492e2013-11-14 21:11:50 -0800368 FlowEntryWrapper entry = (FlowEntryWrapper) obj;
369 // TODO: we need to actually compare the match + actions
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800370 return this.flowEntryId.equals(entry.flowEntryId);
Brian O'Connore46492e2013-11-14 21:11:50 -0800371 }
372 return false;
373 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800374
Brian O'Connore46492e2013-11-14 21:11:50 -0800375 @Override
376 public String toString() {
Pavlin Radoslavov07fb9972013-12-02 16:20:24 -0800377 return flowEntryId.toString();
Brian O'Connore46492e2013-11-14 21:11:50 -0800378 }
379 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800380}