blob: b2e4552082e84ccc46899a781d7ec13c80704010 [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;
5import java.util.Collection;
Brian O'Connora8e49802013-10-30 20:49:59 -07006import java.util.HashMap;
7import java.util.HashSet;
8import java.util.List;
9import java.util.Map;
10import java.util.Set;
11import java.util.concurrent.ExecutionException;
Brian O'Connora8e49802013-10-30 20:49:59 -070012import java.util.concurrent.Future;
13
Brian O'Connor0d6ba512013-11-05 15:17:44 -080014import org.openflow.protocol.OFFlowMod;
Brian O'Connora8e49802013-10-30 20:49:59 -070015import org.openflow.protocol.OFMatch;
Brian O'Connor0d6ba512013-11-05 15:17:44 -080016import org.openflow.protocol.OFMessage;
17import org.openflow.protocol.OFPacketOut;
18import org.openflow.protocol.OFPort;
Brian O'Connora8e49802013-10-30 20:49:59 -070019import org.openflow.protocol.OFStatisticsRequest;
Brian O'Connor0d6ba512013-11-05 15:17:44 -080020import org.openflow.protocol.action.OFAction;
21import org.openflow.protocol.action.OFActionDataLayerDestination;
22import org.openflow.protocol.action.OFActionDataLayerSource;
23import org.openflow.protocol.action.OFActionEnqueue;
24import org.openflow.protocol.action.OFActionNetworkLayerDestination;
25import org.openflow.protocol.action.OFActionNetworkLayerSource;
26import org.openflow.protocol.action.OFActionNetworkTypeOfService;
27import org.openflow.protocol.action.OFActionOutput;
28import org.openflow.protocol.action.OFActionStripVirtualLan;
29import org.openflow.protocol.action.OFActionTransportLayerDestination;
30import org.openflow.protocol.action.OFActionTransportLayerSource;
31import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
32import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
Brian O'Connora8e49802013-10-30 20:49:59 -070033import org.openflow.protocol.statistics.OFFlowStatisticsReply;
34import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
35import org.openflow.protocol.statistics.OFStatistics;
36import org.openflow.protocol.statistics.OFStatisticsType;
37import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
Brian O'Connor8c166a72013-11-14 18:41:48 -080040import com.google.common.collect.Lists;
41import com.tinkerpop.blueprints.Direction;
42
Brian O'Connora8e49802013-10-30 20:49:59 -070043import net.floodlightcontroller.core.IFloodlightProviderService;
44import net.floodlightcontroller.core.IOFSwitch;
45import net.floodlightcontroller.core.IOFSwitchListener;
46import net.floodlightcontroller.core.module.FloodlightModuleContext;
47import net.floodlightcontroller.core.module.FloodlightModuleException;
48import net.floodlightcontroller.core.module.IFloodlightModule;
49import net.floodlightcontroller.core.module.IFloodlightService;
Brian O'Connor8c166a72013-11-14 18:41:48 -080050import net.floodlightcontroller.restserver.IRestApiService;
51import net.onrc.onos.datagrid.IDatagridService;
Brian O'Connora8e49802013-10-30 20:49:59 -070052import net.onrc.onos.graph.GraphDBOperation;
53import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
54import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
Brian O'Connor8c166a72013-11-14 18:41:48 -080055import net.onrc.onos.ofcontroller.core.module.IOnosService;
56import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
Brian O'Connora8e49802013-10-30 20:49:59 -070057import net.onrc.onos.ofcontroller.util.Dpid;
Brian O'Connor0d6ba512013-11-05 15:17:44 -080058import net.onrc.onos.ofcontroller.util.FlowEntryAction;
59import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Brian O'Connora8e49802013-10-30 20:49:59 -070060import net.onrc.onos.ofcontroller.util.FlowEntryId;
Brian O'Connor0d6ba512013-11-05 15:17:44 -080061import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionEnqueue;
62import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionOutput;
63import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetEthernetAddr;
64import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetIPv4Addr;
65import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetIpToS;
66import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetTcpUdpPort;
67import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetVlanId;
68import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetVlanPriority;
69import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionStripVlan;
Brian O'Connor8c166a72013-11-14 18:41:48 -080070import net.onrc.onos.registry.controller.IControllerRegistryService;
Brian O'Connora8e49802013-10-30 20:49:59 -070071
Brian O'Connor8c166a72013-11-14 18:41:48 -080072public class FlowSynchronizer implements IFlowSyncService, IOFSwitchListener {
Brian O'Connora8e49802013-10-30 20:49:59 -070073
Brian O'Connor0d6ba512013-11-05 15:17:44 -080074 protected static Logger log = LoggerFactory.getLogger(FlowSynchronizer.class);
Brian O'Connora8e49802013-10-30 20:49:59 -070075 protected IFloodlightProviderService floodlightProvider;
Brian O'Connor8c166a72013-11-14 18:41:48 -080076 protected IControllerRegistryService registryService;
77 protected IFlowPusherService pusher;
Brian O'Connore46492e2013-11-14 21:11:50 -080078
Brian O'Connor8c166a72013-11-14 18:41:48 -080079 private GraphDBOperation dbHandler;
80 private Map<IOFSwitch, Thread> switchThread = new HashMap<IOFSwitch, Thread>();
Brian O'Connore46492e2013-11-14 21:11:50 -080081
82 public FlowSynchronizer() {
83 dbHandler = new GraphDBOperation("");
84 }
85
86 public void synchronize(IOFSwitch sw) {
87 Synchroizer sync = new Synchroizer(sw);
88 Thread t = new Thread(sync);
89 t.start();
90 switchThread.put(sw, t);
91 }
92
93 @Override
94 public void addedSwitch(IOFSwitch sw) {
95 log.debug("Switch added: {}", sw.getId());
96
97 if (registryService.hasControl(sw.getId())) {
98 synchronize(sw);
99 }
100 }
101
102 @Override
103 public void removedSwitch(IOFSwitch sw) {
104 log.debug("Switch removed: {}", sw.getId());
105
106 Thread t = switchThread.remove(sw);
107 if(t != null) {
108 t.interrupt();
109 }
110
111 }
112
113 @Override
114 public void switchPortChanged(Long switchId) {
115 // TODO Auto-generated method stub
116 }
117
118 @Override
119 public String getName() {
120 return "FlowSynchronizer";
121 }
122
123 //@Override
124 public void init(FloodlightModuleContext context)
125 throws FloodlightModuleException {
126 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
127 registryService = context.getServiceImpl(IControllerRegistryService.class);
128 pusher = context.getServiceImpl(IFlowPusherService.class);
129 }
130
131 //@Override
132 public void startUp(FloodlightModuleContext context) {
133 floodlightProvider.addOFSwitchListener(this);
134 }
135
Brian O'Connora8e49802013-10-30 20:49:59 -0700136 protected class Synchroizer implements Runnable {
137 IOFSwitch sw;
138 ISwitchObject swObj;
Brian O'Connore46492e2013-11-14 21:11:50 -0800139
Brian O'Connora8e49802013-10-30 20:49:59 -0700140 public Synchroizer(IOFSwitch sw) {
141 this.sw = sw;
142 Dpid dpid = new Dpid(sw.getId());
143 this.swObj = dbHandler.searchSwitch(dpid.toString());
144 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800145
Brian O'Connora8e49802013-10-30 20:49:59 -0700146 @Override
147 public void run() {
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800148 Set<FlowEntryWrapper> graphEntries = getFlowEntriesFromGraph();
149 Set<FlowEntryWrapper> switchEntries = getFlowEntriesFromSwitch();
Brian O'Connora8e49802013-10-30 20:49:59 -0700150 compare(graphEntries, switchEntries);
151 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800152
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800153 private void compare(Set<FlowEntryWrapper> graphEntries, Set<FlowEntryWrapper> switchEntries) {
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800154 int added = 0, removed = 0, skipped = 0;
155 for(FlowEntryWrapper entry : switchEntries) {
Brian O'Connore46492e2013-11-14 21:11:50 -0800156 if(graphEntries.contains(entry)) {
157 graphEntries.remove(entry);
158 skipped++;
159 }
160 else {
161 // remove flow entry from the switch
162 entry.removeFromSwitch(sw);
163 removed++;
164 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700165 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800166 for(FlowEntryWrapper entry : graphEntries) {
Brian O'Connore46492e2013-11-14 21:11:50 -0800167 // add flow entry to switch
168 entry.addToSwitch(sw);
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800169 added++;
170 }
171 log.debug("Flow entries added "+ added + ", " +
172 "Flow entries removed "+ removed + ", " +
173 "Flow entries skipped " + skipped);
Brian O'Connora8e49802013-10-30 20:49:59 -0700174 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800175
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800176 private Set<FlowEntryWrapper> getFlowEntriesFromGraph() {
177 Set<FlowEntryWrapper> entries = new HashSet<FlowEntryWrapper>();
Brian O'Connora8e49802013-10-30 20:49:59 -0700178 for(IFlowEntry entry : swObj.getFlowEntries()) {
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800179 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
180 entries.add(fe);
Brian O'Connora8e49802013-10-30 20:49:59 -0700181 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800182 return entries;
Brian O'Connora8e49802013-10-30 20:49:59 -0700183 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800184
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800185 private Set<FlowEntryWrapper> getFlowEntriesFromSwitch() {
Brian O'Connora8e49802013-10-30 20:49:59 -0700186
187 int lengthU = 0;
188 OFMatch match = new OFMatch();
189 match.setWildcards(OFMatch.OFPFW_ALL);
190
191 OFFlowStatisticsRequest stat = new OFFlowStatisticsRequest();
192 stat.setOutPort((short) 0xffff); //TODO: OFPort.OFPP_NONE
193 stat.setTableId((byte) 0xff); // TODO: fix this with enum (ALL TABLES)
194 stat.setMatch(match);
195 List<OFStatistics> stats = new ArrayList<OFStatistics>();
196 stats.add(stat);
197 lengthU += stat.getLength();
198
199 OFStatisticsRequest req = new OFStatisticsRequest();
200 req.setStatisticType(OFStatisticsType.FLOW);
201 req.setStatistics(stats);
202 lengthU += req.getLengthU();
203 req.setLengthU(lengthU);
204
205 List<OFStatistics> entries = null;
206 try {
207 Future<List<OFStatistics>> dfuture = sw.getStatistics(req);
208 entries = dfuture.get();
209 } catch (IOException e) {
210 // TODO Auto-generated catch block
211 e.printStackTrace();
212 } catch (InterruptedException e) {
213 // TODO Auto-generated catch block
214 e.printStackTrace();
215 } catch (ExecutionException e) {
216 // TODO Auto-generated catch block
217 e.printStackTrace();
218 }
Brian O'Connore46492e2013-11-14 21:11:50 -0800219
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800220 Set<FlowEntryWrapper> results = new HashSet<FlowEntryWrapper>();
Brian O'Connora8e49802013-10-30 20:49:59 -0700221 for(OFStatistics result : entries){
Brian O'Connora8e49802013-10-30 20:49:59 -0700222 OFFlowStatisticsReply entry = (OFFlowStatisticsReply) result;
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800223 FlowEntryWrapper fe = new FlowEntryWrapper(entry);
224 results.add(fe);
Brian O'Connora8e49802013-10-30 20:49:59 -0700225 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800226 return results;
Brian O'Connora8e49802013-10-30 20:49:59 -0700227 }
Brian O'Connor8c166a72013-11-14 18:41:48 -0800228
Brian O'Connora8e49802013-10-30 20:49:59 -0700229 }
230
Brian O'Connore46492e2013-11-14 21:11:50 -0800231 class FlowEntryWrapper {
232 FlowEntryId id;
233 IFlowEntry iflowEntry;
234 OFFlowStatisticsReply statisticsReply;
235
236 public FlowEntryWrapper(IFlowEntry entry) {
237 iflowEntry = entry;
238 id = new FlowEntryId(entry.getFlowEntryId());
Brian O'Connora8e49802013-10-30 20:49:59 -0700239 }
240
Brian O'Connore46492e2013-11-14 21:11:50 -0800241 public FlowEntryWrapper(OFFlowStatisticsReply entry) {
242 statisticsReply = entry;
243 id = new FlowEntryId(entry.getCookie());
244 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700245
Brian O'Connore46492e2013-11-14 21:11:50 -0800246 public void addToSwitch(IOFSwitch sw) {
247 if(iflowEntry != null) {
248 pusher.add(sw, iflowEntry.getFlow(), iflowEntry);
249 }
250 else if(statisticsReply != null) {
251 log.error("Adding existing flow entry {} to sw {}",
252 statisticsReply.getCookie(), sw.getId());
253 }
254 }
255
256 public void removeFromSwitch(IOFSwitch sw){
257 if(iflowEntry != null) {
258 log.error("Removing non-existent flow entry {} from sw {}",
259 iflowEntry.getFlowEntryId(), sw.getId());
Brian O'Connora8e49802013-10-30 20:49:59 -0700260
Brian O'Connore46492e2013-11-14 21:11:50 -0800261 }
262 else if(statisticsReply != null) {
263 // Convert Statistics Reply to Flow Mod, then write it
264 OFFlowMod fm = new OFFlowMod();
265 fm.setCookie(statisticsReply.getCookie());
266 fm.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
267 fm.setLengthU(OFFlowMod.MINIMUM_LENGTH);
268 fm.setMatch(statisticsReply.getMatch());
269 fm.setPriority(statisticsReply.getPriority());
270 fm.setOutPort(OFPort.OFPP_NONE);
271 pusher.add(sw, fm);
272 }
273 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700274
Brian O'Connore46492e2013-11-14 21:11:50 -0800275 /**
276 * Return the hash code of the Flow Entry ID
277 */
278 @Override
279 public int hashCode() {
280 return id.hashCode();
281 }
Brian O'Connora8e49802013-10-30 20:49:59 -0700282
Brian O'Connore46492e2013-11-14 21:11:50 -0800283 /**
284 * Returns true of the object is another Flow Entry ID with
285 * the same value; otherwise, returns false.
286 *
287 * @param Object to compare
288 */
289 @Override
290 public boolean equals(Object obj){
291 if(obj.getClass() == this.getClass()) {
292 FlowEntryWrapper entry = (FlowEntryWrapper) obj;
293 // TODO: we need to actually compare the match + actions
294 return this.id.equals(entry.id);
295 }
296 return false;
297 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800298
Brian O'Connore46492e2013-11-14 21:11:50 -0800299 @Override
300 public String toString() {
301 return id.toString();
302 }
303 }
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800304}
305
Brian O'Connor0d6ba512013-11-05 15:17:44 -0800306