blob: 5d06337a00068ac2739124dd9d23b70669cc86bd [file] [log] [blame]
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001package net.floodlightcontroller.flowcache;
2
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08004import java.util.ArrayList;
5import java.util.Collection;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08006import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08007import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00008import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08009import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080010import java.util.Map;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070011import java.util.TreeMap;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070012import java.util.Collections;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070013import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070015import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.ScheduledExecutorService;
17import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070018import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IFloodlightProviderService;
22import net.floodlightcontroller.core.INetMapStorage;
23import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
24import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070025import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070026import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080027import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080028import net.floodlightcontroller.core.module.FloodlightModuleContext;
29import net.floodlightcontroller.core.module.FloodlightModuleException;
30import net.floodlightcontroller.core.module.IFloodlightModule;
31import net.floodlightcontroller.core.module.IFloodlightService;
32import net.floodlightcontroller.flowcache.IFlowService;
33import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
34import net.floodlightcontroller.restserver.IRestApiService;
35import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080036import net.floodlightcontroller.util.DataPath;
37import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080038import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070040import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070042import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043import net.floodlightcontroller.util.FlowEntrySwitchState;
44import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080045import net.floodlightcontroller.util.FlowId;
46import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070047import net.floodlightcontroller.util.IPv4Net;
48import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080049import net.floodlightcontroller.util.OFMessageDamper;
50import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070051import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070052import net.onrc.onos.flow.IFlowManager;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080053import net.onrc.onos.util.GraphDBConnection;
54import net.onrc.onos.util.GraphDBConnection.Transaction;
55
56import org.openflow.protocol.OFFlowMod;
57import org.openflow.protocol.OFMatch;
58import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070059import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080060import org.openflow.protocol.OFType;
61import org.openflow.protocol.action.OFAction;
62import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080063
64import org.slf4j.Logger;
65import org.slf4j.LoggerFactory;
66
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070067public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080068
69 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080070
71 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070073 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070074 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080075
76 protected OFMessageDamper messageDamper;
77
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070078 //
79 // TODO: Values copied from elsewhere (class LearningSwitch).
80 // The local copy should go away!
81 //
82 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
83 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
84 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
85 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
86 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080087
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070088 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070089 private static long measurementFlowId = 100000;
90 private static String measurementFlowIdStr = "0x186a0"; // 100000
91 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070092
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080093 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080094 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
95
96 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070097 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080098 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070099 private final ScheduledExecutorService measureMapReaderScheduler =
100 Executors.newScheduledThreadPool(1);
101 private final ScheduledExecutorService mapReaderScheduler =
102 Executors.newScheduledThreadPool(1);
103
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700104 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
105 private ThreadPoolExecutor shortestPathExecutor =
106 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
107
108 class ShortestPathTask implements Runnable {
109 private int hint;
110 private ITopoRouteService topoRouteService;
111 private ArrayList<DataPath> dpList;
112
113 public ShortestPathTask(int hint,
114 ITopoRouteService topoRouteService,
115 ArrayList<DataPath> dpList) {
116 this.hint = hint;
117 this.topoRouteService = topoRouteService;
118 this.dpList = dpList;
119 }
120
121 @Override
122 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700123 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700124 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
125 log.debug(logMsg);
126 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700127 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700128 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700129 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700130 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700131 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700132 long estimatedTime = System.nanoTime() - startTime;
133 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
134 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
135 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700136 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700137 }
138 }
139
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700140 final Runnable measureShortestPath = new Runnable() {
141 public void run() {
142 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
143 if (floodlightProvider == null) {
144 log.debug("FloodlightProvider service not found!");
145 return;
146 }
147
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700148 if (topoRouteService == null) {
149 log.debug("Topology Route Service not found");
150 return;
151 }
152
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700153 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
154 if (leftoverQueueSize > 0) {
155 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
156 log.debug(logMsg);
157 return;
158 }
159 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
160
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700161 //
162 // Recompute the Shortest Paths for all Flows
163 //
164 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700165 int hint = 0;
166 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700167 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700168
169 topoRouteService.prepareShortestPathTopo();
170
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700171 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
172 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700173 FlowId flowId = new FlowId(flowPathObj.getFlowId());
174
175 // log.debug("Found Path {}", flowId.toString());
176 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
177 Port srcPort = new Port(flowPathObj.getSrcPort());
178 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
179 Port dstPort = new Port(flowPathObj.getDstPort());
180 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
181 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700182
183 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700184 DataPath dp = new DataPath();
185 dp.setSrcPort(srcSwitchPort);
186 dp.setDstPort(dstSwitchPort);
187 dpList.add(dp);
188 if ((dpList.size() % 10) == 0) {
189 shortestPathExecutor.execute(
190 new ShortestPathTask(hint, topoRouteService,
191 dpList));
192 dpList = new ArrayList<DataPath>();
193 hint++;
194 }
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700195 */
196
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700197 DataPath dataPath =
198 topoRouteService.getTopoShortestPath(srcSwitchPort,
199 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700200 counter++;
201 }
202 if (dpList.size() > 0) {
203 shortestPathExecutor.execute(
204 new ShortestPathTask(hint, topoRouteService,
205 dpList));
206 }
207
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700208 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700209 // Wait for all tasks to finish
210 try {
211 while (shortestPathExecutor.getQueue().size() > 0) {
212 Thread.sleep(100);
213 }
214 } catch (InterruptedException ex) {
215 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700216 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700217 */
218
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700219 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700220 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700221
222 long estimatedTime = System.nanoTime() - startTime;
223 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
224 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
225 log.debug(logMsg);
226 }
227 };
228
229 final Runnable measureMapReader = new Runnable() {
230 public void run() {
231 if (floodlightProvider == null) {
232 log.debug("FloodlightProvider service not found!");
233 return;
234 }
235
236 //
237 // Fetch all Flow Entries
238 //
239 int counter = 0;
240 long startTime = System.nanoTime();
241 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
242 for (IFlowEntry flowEntryObj : allFlowEntries) {
243 counter++;
244 FlowEntryId flowEntryId =
245 new FlowEntryId(flowEntryObj.getFlowEntryId());
246 String userState = flowEntryObj.getUserState();
247 String switchState = flowEntryObj.getSwitchState();
248 }
249 conn.endTx(Transaction.COMMIT);
250
251 long estimatedTime = System.nanoTime() - startTime;
252 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
253 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
254 log.debug(logMsg);
255 }
256 };
257
258 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800259 public void run() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800260 if (floodlightProvider == null) {
261 log.debug("FloodlightProvider service not found!");
262 return;
263 }
264
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000265 Map<Long, IOFSwitch> mySwitches =
266 floodlightProvider.getSwitches();
267 Map<Long, IFlowEntry> myFlowEntries =
268 new TreeMap<Long, IFlowEntry>();
269 LinkedList<IFlowEntry> deleteFlowEntries =
270 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700271
272 //
273 // Fetch all Flow Entries and select only my Flow Entries
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000274 // that need to be undated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700275 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000276 Iterable<IFlowEntry> allFlowEntries =
277 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700278 for (IFlowEntry flowEntryObj : allFlowEntries) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000279 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700280 String userState = flowEntryObj.getUserState();
281 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000282 String dpidStr = flowEntryObj.getSwitchDpid();
283 if ((flowEntryIdStr == null) ||
284 (userState == null) ||
285 (switchState == null) ||
286 (dpidStr == null)) {
287 log.debug("IGNORING Flow Entry entry with null fields");
288 continue;
289 }
290 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
291 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800292
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000293 /*
294 log.debug("Found Flow Entry Id = {} {}",
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700295 flowEntryId.toString(),
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000296 "DPID = " + dpid.toString() +
297 " User State: " + userState +
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700298 " Switch State: " + switchState);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000299 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800300
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000301 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
302 continue; // Ignore the entry: nothing to do
303
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800304 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000305 if (mySwitch == null)
306 continue; // Ignore the entry: not my switch
307
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700308 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
309 }
310
311 //
312 // Process my Flow Entries
313 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700314 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700315 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
316 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700317 // Code for measurement purpose
318 {
319 IFlowPath flowObj =
320 conn.utils().getFlowPathByFlowEntry(conn,
321 flowEntryObj);
322 if ((flowObj != null) &&
323 flowObj.getFlowId().equals(measurementFlowIdStr)) {
324 processed_measurement_flow = true;
325 }
326 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700327
328 //
329 // TODO: Eliminate the re-fetching of flowEntryId,
330 // userState, switchState, and dpid from the flowEntryObj.
331 //
332 FlowEntryId flowEntryId =
333 new FlowEntryId(flowEntryObj.getFlowEntryId());
334 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
335 String userState = flowEntryObj.getUserState();
336 String switchState = flowEntryObj.getSwitchState();
337 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000338 if (mySwitch == null)
339 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800340
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700341 // TODO: PAVPAVPAV: FROM HERE...
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800342 //
343 // Create the Open Flow Flow Modification Entry to push
344 //
345 OFFlowMod fm =
346 (OFFlowMod) floodlightProvider.getOFMessageFactory()
347 .getMessage(OFType.FLOW_MOD);
348 long cookie = flowEntryId.value();
349
350 short flowModCommand = OFFlowMod.OFPFC_ADD;
351 if (userState.equals("FE_USER_ADD")) {
352 flowModCommand = OFFlowMod.OFPFC_ADD;
353 } else if (userState.equals("FE_USER_MODIFY")) {
354 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
355 } else if (userState.equals("FE_USER_DELETE")) {
356 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
357 } else {
358 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700359 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
360 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800361 continue;
362 }
363
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700364 //
365 // Fetch the match conditions
366 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800367 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700368 match.setWildcards(OFMatch.OFPFW_ALL);
369 Short matchInPort = flowEntryObj.getMatchInPort();
370 if (matchInPort != null) {
371 match.setInputPort(matchInPort);
372 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
373 }
374 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
375 if (matchEthernetFrameType != null) {
376 match.setDataLayerType(matchEthernetFrameType);
377 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
378 }
379 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
380 if (matchSrcIPv4Net != null) {
381 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
382 }
383 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
384 if (matchDstIPv4Net != null) {
385 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
386 }
387 String matchSrcMac = flowEntryObj.getMatchSrcMac();
388 if (matchSrcMac != null) {
389 match.setDataLayerSource(matchSrcMac);
390 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
391 }
392 String matchDstMac = flowEntryObj.getMatchDstMac();
393 if (matchDstMac != null) {
394 match.setDataLayerDestination(matchDstMac);
395 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
396 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700397
398 //
399 // Fetch the actions
400 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800401 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700402 Short actionOutputPort = flowEntryObj.getActionOutput();
403 if (actionOutputPort != null) {
404 OFActionOutput action = new OFActionOutput();
405 // XXX: The max length is hard-coded for now
406 action.setMaxLength((short)0xffff);
407 action.setPort(actionOutputPort);
408 actions.add(action);
409 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800410
411 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
412 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700413 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800414 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
415 .setCookie(cookie)
416 .setCommand(flowModCommand)
417 .setMatch(match)
418 .setActions(actions)
419 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700420 fm.setOutPort(OFPort.OFPP_NONE.getValue());
421 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
422 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
423 if (actionOutputPort != null)
424 fm.setOutPort(actionOutputPort);
425 }
426
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800427 //
428 // TODO: Set the following flag
429 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
430 // See method ForwardingBase::pushRoute()
431 //
432 try {
433 messageDamper.write(mySwitch, fm, null);
434 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000435 //
436 // TODO: We should use the OpenFlow Barrier mechanism
437 // to check for errors, and update the SwitchState
438 // for a flow entry after the Barrier message is
439 // is received.
440 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800441 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
442 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000443 // An entry that needs to be deleted.
444 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800445 }
446 } catch (IOException e) {
447 log.error("Failure writing flow mod from network map", e);
448 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700449 // TODO: XXX: PAVPAVPAV: TO HERE.
450 // TODO: XXX: PAVPAVPAV: Update the flowEntryObj
451 // to "FE_SWITCH_UPDATED" in the new (refactored) code.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800452 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000453
454 //
455 // Delete all entries marked for deletion
456 //
457 // TODO: We should use the OpenFlow Barrier mechanism
458 // to check for errors, and delete the Flow Entries after the
459 // Barrier message is received.
460 //
461 while (! deleteFlowEntries.isEmpty()) {
462 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
463 IFlowPath flowObj =
464 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
465 if (flowObj == null) {
466 log.debug("Did not find FlowPath to be deleted");
467 continue;
468 }
469 flowObj.removeFlowEntry(flowEntryObj);
470 conn.utils().removeFlowEntry(conn, flowEntryObj);
471
472 // Test whether the last flow entry
473 Iterable<IFlowEntry> tmpflowEntries =
474 flowObj.getFlowEntries();
475 boolean found = false;
476 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
477 found = true;
478 break;
479 }
480 if (! found) {
481 // Remove the Flow Path as well
482 conn.utils().removeFlowPath(conn, flowObj);
483 }
484 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800485 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700486
487 if (processed_measurement_flow) {
488 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
489 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
490 (double)estimatedTime / 1000000000 + " sec";
491 log.debug(logMsg);
492 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800493 }
494 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700495
496 /*
497 final ScheduledFuture<?> measureShortestPathHandle =
498 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
499 */
500
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700501 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700502 final ScheduledFuture<?> measureMapReaderHandle =
503 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700504 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700505
506 final ScheduledFuture<?> mapReaderHandle =
507 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800508
509 @Override
510 public void init(String conf) {
511 conn = GraphDBConnection.getInstance(conf);
512 }
513
514 public void finalize() {
515 close();
516 }
517
518 @Override
519 public void close() {
520 conn.close();
521 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800522
523 @Override
524 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
525 Collection<Class<? extends IFloodlightService>> l =
526 new ArrayList<Class<? extends IFloodlightService>>();
527 l.add(IFlowService.class);
528 return l;
529 }
530
531 @Override
532 public Map<Class<? extends IFloodlightService>, IFloodlightService>
533 getServiceImpls() {
534 Map<Class<? extends IFloodlightService>,
535 IFloodlightService> m =
536 new HashMap<Class<? extends IFloodlightService>,
537 IFloodlightService>();
538 m.put(IFlowService.class, this);
539 return m;
540 }
541
542 @Override
543 public Collection<Class<? extends IFloodlightService>>
544 getModuleDependencies() {
545 Collection<Class<? extends IFloodlightService>> l =
546 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800547 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700548 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800549 l.add(IRestApiService.class);
550 return l;
551 }
552
553 @Override
554 public void init(FloodlightModuleContext context)
555 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700556 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800557 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700558 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800559 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800560 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
561 EnumSet.of(OFType.FLOW_MOD),
562 OFMESSAGE_DAMPER_TIMEOUT);
563 // TODO: An ugly hack!
564 String conf = "/tmp/cassandra.titan";
565 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800566 }
567
568 @Override
569 public void startUp(FloodlightModuleContext context) {
570 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700571
572 //
573 // Extract all flow entries and assign the next Flow Entry ID
574 // to be larger than the largest Flow Entry ID
575 //
576 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
577 for (IFlowEntry flowEntryObj : allFlowEntries) {
578 FlowEntryId flowEntryId =
579 new FlowEntryId(flowEntryObj.getFlowEntryId());
580 if (flowEntryId.value() >= nextFlowEntryId)
581 nextFlowEntryId = flowEntryId.value() + 1;
582 }
583 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800584 }
585
586 /**
587 * Add a flow.
588 *
589 * Internally, ONOS will automatically register the installer for
590 * receiving Flow Path Notifications for that path.
591 *
592 * @param flowPath the Flow Path to install.
593 * @param flowId the return-by-reference Flow ID as assigned internally.
594 * @return true on success, otherwise false.
595 */
596 @Override
597 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700598 if (flowPath.flowId().value() == measurementFlowId) {
599 modifiedMeasurementFlowTime = System.nanoTime();
600 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800601
602 //
603 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700604 // Right now every new flow entry gets a new flow entry ID
605 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800606 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800607 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700608 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800609 flowEntry.setFlowEntryId(new FlowEntryId(id));
610 }
611
612 IFlowPath flowObj = null;
613 try {
614 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
615 != null) {
616 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
617 flowPath.flowId().toString());
618 } else {
619 flowObj = conn.utils().newFlowPath(conn);
620 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
621 flowPath.flowId().toString());
622 }
623 } catch (Exception e) {
624 // TODO: handle exceptions
625 conn.endTx(Transaction.ROLLBACK);
626 log.error(":addFlow FlowId:{} failed",
627 flowPath.flowId().toString());
628 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700629 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000630 log.error(":addFlow FlowId:{} failed: Flow object not created",
631 flowPath.flowId().toString());
632 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800633 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700634 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800635
636 //
637 // Set the Flow key:
638 // - flowId
639 //
640 flowObj.setFlowId(flowPath.flowId().toString());
641 flowObj.setType("flow");
642
643 //
644 // Set the Flow attributes:
645 // - flowPath.installerId()
646 // - flowPath.dataPath().srcPort()
647 // - flowPath.dataPath().dstPort()
648 //
649 flowObj.setInstallerId(flowPath.installerId().toString());
650 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
651 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
652 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
653 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
654
655 // Flow edges:
656 // HeadFE
657
658
659 //
660 // Flow Entries:
661 // flowPath.dataPath().flowEntries()
662 //
663 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
664 IFlowEntry flowEntryObj = null;
665 boolean found = false;
666 try {
667 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
668 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
669 flowEntry.flowEntryId().toString());
670 found = true;
671 } else {
672 flowEntryObj = conn.utils().newFlowEntry(conn);
673 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
674 flowEntry.flowEntryId().toString());
675 }
676 } catch (Exception e) {
677 // TODO: handle exceptions
678 conn.endTx(Transaction.ROLLBACK);
679 log.error(":addFlow FlowEntryId:{} failed",
680 flowEntry.flowEntryId().toString());
681 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700682 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000683 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
684 flowEntry.flowEntryId().toString());
685 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800686 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700687 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800688
689 //
690 // Set the Flow Entry key:
691 // - flowEntry.flowEntryId()
692 //
693 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
694 flowEntryObj.setType("flow_entry");
695
696 //
697 // Set the Flow Entry attributes:
698 // - flowEntry.flowEntryMatch()
699 // - flowEntry.flowEntryActions()
700 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800701 // - flowEntry.flowEntryUserState()
702 // - flowEntry.flowEntrySwitchState()
703 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700704 // - flowEntry.matchInPort()
705 // - flowEntry.matchEthernetFrameType()
706 // - flowEntry.matchSrcIPv4Net()
707 // - flowEntry.matchDstIPv4Net()
708 // - flowEntry.matchSrcMac()
709 // - flowEntry.matchDstMac()
710 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800711 //
712 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700713 if (flowEntry.flowEntryMatch().matchInPort())
714 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
715 if (flowEntry.flowEntryMatch().matchEthernetFrameType())
716 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
717 if (flowEntry.flowEntryMatch().matchSrcIPv4Net())
718 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
719 if (flowEntry.flowEntryMatch().matchDstIPv4Net())
720 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
721 if (flowEntry.flowEntryMatch().matchSrcMac())
722 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
723 if (flowEntry.flowEntryMatch().matchDstMac())
724 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
725
726 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
727 if (fa.actionOutput() != null)
728 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
729 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800730 // TODO: Hacks with hard-coded state names!
731 if (found)
732 flowEntryObj.setUserState("FE_USER_MODIFY");
733 else
734 flowEntryObj.setUserState("FE_USER_ADD");
735 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
736 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800737 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800738 // and FlowEntryErrorState.
739 //
740
741 // Flow Entries edges:
742 // Flow
743 // NextFE
744 // InPort
745 // OutPort
746 // Switch
747 if (! found)
748 flowObj.addFlowEntry(flowEntryObj);
749 }
750 conn.endTx(Transaction.COMMIT);
751
752 //
753 // TODO: We need a proper Flow ID allocation mechanism.
754 //
755 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700756
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800757 return true;
758 }
759
760 /**
761 * Delete a previously added flow.
762 *
763 * @param flowId the Flow ID of the flow to delete.
764 * @return true on success, otherwise false.
765 */
766 @Override
767 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700768 if (flowId.value() == measurementFlowId) {
769 modifiedMeasurementFlowTime = System.nanoTime();
770 }
771
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800772 IFlowPath flowObj = null;
773 //
774 // We just mark the entries for deletion,
775 // and let the switches remove each individual entry after
776 // it has been removed from the switches.
777 //
778 try {
779 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
780 != null) {
781 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
782 flowId.toString());
783 } else {
784 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
785 flowId.toString());
786 }
787 } catch (Exception e) {
788 // TODO: handle exceptions
789 conn.endTx(Transaction.ROLLBACK);
790 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
791 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700792 if (flowObj == null) {
793 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800794 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700795 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800796
797 //
798 // Find and mark for deletion all Flow Entries
799 //
800 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
801 boolean empty = true; // TODO: an ugly hack
802 for (IFlowEntry flowEntryObj : flowEntries) {
803 empty = false;
804 // flowObj.removeFlowEntry(flowEntryObj);
805 // conn.utils().removeFlowEntry(conn, flowEntryObj);
806 flowEntryObj.setUserState("FE_USER_DELETE");
807 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
808 }
809 // Remove from the database empty flows
810 if (empty)
811 conn.utils().removeFlowPath(conn, flowObj);
812 conn.endTx(Transaction.COMMIT);
813
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800814 return true;
815 }
816
817 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700818 * Clear the state for a previously added flow.
819 *
820 * @param flowId the Flow ID of the flow to clear.
821 * @return true on success, otherwise false.
822 */
823 @Override
824 public boolean clearFlow(FlowId flowId) {
825 IFlowPath flowObj = null;
826 try {
827 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
828 != null) {
829 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
830 flowId.toString());
831 } else {
832 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
833 flowId.toString());
834 }
835 } catch (Exception e) {
836 // TODO: handle exceptions
837 conn.endTx(Transaction.ROLLBACK);
838 log.error(":clearFlow FlowId:{} failed", flowId.toString());
839 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700840 if (flowObj == null) {
841 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700842 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700843 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700844
845 //
846 // Remove all Flow Entries
847 //
848 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
849 for (IFlowEntry flowEntryObj : flowEntries) {
850 flowObj.removeFlowEntry(flowEntryObj);
851 conn.utils().removeFlowEntry(conn, flowEntryObj);
852 }
853 // Remove the Flow itself
854 conn.utils().removeFlowPath(conn, flowObj);
855 conn.endTx(Transaction.COMMIT);
856
857 return true;
858 }
859
860 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800861 * Get a previously added flow.
862 *
863 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800864 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800865 */
866 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800867 public FlowPath getFlow(FlowId flowId) {
868 IFlowPath flowObj = null;
869 try {
870 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
871 != null) {
872 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
873 flowId.toString());
874 } else {
875 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
876 flowId.toString());
877 }
878 } catch (Exception e) {
879 // TODO: handle exceptions
880 conn.endTx(Transaction.ROLLBACK);
881 log.error(":getFlow FlowId:{} failed", flowId.toString());
882 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700883 if (flowObj == null) {
884 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800885 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700886 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800887
888 //
889 // Extract the Flow state
890 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800891 FlowPath flowPath = extractFlowPath(flowObj);
892 conn.endTx(Transaction.COMMIT);
893
894 return flowPath;
895 }
896
897 /**
898 * Get all previously added flows by a specific installer for a given
899 * data path endpoints.
900 *
901 * @param installerId the Caller ID of the installer of the flow to get.
902 * @param dataPathEndpoints the data path endpoints of the flow to get.
903 * @return the Flow Paths if found, otherwise null.
904 */
905 @Override
906 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
907 DataPathEndpoints dataPathEndpoints) {
908 //
909 // TODO: The implementation below is not optimal:
910 // We fetch all flows, and then return only the subset that match
911 // the query conditions.
912 // We should use the appropriate Titan/Gremlin query to filter-out
913 // the flows as appropriate.
914 //
915 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700916 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800917
918 if (allFlows == null) {
919 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700920 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800921 }
922
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800923 for (FlowPath flow : allFlows) {
924 //
925 // TODO: String-based comparison is sub-optimal.
926 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800927 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800928 //
929 if (! flow.installerId().toString().equals(installerId.toString()))
930 continue;
931 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
932 continue;
933 }
934 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
935 continue;
936 }
937 flowPaths.add(flow);
938 }
939
940 if (flowPaths.isEmpty()) {
941 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800942 } else {
943 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
944 }
945
946 return flowPaths;
947 }
948
949 /**
950 * Get all installed flows by all installers for given data path endpoints.
951 *
952 * @param dataPathEndpoints the data path endpoints of the flows to get.
953 * @return the Flow Paths if found, otherwise null.
954 */
955 @Override
956 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
957 //
958 // TODO: The implementation below is not optimal:
959 // We fetch all flows, and then return only the subset that match
960 // the query conditions.
961 // We should use the appropriate Titan/Gremlin query to filter-out
962 // the flows as appropriate.
963 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700964 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
965 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800966
967 if (allFlows == null) {
968 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700969 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800970 }
971
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800972 for (FlowPath flow : allFlows) {
973 //
974 // TODO: String-based comparison is sub-optimal.
975 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800976 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800977 //
978 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
979 continue;
980 }
981 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
982 continue;
983 }
984 flowPaths.add(flow);
985 }
986
987 if (flowPaths.isEmpty()) {
988 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800989 } else {
990 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
991 }
992
993 return flowPaths;
994 }
995
996 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700997 * Get summary of all installed flows by all installers in a given range
998 *
999 * @param flowId the data path endpoints of the flows to get.
1000 * @param maxFlows: the maximum number of flows to be returned
1001 * @return the Flow Paths if found, otherwise null.
1002 */
1003 @Override
1004 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1005 //
1006 // TODO: The implementation below is not optimal:
1007 // We fetch all flows, and then return only the subset that match
1008 // the query conditions.
1009 // We should use the appropriate Titan/Gremlin query to filter-out
1010 // the flows as appropriate.
1011 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001012 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1013
1014 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001015
1016 if (allFlows == null) {
1017 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001018 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001019 }
1020
1021 Collections.sort(allFlows);
1022
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001023 for (FlowPath flow : allFlows) {
1024
1025 // start from desired flowId
1026 if (flow.flowId().value() < flowId.value()) {
1027 continue;
1028 }
1029
1030 // Summarize by making null flow entry fields that are not relevant to report
1031 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1032 flowEntry.setFlowEntryActions(null);
1033 flowEntry.setFlowEntryMatch(null);
1034 }
1035
1036 flowPaths.add(flow);
1037 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1038 break;
1039 }
1040 }
1041
1042 if (flowPaths.isEmpty()) {
1043 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001044 } else {
1045 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1046 }
1047
1048 return flowPaths;
1049 }
1050
1051 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001052 * Get all installed flows by all installers.
1053 *
1054 * @return the Flow Paths if found, otherwise null.
1055 */
1056 @Override
1057 public ArrayList<FlowPath> getAllFlows() {
1058 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001059 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001060
1061 try {
1062 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1063 log.debug("Get all FlowPaths: found FlowPaths");
1064 } else {
1065 log.debug("Get all FlowPaths: no FlowPaths found");
1066 }
1067 } catch (Exception e) {
1068 // TODO: handle exceptions
1069 conn.endTx(Transaction.ROLLBACK);
1070 log.error(":getAllFlowPaths failed");
1071 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001072 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1073 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001074 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001075 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001076
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001077 for (IFlowPath flowObj : flowPathsObj) {
1078 //
1079 // Extract the Flow state
1080 //
1081 FlowPath flowPath = extractFlowPath(flowObj);
1082 flowPaths.add(flowPath);
1083 }
1084
1085 conn.endTx(Transaction.COMMIT);
1086
1087 return flowPaths;
1088 }
1089
1090 /**
1091 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1092 *
1093 * @param flowObj the object to extract the Flow Path State from.
1094 * @return the extracted Flow Path State.
1095 */
1096 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001097 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001098
1099 //
1100 // Extract the Flow state
1101 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001102 String flowIdStr = flowObj.getFlowId();
1103 String installerIdStr = flowObj.getInstallerId();
1104 String srcSwitchStr = flowObj.getSrcSwitch();
1105 Short srcPortStr = flowObj.getSrcPort();
1106 String dstSwitchStr = flowObj.getDstSwitch();
1107 Short dstPortStr = flowObj.getDstPort();
1108
1109 if ((flowIdStr == null) ||
1110 (installerIdStr == null) ||
1111 (srcSwitchStr == null) ||
1112 (srcPortStr == null) ||
1113 (dstSwitchStr == null) ||
1114 (dstPortStr == null)) {
1115 // TODO: A work-around, becauuse of some bogus database objects
1116 return null;
1117 }
1118
1119 flowPath.setFlowId(new FlowId(flowIdStr));
1120 flowPath.setInstallerId(new CallerId(installerIdStr));
1121 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
1122 flowPath.dataPath().srcPort().setPort(new Port(srcPortStr));
1123 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
1124 flowPath.dataPath().dstPort().setPort(new Port(dstPortStr));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001125
1126 //
1127 // Extract all Flow Entries
1128 //
1129 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1130 for (IFlowEntry flowEntryObj : flowEntries) {
1131 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001132 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1133 String switchDpidStr = flowEntryObj.getSwitchDpid();
1134 String userState = flowEntryObj.getUserState();
1135 String switchState = flowEntryObj.getSwitchState();
1136
1137 if ((flowEntryIdStr == null) ||
1138 (switchDpidStr == null) ||
1139 (userState == null) ||
1140 (switchState == null)) {
1141 // TODO: A work-around, becauuse of some bogus database objects
1142 continue;
1143 }
1144 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1145 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001146
1147 //
1148 // Extract the match conditions
1149 //
1150 FlowEntryMatch match = new FlowEntryMatch();
1151 Short matchInPort = flowEntryObj.getMatchInPort();
1152 if (matchInPort != null)
1153 match.enableInPort(new Port(matchInPort));
1154 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1155 if (matchEthernetFrameType != null)
1156 match.enableEthernetFrameType(matchEthernetFrameType);
1157 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1158 if (matchSrcIPv4Net != null)
1159 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1160 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1161 if (matchDstIPv4Net != null)
1162 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1163 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1164 if (matchSrcMac != null)
1165 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1166 String matchDstMac = flowEntryObj.getMatchDstMac();
1167 if (matchDstMac != null)
1168 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1169 flowEntry.setFlowEntryMatch(match);
1170
1171 //
1172 // Extract the actions
1173 //
1174 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1175 Short actionOutputPort = flowEntryObj.getActionOutput();
1176 if (actionOutputPort != null) {
1177 FlowEntryAction action = new FlowEntryAction();
1178 action.setActionOutput(new Port(actionOutputPort));
1179 actions.add(action);
1180 }
1181 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001182 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001183 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1184 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001185 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001186 // and FlowEntryErrorState.
1187 //
1188 flowPath.dataPath().flowEntries().add(flowEntry);
1189 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001190
1191 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001192 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001193
1194 /**
1195 * Add and maintain a shortest-path flow.
1196 *
1197 * NOTE: The Flow Path does NOT contain all flow entries.
1198 * Instead, it contains a single dummy flow entry that is used to
1199 * store the matching condition(s).
1200 * That entry is replaced by the appropriate entries from the
1201 * internally performed shortest-path computation.
1202 *
1203 * @param flowPath the Flow Path with the endpoints and the match
1204 * conditions to install.
1205 * @param flowId the return-by-reference Flow ID as assigned internally.
1206 * @return true on success, otherwise false.
1207 */
1208 @Override
1209 public boolean addAndMaintainShortestPathFlow(FlowPath flowPath,
1210 FlowId flowId) {
1211 //
1212 // Do the shortest path computation
1213 //
1214 DataPath dataPath =
1215 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1216 flowPath.dataPath().dstPort());
1217 if (dataPath == null)
1218 return false;
1219
1220 FlowEntryMatch userFlowEntryMatch = null;
1221 if (! flowPath.dataPath().flowEntries().isEmpty()) {
1222 userFlowEntryMatch = flowPath.dataPath().flowEntries().get(0).flowEntryMatch();
1223 }
1224
1225 //
1226 // Set the incoming port matching and the outgoing port output
1227 // actions for each flow entry.
1228 //
1229 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1230 // Set the incoming port matching
1231 FlowEntryMatch flowEntryMatch = null;
1232 if (userFlowEntryMatch != null)
1233 flowEntryMatch = new FlowEntryMatch(userFlowEntryMatch);
1234 else
1235 flowEntryMatch = new FlowEntryMatch();
1236 flowEntry.setFlowEntryMatch(flowEntryMatch);
1237 flowEntryMatch.enableInPort(flowEntry.inPort());
1238
1239 // Set the outgoing port output action
1240 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1241 if (flowEntryActions == null) {
1242 flowEntryActions = new ArrayList<FlowEntryAction>();
1243 flowEntry.setFlowEntryActions(flowEntryActions);
1244 }
1245 FlowEntryAction flowEntryAction = new FlowEntryAction();
1246 flowEntryAction.setActionOutput(flowEntry.outPort());
1247 flowEntryActions.add(flowEntryAction);
1248 }
1249
1250 //
1251 // Prepare the computed Flow Path
1252 //
1253 FlowPath resultFlowPath = new FlowPath();
1254 resultFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1255 resultFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1256 resultFlowPath.setDataPath(dataPath);
1257
1258 boolean returnValue = addFlow(resultFlowPath, flowId);
1259
1260 // TODO: Mark the flow for maintenance purpose
1261
1262 return (returnValue);
1263 }
1264
1265 /**
1266 * Create a Flow from port to port.
1267 *
1268 * TODO: We don't need it for now.
1269 *
1270 * @param src_port the source port.
1271 * @param dest_port the destination port.
1272 */
1273 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1274 // TODO: We don't need it for now.
1275 }
1276
1277 /**
1278 * Get all Flows matching a source and a destination port.
1279 *
1280 * TODO: Pankaj might be implementing it later.
1281 *
1282 * @param src_port the source port to match.
1283 * @param dest_port the destination port to match.
1284 * @return all flows matching the source and the destination port.
1285 */
1286 public Iterable<FlowPath> getFlows(IPortObject src_port,
1287 IPortObject dest_port) {
1288 // TODO: Pankaj might be implementing it later.
1289 return null;
1290 }
1291
1292 /**
1293 * Get all Flows going out from a port.
1294 *
1295 * TODO: We need it now: Pankaj
1296 *
1297 * @param port the port to match.
1298 * @return the list of flows that are going out from the port.
1299 */
1300 public Iterable<FlowPath> getFlows(IPortObject port) {
1301 // TODO: We need it now: Pankaj
1302 return null;
1303 }
1304
1305 /**
1306 * Reconcile all flows on inactive port (src port of link which might be
1307 * broken).
1308 *
1309 * TODO: We need it now: Pavlin
1310 *
1311 * @param src_port the port that has become inactive.
1312 */
1313 public void reconcileFlows(IPortObject src_port) {
1314 // TODO: We need it now: Pavlin
1315
1316 // TODO: It should call installFlowEntry() as appropriate.
1317 }
1318
1319 /**
1320 * Reconcile all flows between a source and a destination port.
1321 *
1322 * TODO: We don't need it for now.
1323 *
1324 * @param src_port the source port.
1325 * @param dest_port the destination port.
1326 */
1327 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1328 // TODO: We don't need it for now.
1329 }
1330
1331 /**
1332 * Compute the shortest path between a source and a destination ports.
1333 *
1334 * @param src_port the source port.
1335 * @param dest_port the destination port.
1336 * @return the computed shortest path between the source and the
1337 * destination ports. The flow entries in the path itself would
1338 * contain the incoming port matching and the outgoing port output
1339 * actions set. However, the path itself will NOT have the Flow ID,
1340 * Installer ID, and any additional matching conditions for the
1341 * flow entries (e.g., source or destination MAC address, etc).
1342 */
1343 public FlowPath computeFlowPath(IPortObject src_port,
1344 IPortObject dest_port) {
1345 //
1346 // Prepare the arguments
1347 //
1348 String dpidStr = src_port.getSwitch().getDPID();
1349 Dpid srcDpid = new Dpid(dpidStr);
1350 Port srcPort = new Port(src_port.getNumber());
1351
1352 dpidStr = dest_port.getSwitch().getDPID();
1353 Dpid dstDpid = new Dpid(dpidStr);
1354 Port dstPort = new Port(dest_port.getNumber());
1355
1356 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1357 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1358
1359 //
1360 // Do the shortest path computation
1361 //
1362 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1363 if (dataPath == null)
1364 return null;
1365
1366 //
1367 // Set the incoming port matching and the outgoing port output
1368 // actions for each flow entry.
1369 //
1370 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1371 // Set the incoming port matching
1372 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1373 if (flowEntryMatch == null) {
1374 flowEntryMatch = new FlowEntryMatch();
1375 flowEntry.setFlowEntryMatch(flowEntryMatch);
1376 }
1377 flowEntryMatch.enableInPort(flowEntry.inPort());
1378
1379 // Set the outgoing port output action
1380 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1381 if (flowEntryActions == null) {
1382 flowEntryActions = new ArrayList<FlowEntryAction>();
1383 flowEntry.setFlowEntryActions(flowEntryActions);
1384 }
1385 FlowEntryAction flowEntryAction = new FlowEntryAction();
1386 flowEntryAction.setActionOutput(flowEntry.outPort());
1387 flowEntryActions.add(flowEntryAction);
1388 }
1389
1390 //
1391 // Prepare the return result
1392 //
1393 FlowPath flowPath = new FlowPath();
1394 flowPath.setDataPath(dataPath);
1395
1396 return flowPath;
1397 }
1398
1399 /**
1400 * Get all Flow Entries of a Flow.
1401 *
1402 * @param flow the flow whose flow entries should be returned.
1403 * @return the flow entries of the flow.
1404 */
1405 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1406 return flow.dataPath().flowEntries();
1407 }
1408
1409 /**
1410 * Install a Flow Entry on a switch.
1411 *
1412 * @param mySwitches the DPID-to-Switch mapping for the switches
1413 * controlled by this controller.
1414 * @param flowEntry the flow entry to install.
1415 * @return true on success, otherwise false.
1416 */
1417 public boolean installFlowEntry(Map<Long, IOFSwitch> mySwitches,
1418 FlowEntry flowEntry) {
1419 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1420 if (mySwitch == null) {
1421 // Not my switch
1422 return (installRemoteFlowEntry(flowEntry));
1423 }
1424
1425 //
1426 // Create the OpenFlow Flow Modification Entry to push
1427 //
1428 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1429 .getMessage(OFType.FLOW_MOD);
1430 long cookie = flowEntry.flowEntryId().value();
1431
1432 short flowModCommand = OFFlowMod.OFPFC_ADD;
1433 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1434 flowModCommand = OFFlowMod.OFPFC_ADD;
1435 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1436 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1437 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1438 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1439 } else {
1440 // Unknown user state. Ignore the entry
1441 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1442 flowEntry.flowEntryId().toString(),
1443 flowEntry.flowEntryUserState());
1444 return false;
1445 }
1446
1447 //
1448 // Fetch the match conditions
1449 //
1450 OFMatch match = new OFMatch();
1451 match.setWildcards(OFMatch.OFPFW_ALL);
1452 Port matchInPort = flowEntry.flowEntryMatch().inPort();
1453 if (matchInPort != null) {
1454 match.setInputPort(matchInPort.value());
1455 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1456 }
1457 Short matchEthernetFrameType =
1458 flowEntry.flowEntryMatch().ethernetFrameType();
1459 if (matchEthernetFrameType != null) {
1460 match.setDataLayerType(matchEthernetFrameType);
1461 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1462 }
1463 IPv4Net matchSrcIPv4Net = flowEntry.flowEntryMatch().srcIPv4Net();
1464 if (matchSrcIPv4Net != null) {
1465 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1466 }
1467 IPv4Net matchDstIPv4Net = flowEntry.flowEntryMatch().dstIPv4Net();
1468 if (matchDstIPv4Net != null) {
1469 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1470 }
1471 MACAddress matchSrcMac = flowEntry.flowEntryMatch().srcMac();
1472 if (matchSrcMac != null) {
1473 match.setDataLayerSource(matchSrcMac.toString());
1474 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1475 }
1476 MACAddress matchDstMac = flowEntry.flowEntryMatch().dstMac();
1477 if (matchDstMac != null) {
1478 match.setDataLayerDestination(matchDstMac.toString());
1479 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1480 }
1481
1482 //
1483 // Fetch the actions
1484 //
1485 // TODO: For now we support only the "OUTPUT" actions.
1486 //
1487 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1488 List<OFAction> actions = new ArrayList<OFAction>();
1489 ArrayList<FlowEntryAction> flowEntryActions =
1490 flowEntry.flowEntryActions();
1491 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1492 FlowEntryAction.ActionOutput actionOutput =
1493 flowEntryAction.actionOutput();
1494 if (actionOutput != null) {
1495 short actionOutputPort = actionOutput.port().value();
1496 OFActionOutput action = new OFActionOutput();
1497 // XXX: The max length is hard-coded for now
1498 action.setMaxLength((short)0xffff);
1499 action.setPort(actionOutputPort);
1500 actions.add(action);
1501 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1502 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1503 fm.setOutPort(actionOutputPort);
1504 }
1505 }
1506 }
1507
1508 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1509 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1510 .setPriority(PRIORITY_DEFAULT)
1511 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1512 .setCookie(cookie)
1513 .setCommand(flowModCommand)
1514 .setMatch(match)
1515 .setActions(actions)
1516 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1517
1518 //
1519 // TODO: Set the following flag
1520 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1521 // See method ForwardingBase::pushRoute()
1522 //
1523
1524 //
1525 // Write the message to the switch
1526 //
1527 try {
1528 messageDamper.write(mySwitch, fm, null);
1529 mySwitch.flush();
1530 } catch (IOException e) {
1531 log.error("Failure writing flow mod from network map", e);
1532 return false;
1533 }
1534 return true;
1535 }
1536
1537 /**
1538 * Remove a Flow Entry from a switch.
1539 *
1540 * TODO: We need it now: Pavlin
1541 * - Remove only for local switches
1542 * - It will call the removeRemoteFlowEntry() for remote switches.
1543 * - To be called by reconcileFlow()
1544 *
1545 * @param entry the flow entry to remove.
1546 */
1547 public void removeFlowEntry(FlowEntry entry) {
1548 // TODO: We need it now: Pavlin
1549 // - Remove only for local switches
1550 // - It will call the removeRemoteFlowEntry() for remote switches.
1551 // - To be called by reconcileFlow()
1552 }
1553
1554 /**
1555 * Install a Flow Entry on a remote controller.
1556 *
1557 * TODO: We need it now: Jono
1558 * - For now it will make a REST call to the remote controller.
1559 * - Internally, it needs to know the name of the remote controller.
1560 *
1561 * @param entry the flow entry to install.
1562 * @return true on success, otherwise false.
1563 */
1564 public boolean installRemoteFlowEntry(FlowEntry entry) {
1565 // TODO: We need it now: Jono
1566 // - For now it will make a REST call to the remote controller.
1567 // - Internally, it needs to know the name of the remote controller.
1568 return true;
1569 }
1570
1571 /**
1572 * Remove a flow entry on a remote controller.
1573 *
1574 * TODO: We need it now: Jono
1575 * - For now it will make a REST call to the remote controller.
1576 * - Internally, it needs to know the name of the remote controller.
1577 *
1578 * @param entry the flow entry to remove.
1579 */
1580 public void removeRemoteFlowEntry(FlowEntry entry) {
1581 // TODO: We need it now: Jono
1582 // - For now it will make a REST call to the remote controller.
1583 // - Internally, it needs to know the name of the remote controller.
1584 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001585}