blob: dcc9022f2b8559e478563ddd9d45c21b25a4f7ef [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;
10import java.util.concurrent.ExecutionException;
Brian O'Connora8e49802013-10-30 20:49:59 -070011import java.util.concurrent.Future;
12
Brian O'Connor0d6ba512013-11-05 15:17:44 -080013import org.openflow.protocol.OFFlowMod;
Brian O'Connora8e49802013-10-30 20:49:59 -070014import org.openflow.protocol.OFMatch;
Brian O'Connor0d6ba512013-11-05 15:17:44 -080015import org.openflow.protocol.OFPort;
Brian O'Connora8e49802013-10-30 20:49:59 -070016import org.openflow.protocol.OFStatisticsRequest;
17import org.openflow.protocol.statistics.OFFlowStatisticsReply;
18import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
19import org.openflow.protocol.statistics.OFStatistics;
20import org.openflow.protocol.statistics.OFStatisticsType;
21import org.slf4j.Logger;
22import org.slf4j.LoggerFactory;
23
Brian O'Connora8e49802013-10-30 20:49:59 -070024import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connora8e49802013-10-30 20:49:59 -070025import net.onrc.onos.graph.GraphDBOperation;
26import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
27import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
Brian O'Connora8e49802013-10-30 20:49:59 -070028import net.onrc.onos.ofcontroller.util.Dpid;
Brian O'Connora8e49802013-10-30 20:49:59 -070029import net.onrc.onos.ofcontroller.util.FlowEntryId;
30
Brian O'Connorea1efbe2013-11-25 22:57:43 -080031public class FlowSynchronizer implements IFlowSyncService {
Brian O'Connora8e49802013-10-30 20:49:59 -070032
Brian O'Connorea1efbe2013-11-25 22:57:43 -080033 private static Logger log = LoggerFactory.getLogger(FlowSynchronizer.class);
Brian O'Connore46492e2013-11-14 21:11:50 -080034
Brian O'Connor8c166a72013-11-14 18:41:48 -080035 private GraphDBOperation dbHandler;
Brian O'Connorea1efbe2013-11-25 22:57:43 -080036 protected IFlowPusherService pusher;
37 private Map<IOFSwitch, Thread> switchThreads;
Brian O'Connore46492e2013-11-14 21:11:50 -080038
39 public FlowSynchronizer() {
40 dbHandler = new GraphDBOperation("");
Brian O'Connorea1efbe2013-11-25 22:57:43 -080041 switchThreads = new HashMap<IOFSwitch, Thread>();
Brian O'Connore46492e2013-11-14 21:11:50 -080042 }
43
Brian O'Connorea1efbe2013-11-25 22:57:43 -080044 @Override
Brian O'Connore46492e2013-11-14 21:11:50 -080045 public void synchronize(IOFSwitch sw) {
46 Synchroizer sync = new Synchroizer(sw);
47 Thread t = new Thread(sync);
Brian O'Connorea1efbe2013-11-25 22:57:43 -080048 switchThreads.put(sw, t);
Brian O'Connore46492e2013-11-14 21:11:50 -080049 t.start();
Brian O'Connore46492e2013-11-14 21:11:50 -080050 }
Brian O'Connorea1efbe2013-11-25 22:57:43 -080051
Brian O'Connore46492e2013-11-14 21:11:50 -080052 @Override
Brian O'Connorea1efbe2013-11-25 22:57:43 -080053 public void interrupt(IOFSwitch sw) {
54 Thread t = switchThreads.remove(sw);
Brian O'Connore46492e2013-11-14 21:11:50 -080055 if(t != null) {
56 t.interrupt();
Brian O'Connorea1efbe2013-11-25 22:57:43 -080057 }
Brian O'Connore46492e2013-11-14 21:11:50 -080058 }
59
Brian O'Connorea1efbe2013-11-25 22:57:43 -080060 public void init(IFlowPusherService pusherService) {
61 pusher = pusherService;
Brian O'Connore46492e2013-11-14 21:11:50 -080062 }
63
Brian O'Connora8e49802013-10-30 20:49:59 -070064 protected class Synchroizer implements Runnable {
65 IOFSwitch sw;
66 ISwitchObject swObj;
Brian O'Connore46492e2013-11-14 21:11:50 -080067
Brian O'Connora8e49802013-10-30 20:49:59 -070068 public Synchroizer(IOFSwitch sw) {
69 this.sw = sw;
70 Dpid dpid = new Dpid(sw.getId());
71 this.swObj = dbHandler.searchSwitch(dpid.toString());
72 }
Brian O'Connore46492e2013-11-14 21:11:50 -080073
Brian O'Connora8e49802013-10-30 20:49:59 -070074 @Override
75 public void run() {
Brian O'Connorea1efbe2013-11-25 22:57:43 -080076 // TODO: stop adding other flow entries while synchronizing
77 //pusher.suspend(sw);
Brian O'Connor0d6ba512013-11-05 15:17:44 -080078 Set<FlowEntryWrapper> graphEntries = getFlowEntriesFromGraph();
79 Set<FlowEntryWrapper> switchEntries = getFlowEntriesFromSwitch();
Brian O'Connora8e49802013-10-30 20:49:59 -070080 compare(graphEntries, switchEntries);
Brian O'Connorea1efbe2013-11-25 22:57:43 -080081 //pusher.resume(sw);
Brian O'Connora8e49802013-10-30 20:49:59 -070082 }
Brian O'Connore46492e2013-11-14 21:11:50 -080083
Brian O'Connor0d6ba512013-11-05 15:17:44 -080084 private void compare(Set<FlowEntryWrapper> graphEntries, Set<FlowEntryWrapper> switchEntries) {
Brian O'Connor0d6ba512013-11-05 15:17:44 -080085 int added = 0, removed = 0, skipped = 0;
86 for(FlowEntryWrapper entry : switchEntries) {
Brian O'Connore46492e2013-11-14 21:11:50 -080087 if(graphEntries.contains(entry)) {
88 graphEntries.remove(entry);
89 skipped++;
90 }
91 else {
92 // remove flow entry from the switch
93 entry.removeFromSwitch(sw);
94 removed++;
95 }
Brian O'Connora8e49802013-10-30 20:49:59 -070096 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -080097 for(FlowEntryWrapper entry : graphEntries) {
Brian O'Connore46492e2013-11-14 21:11:50 -080098 // add flow entry to switch
99 entry.addToSwitch(sw);
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800100 added++;
101 }
102 log.debug("Flow entries added "+ added + ", " +
103 "Flow entries removed "+ removed + ", " +
104 "Flow entries skipped " + skipped);
Brian O'Connora8e49802013-10-30 20:49:59 -0700105 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800106
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800107 private Set<FlowEntryWrapper> getFlowEntriesFromGraph() {
108 Set<FlowEntryWrapper> entries = new HashSet<FlowEntryWrapper>();
Brian O'Connora8e49802013-10-30 20:49:59 -0700109 for(IFlowEntry entry : swObj.getFlowEntries()) {
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800110 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
111 entries.add(fe);
Brian O'Connora8e49802013-10-30 20:49:59 -0700112 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800113 return entries;
Brian O'Connora8e49802013-10-30 20:49:59 -0700114 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800115
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800116 private Set<FlowEntryWrapper> getFlowEntriesFromSwitch() {
Brian O'Connora8e49802013-10-30 20:49:59 -0700117
118 int lengthU = 0;
119 OFMatch match = new OFMatch();
120 match.setWildcards(OFMatch.OFPFW_ALL);
121
122 OFFlowStatisticsRequest stat = new OFFlowStatisticsRequest();
123 stat.setOutPort((short) 0xffff); //TODO: OFPort.OFPP_NONE
124 stat.setTableId((byte) 0xff); // TODO: fix this with enum (ALL TABLES)
125 stat.setMatch(match);
126 List<OFStatistics> stats = new ArrayList<OFStatistics>();
127 stats.add(stat);
128 lengthU += stat.getLength();
129
130 OFStatisticsRequest req = new OFStatisticsRequest();
131 req.setStatisticType(OFStatisticsType.FLOW);
132 req.setStatistics(stats);
133 lengthU += req.getLengthU();
134 req.setLengthU(lengthU);
135
136 List<OFStatistics> entries = null;
137 try {
138 Future<List<OFStatistics>> dfuture = sw.getStatistics(req);
139 entries = dfuture.get();
140 } catch (IOException e) {
141 // TODO Auto-generated catch block
142 e.printStackTrace();
143 } catch (InterruptedException e) {
144 // TODO Auto-generated catch block
145 e.printStackTrace();
146 } catch (ExecutionException e) {
147 // TODO Auto-generated catch block
148 e.printStackTrace();
149 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800150
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800151 Set<FlowEntryWrapper> results = new HashSet<FlowEntryWrapper>();
Brian O'Connora8e49802013-10-30 20:49:59 -0700152 for(OFStatistics result : entries){
Brian O'Connora8e49802013-10-30 20:49:59 -0700153 OFFlowStatisticsReply entry = (OFFlowStatisticsReply) result;
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800154 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
155 results.add(fe);
Brian O'Connora8e49802013-10-30 20:49:59 -0700156 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800157 return results;
Brian O'Connora8e49802013-10-30 20:49:59 -0700158 }
Brian O'Connor8c166a72013-11-14 18:41:48 -0800159
Brian O'Connora8e49802013-10-30 20:49:59 -0700160 }
161
Brian O'Connore46492e2013-11-14 21:11:50 -0800162 class FlowEntryWrapper {
163 FlowEntryId id;
164 IFlowEntry iflowEntry;
165 OFFlowStatisticsReply statisticsReply;
166
167 public FlowEntryWrapper(IFlowEntry entry) {
168 iflowEntry = entry;
169 id = new FlowEntryId(entry.getFlowEntryId());
Brian O'Connora8e49802013-10-30 20:49:59 -0700170 }
171
Brian O'Connore46492e2013-11-14 21:11:50 -0800172 public FlowEntryWrapper(OFFlowStatisticsReply entry) {
173 statisticsReply = entry;
174 id = new FlowEntryId(entry.getCookie());
175 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700176
Brian O'Connore46492e2013-11-14 21:11:50 -0800177 public void addToSwitch(IOFSwitch sw) {
178 if(iflowEntry != null) {
179 pusher.add(sw, iflowEntry.getFlow(), iflowEntry);
180 }
181 else if(statisticsReply != null) {
182 log.error("Adding existing flow entry {} to sw {}",
183 statisticsReply.getCookie(), sw.getId());
184 }
185 }
186
187 public void removeFromSwitch(IOFSwitch sw){
188 if(iflowEntry != null) {
189 log.error("Removing non-existent flow entry {} from sw {}",
190 iflowEntry.getFlowEntryId(), sw.getId());
Brian O'Connora8e49802013-10-30 20:49:59 -0700191
Brian O'Connore46492e2013-11-14 21:11:50 -0800192 }
193 else if(statisticsReply != null) {
194 // Convert Statistics Reply to Flow Mod, then write it
195 OFFlowMod fm = new OFFlowMod();
196 fm.setCookie(statisticsReply.getCookie());
197 fm.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
198 fm.setLengthU(OFFlowMod.MINIMUM_LENGTH);
199 fm.setMatch(statisticsReply.getMatch());
200 fm.setPriority(statisticsReply.getPriority());
201 fm.setOutPort(OFPort.OFPP_NONE);
202 pusher.add(sw, fm);
203 }
204 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700205
Brian O'Connore46492e2013-11-14 21:11:50 -0800206 /**
207 * Return the hash code of the Flow Entry ID
208 */
209 @Override
210 public int hashCode() {
211 return id.hashCode();
212 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700213
Brian O'Connore46492e2013-11-14 21:11:50 -0800214 /**
215 * Returns true of the object is another Flow Entry ID with
216 * the same value; otherwise, returns false.
217 *
218 * @param Object to compare
219 */
220 @Override
221 public boolean equals(Object obj){
222 if(obj.getClass() == this.getClass()) {
223 FlowEntryWrapper entry = (FlowEntryWrapper) obj;
224 // TODO: we need to actually compare the match + actions
225 return this.id.equals(entry.id);
226 }
227 return false;
228 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800229
Brian O'Connore46492e2013-11-14 21:11:50 -0800230 @Override
231 public String toString() {
232 return id.toString();
233 }
234 }
Brian O'Connorea1efbe2013-11-25 22:57:43 -0800235
236
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800237}
238
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800239