blob: d1eae4d56d26c34fb04b2b685c2c7ccabcdf7eea [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 Radoslavov0b22d0e2013-04-02 01:12:46 +00006import java.util.Collections;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08007import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08008import java.util.HashMap;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07009import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000010import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080012import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000013import java.util.Random;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070014import java.util.TreeMap;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070015import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070017import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080018import java.util.concurrent.ScheduledExecutorService;
19import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070020import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080022
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080023import net.floodlightcontroller.core.IFloodlightProviderService;
24import net.floodlightcontroller.core.INetMapStorage;
25import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
26import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070027import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070028import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070029import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080030import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080031import net.floodlightcontroller.core.module.FloodlightModuleContext;
32import net.floodlightcontroller.core.module.FloodlightModuleException;
33import net.floodlightcontroller.core.module.IFloodlightModule;
34import net.floodlightcontroller.core.module.IFloodlightService;
35import net.floodlightcontroller.flowcache.IFlowService;
36import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
37import net.floodlightcontroller.restserver.IRestApiService;
38import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.DataPath;
40import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080041import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080042import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070043import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080044import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070045import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046import net.floodlightcontroller.util.FlowEntrySwitchState;
47import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080048import net.floodlightcontroller.util.FlowId;
49import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070050import net.floodlightcontroller.util.IPv4Net;
51import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080052import net.floodlightcontroller.util.OFMessageDamper;
53import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070054import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070055import net.onrc.onos.flow.IFlowManager;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056import net.onrc.onos.util.GraphDBConnection;
57import net.onrc.onos.util.GraphDBConnection.Transaction;
58
59import org.openflow.protocol.OFFlowMod;
60import org.openflow.protocol.OFMatch;
61import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070062import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080063import org.openflow.protocol.OFType;
64import org.openflow.protocol.action.OFAction;
65import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080066
67import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070070public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071
72 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080073
74 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080075 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070076 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070077 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080078
79 protected OFMessageDamper messageDamper;
80
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070081 //
82 // TODO: Values copied from elsewhere (class LearningSwitch).
83 // The local copy should go away!
84 //
85 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
86 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
87 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
88 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
89 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080090
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000091 // Flow Entry ID generation state
92 private static Random randomGenerator = new Random();
93 private static int nextFlowEntryIdPrefix = 0;
94 private static int nextFlowEntryIdSuffix = 0;
95 private static long nextFlowEntryId = 0;
96
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070097 private static long measurementFlowId = 100000;
98 private static String measurementFlowIdStr = "0x186a0"; // 100000
99 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700100
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800101 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800102 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
103
104 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700105 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800106 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700107 private final ScheduledExecutorService measureMapReaderScheduler =
108 Executors.newScheduledThreadPool(1);
109 private final ScheduledExecutorService mapReaderScheduler =
110 Executors.newScheduledThreadPool(1);
111
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700112 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
113 private ThreadPoolExecutor shortestPathExecutor =
114 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
115
116 class ShortestPathTask implements Runnable {
117 private int hint;
118 private ITopoRouteService topoRouteService;
119 private ArrayList<DataPath> dpList;
120
121 public ShortestPathTask(int hint,
122 ITopoRouteService topoRouteService,
123 ArrayList<DataPath> dpList) {
124 this.hint = hint;
125 this.topoRouteService = topoRouteService;
126 this.dpList = dpList;
127 }
128
129 @Override
130 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700131 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700132 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
133 log.debug(logMsg);
134 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700135 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700136 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700137 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700138 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700139 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700140 long estimatedTime = System.nanoTime() - startTime;
141 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
142 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
143 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700144 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700145 }
146 }
147
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700148 final Runnable measureShortestPath = new Runnable() {
149 public void run() {
150 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
151 if (floodlightProvider == null) {
152 log.debug("FloodlightProvider service not found!");
153 return;
154 }
155
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700156 if (topoRouteService == null) {
157 log.debug("Topology Route Service not found");
158 return;
159 }
160
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700161 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
162 if (leftoverQueueSize > 0) {
163 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
164 log.debug(logMsg);
165 return;
166 }
167 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
168
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700169 //
170 // Recompute the Shortest Paths for all Flows
171 //
172 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700173 int hint = 0;
174 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700175 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700176
177 topoRouteService.prepareShortestPathTopo();
178
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700179 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
180 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700181 FlowId flowId = new FlowId(flowPathObj.getFlowId());
182
183 // log.debug("Found Path {}", flowId.toString());
184 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
185 Port srcPort = new Port(flowPathObj.getSrcPort());
186 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
187 Port dstPort = new Port(flowPathObj.getDstPort());
188 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
189 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700190
191 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700192 DataPath dp = new DataPath();
193 dp.setSrcPort(srcSwitchPort);
194 dp.setDstPort(dstSwitchPort);
195 dpList.add(dp);
196 if ((dpList.size() % 10) == 0) {
197 shortestPathExecutor.execute(
198 new ShortestPathTask(hint, topoRouteService,
199 dpList));
200 dpList = new ArrayList<DataPath>();
201 hint++;
202 }
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700203 */
204
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700205 DataPath dataPath =
206 topoRouteService.getTopoShortestPath(srcSwitchPort,
207 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700208 counter++;
209 }
210 if (dpList.size() > 0) {
211 shortestPathExecutor.execute(
212 new ShortestPathTask(hint, topoRouteService,
213 dpList));
214 }
215
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700216 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700217 // Wait for all tasks to finish
218 try {
219 while (shortestPathExecutor.getQueue().size() > 0) {
220 Thread.sleep(100);
221 }
222 } catch (InterruptedException ex) {
223 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700224 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700225 */
226
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700227 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700228 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700229
230 long estimatedTime = System.nanoTime() - startTime;
231 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
232 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
233 log.debug(logMsg);
234 }
235 };
236
237 final Runnable measureMapReader = new Runnable() {
238 public void run() {
239 if (floodlightProvider == null) {
240 log.debug("FloodlightProvider service not found!");
241 return;
242 }
243
244 //
245 // Fetch all Flow Entries
246 //
247 int counter = 0;
248 long startTime = System.nanoTime();
249 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
250 for (IFlowEntry flowEntryObj : allFlowEntries) {
251 counter++;
252 FlowEntryId flowEntryId =
253 new FlowEntryId(flowEntryObj.getFlowEntryId());
254 String userState = flowEntryObj.getUserState();
255 String switchState = flowEntryObj.getSwitchState();
256 }
257 conn.endTx(Transaction.COMMIT);
258
259 long estimatedTime = System.nanoTime() - startTime;
260 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
261 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
262 log.debug(logMsg);
263 }
264 };
265
266 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800267 public void run() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800268 if (floodlightProvider == null) {
269 log.debug("FloodlightProvider service not found!");
270 return;
271 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000272 Map<Long, IOFSwitch> mySwitches =
273 floodlightProvider.getSwitches();
274 Map<Long, IFlowEntry> myFlowEntries =
275 new TreeMap<Long, IFlowEntry>();
276 LinkedList<IFlowEntry> deleteFlowEntries =
277 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700278
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700279
280 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700281 // Fetch all Flow Entries and select only my Flow Entries
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000282 // that need to be undated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700283 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000284 Iterable<IFlowEntry> allFlowEntries =
285 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700286 for (IFlowEntry flowEntryObj : allFlowEntries) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000287 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700288 String userState = flowEntryObj.getUserState();
289 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000290 String dpidStr = flowEntryObj.getSwitchDpid();
291 if ((flowEntryIdStr == null) ||
292 (userState == null) ||
293 (switchState == null) ||
294 (dpidStr == null)) {
295 log.debug("IGNORING Flow Entry entry with null fields");
296 continue;
297 }
298 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
299 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800300
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000301 /*
302 log.debug("Found Flow Entry Id = {} {}",
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700303 flowEntryId.toString(),
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000304 "DPID = " + dpid.toString() +
305 " User State: " + userState +
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700306 " Switch State: " + switchState);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000307 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800308
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000309 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
310 continue; // Ignore the entry: nothing to do
311
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800312 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000313 if (mySwitch == null)
314 continue; // Ignore the entry: not my switch
315
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700316 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
317 }
318
319 //
320 // Process my Flow Entries
321 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700322 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700323 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
324 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700325 // Code for measurement purpose
326 {
327 IFlowPath flowObj =
328 conn.utils().getFlowPathByFlowEntry(conn,
329 flowEntryObj);
330 if ((flowObj != null) &&
331 flowObj.getFlowId().equals(measurementFlowIdStr)) {
332 processed_measurement_flow = true;
333 }
334 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700335
336 //
337 // TODO: Eliminate the re-fetching of flowEntryId,
338 // userState, switchState, and dpid from the flowEntryObj.
339 //
340 FlowEntryId flowEntryId =
341 new FlowEntryId(flowEntryObj.getFlowEntryId());
342 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
343 String userState = flowEntryObj.getUserState();
344 String switchState = flowEntryObj.getSwitchState();
345 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000346 if (mySwitch == null)
347 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800348
349 //
350 // Create the Open Flow Flow Modification Entry to push
351 //
352 OFFlowMod fm =
353 (OFFlowMod) floodlightProvider.getOFMessageFactory()
354 .getMessage(OFType.FLOW_MOD);
355 long cookie = flowEntryId.value();
356
357 short flowModCommand = OFFlowMod.OFPFC_ADD;
358 if (userState.equals("FE_USER_ADD")) {
359 flowModCommand = OFFlowMod.OFPFC_ADD;
360 } else if (userState.equals("FE_USER_MODIFY")) {
361 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
362 } else if (userState.equals("FE_USER_DELETE")) {
363 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
364 } else {
365 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700366 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
367 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800368 continue;
369 }
370
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700371 //
372 // Fetch the match conditions
373 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800374 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700375 match.setWildcards(OFMatch.OFPFW_ALL);
376 Short matchInPort = flowEntryObj.getMatchInPort();
377 if (matchInPort != null) {
378 match.setInputPort(matchInPort);
379 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
380 }
381 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
382 if (matchEthernetFrameType != null) {
383 match.setDataLayerType(matchEthernetFrameType);
384 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
385 }
386 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
387 if (matchSrcIPv4Net != null) {
388 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
389 }
390 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
391 if (matchDstIPv4Net != null) {
392 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
393 }
394 String matchSrcMac = flowEntryObj.getMatchSrcMac();
395 if (matchSrcMac != null) {
396 match.setDataLayerSource(matchSrcMac);
397 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
398 }
399 String matchDstMac = flowEntryObj.getMatchDstMac();
400 if (matchDstMac != null) {
401 match.setDataLayerDestination(matchDstMac);
402 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
403 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700404
405 //
406 // Fetch the actions
407 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800408 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700409 Short actionOutputPort = flowEntryObj.getActionOutput();
410 if (actionOutputPort != null) {
411 OFActionOutput action = new OFActionOutput();
412 // XXX: The max length is hard-coded for now
413 action.setMaxLength((short)0xffff);
414 action.setPort(actionOutputPort);
415 actions.add(action);
416 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800417
418 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
419 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700420 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800421 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
422 .setCookie(cookie)
423 .setCommand(flowModCommand)
424 .setMatch(match)
425 .setActions(actions)
426 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700427 fm.setOutPort(OFPort.OFPP_NONE.getValue());
428 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
429 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
430 if (actionOutputPort != null)
431 fm.setOutPort(actionOutputPort);
432 }
433
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800434 //
435 // TODO: Set the following flag
436 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
437 // See method ForwardingBase::pushRoute()
438 //
439 try {
440 messageDamper.write(mySwitch, fm, null);
441 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000442 //
443 // TODO: We should use the OpenFlow Barrier mechanism
444 // to check for errors, and update the SwitchState
445 // for a flow entry after the Barrier message is
446 // is received.
447 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800448 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
449 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000450 // An entry that needs to be deleted.
451 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800452 }
453 } catch (IOException e) {
454 log.error("Failure writing flow mod from network map", e);
455 }
456 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000457
458 //
459 // Delete all entries marked for deletion
460 //
461 // TODO: We should use the OpenFlow Barrier mechanism
462 // to check for errors, and delete the Flow Entries after the
463 // Barrier message is received.
464 //
465 while (! deleteFlowEntries.isEmpty()) {
466 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
467 IFlowPath flowObj =
468 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
469 if (flowObj == null) {
470 log.debug("Did not find FlowPath to be deleted");
471 continue;
472 }
473 flowObj.removeFlowEntry(flowEntryObj);
474 conn.utils().removeFlowEntry(conn, flowEntryObj);
475
476 // Test whether the last flow entry
477 Iterable<IFlowEntry> tmpflowEntries =
478 flowObj.getFlowEntries();
479 boolean found = false;
480 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
481 found = true;
482 break;
483 }
484 if (! found) {
485 // Remove the Flow Path as well
486 conn.utils().removeFlowPath(conn, flowObj);
487 }
488 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700489
490
491 //
492 // Fetch and recompute the Shortest Path for those
493 // Flow Paths this controller is responsible for.
494 //
495
496 /*
497 * TODO: For now, the computation of the reconciliation is
498 * commented-out.
499 */
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700500 topoRouteService.prepareShortestPathTopo();
501 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
502 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
503 for (IFlowPath flowPathObj : allFlowPaths) {
504 if (flowPathObj == null)
505 continue;
506 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
507 if (dataPathSummaryStr == null)
508 continue; // Could be invalid entry?
509 if (dataPathSummaryStr.isEmpty())
510 continue; // No need to maintain this flow
511
512 // Fetch the fields needed to recompute the shortest path
513 String flowIdStr = flowPathObj.getFlowId();
514 String srcDpidStr = flowPathObj.getSrcSwitch();
515 Short srcPortShort = flowPathObj.getSrcPort();
516 String dstDpidStr = flowPathObj.getDstSwitch();
517 Short dstPortShort = flowPathObj.getDstPort();
518 if ((flowIdStr == null) ||
519 (srcDpidStr == null) ||
520 (srcPortShort == null) ||
521 (dstDpidStr == null) ||
522 (dstPortShort == null)) {
523 log.debug("IGNORING Flow Path entry with null fields");
524 continue;
525 }
526
527 FlowId flowId = new FlowId(flowIdStr);
528 Dpid srcDpid = new Dpid(srcDpidStr);
529 Port srcPort = new Port(srcPortShort);
530 Dpid dstDpid = new Dpid(dstDpidStr);
531 Port dstPort = new Port(dstPortShort);
532 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
533 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700534 //
535 // NOTE: Using here the regular getShortestPath() method
536 // won't work here, because that method calls internally
537 // "conn.endTx(Transaction.COMMIT)", and that will
538 // invalidate all handlers to the Titan database.
539 // If we want to experiment with calling here
540 // getShortestPath(), we need to refactor that code
541 // to avoid closing the transaction.
542 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700543 DataPath dataPath =
544 topoRouteService.getTopoShortestPath(srcSwitchPort,
545 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000546 if (dataPath == null) {
547 // We need the DataPath to compare the paths
548 dataPath = new DataPath();
549 dataPath.setSrcPort(srcSwitchPort);
550 dataPath.setDstPort(dstSwitchPort);
551 }
552
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700553 String newDataPathSummaryStr = dataPath.dataPathSummary();
554 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
555 continue; // Nothing changed
556
557 //
558 // Use the source DPID as a heuristic to decide
559 // which controller is responsible for maintaining the
560 // shortest path.
561 // NOTE: This heuristic is error-prone: if the switch
562 // goes away and no controller is responsible for that
563 // switch, then the original Flow Path is not cleaned-up
564 //
565 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
566 if (mySwitch == null)
567 continue; // Ignore: not my responsibility
568
569 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
570 flowId.toString());
571 flowObjSet.add(flowPathObj);
572 }
573 reconcileFlows(flowObjSet);
574 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700575
576
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800577 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700578
579 if (processed_measurement_flow) {
580 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
581 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
582 (double)estimatedTime / 1000000000 + " sec";
583 log.debug(logMsg);
584 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800585 }
586 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700587
588 /*
589 final ScheduledFuture<?> measureShortestPathHandle =
590 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
591 */
592
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700593 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700594 final ScheduledFuture<?> measureMapReaderHandle =
595 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700596 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700597
598 final ScheduledFuture<?> mapReaderHandle =
599 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800600
601 @Override
602 public void init(String conf) {
603 conn = GraphDBConnection.getInstance(conf);
604 }
605
606 public void finalize() {
607 close();
608 }
609
610 @Override
611 public void close() {
612 conn.close();
613 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800614
615 @Override
616 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
617 Collection<Class<? extends IFloodlightService>> l =
618 new ArrayList<Class<? extends IFloodlightService>>();
619 l.add(IFlowService.class);
620 return l;
621 }
622
623 @Override
624 public Map<Class<? extends IFloodlightService>, IFloodlightService>
625 getServiceImpls() {
626 Map<Class<? extends IFloodlightService>,
627 IFloodlightService> m =
628 new HashMap<Class<? extends IFloodlightService>,
629 IFloodlightService>();
630 m.put(IFlowService.class, this);
631 return m;
632 }
633
634 @Override
635 public Collection<Class<? extends IFloodlightService>>
636 getModuleDependencies() {
637 Collection<Class<? extends IFloodlightService>> l =
638 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800639 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700640 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800641 l.add(IRestApiService.class);
642 return l;
643 }
644
645 @Override
646 public void init(FloodlightModuleContext context)
647 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700648 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800649 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700650 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800651 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800652 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
653 EnumSet.of(OFType.FLOW_MOD),
654 OFMESSAGE_DAMPER_TIMEOUT);
655 // TODO: An ugly hack!
656 String conf = "/tmp/cassandra.titan";
657 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800658 }
659
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000660 private long getNextFlowEntryId() {
661 //
662 // Generate the next Flow Entry ID.
663 // NOTE: For now, the higher 32 bits are random, and
664 // the lower 32 bits are sequential.
665 // In the future, we need a better allocation mechanism.
666 //
667 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
668 nextFlowEntryIdPrefix = randomGenerator.nextInt();
669 nextFlowEntryIdSuffix = 0;
670 } else {
671 nextFlowEntryIdSuffix++;
672 }
673 long result = (long)nextFlowEntryIdPrefix << 32;
674 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
675 return result;
676 }
677
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800678 @Override
679 public void startUp(FloodlightModuleContext context) {
680 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700681
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000682 // Initialize the Flow Entry ID generator
683 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800684 }
685
686 /**
687 * Add a flow.
688 *
689 * Internally, ONOS will automatically register the installer for
690 * receiving Flow Path Notifications for that path.
691 *
692 * @param flowPath the Flow Path to install.
693 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700694 * @param dataPathSummaryStr the data path summary string if the added
695 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800696 * @return true on success, otherwise false.
697 */
698 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700699 public boolean addFlow(FlowPath flowPath, FlowId flowId,
700 String dataPathSummaryStr) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700701 if (flowPath.flowId().value() == measurementFlowId) {
702 modifiedMeasurementFlowTime = System.nanoTime();
703 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800704
705 //
706 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700707 // Right now every new flow entry gets a new flow entry ID
708 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800709 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800710 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000711 long id = getNextFlowEntryId();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800712 flowEntry.setFlowEntryId(new FlowEntryId(id));
713 }
714
715 IFlowPath flowObj = null;
716 try {
717 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
718 != null) {
719 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
720 flowPath.flowId().toString());
721 } else {
722 flowObj = conn.utils().newFlowPath(conn);
723 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
724 flowPath.flowId().toString());
725 }
726 } catch (Exception e) {
727 // TODO: handle exceptions
728 conn.endTx(Transaction.ROLLBACK);
729 log.error(":addFlow FlowId:{} failed",
730 flowPath.flowId().toString());
731 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700732 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000733 log.error(":addFlow FlowId:{} failed: Flow object not created",
734 flowPath.flowId().toString());
735 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800736 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700737 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800738
739 //
740 // Set the Flow key:
741 // - flowId
742 //
743 flowObj.setFlowId(flowPath.flowId().toString());
744 flowObj.setType("flow");
745
746 //
747 // Set the Flow attributes:
748 // - flowPath.installerId()
749 // - flowPath.dataPath().srcPort()
750 // - flowPath.dataPath().dstPort()
751 //
752 flowObj.setInstallerId(flowPath.installerId().toString());
753 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
754 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
755 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
756 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
757
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700758 if (dataPathSummaryStr != null) {
759 flowObj.setDataPathSummary(dataPathSummaryStr);
760 } else {
761 flowObj.setDataPathSummary("");
762 }
763
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800764 // Flow edges:
765 // HeadFE
766
767
768 //
769 // Flow Entries:
770 // flowPath.dataPath().flowEntries()
771 //
772 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
773 IFlowEntry flowEntryObj = null;
774 boolean found = false;
775 try {
776 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
777 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
778 flowEntry.flowEntryId().toString());
779 found = true;
780 } else {
781 flowEntryObj = conn.utils().newFlowEntry(conn);
782 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
783 flowEntry.flowEntryId().toString());
784 }
785 } catch (Exception e) {
786 // TODO: handle exceptions
787 conn.endTx(Transaction.ROLLBACK);
788 log.error(":addFlow FlowEntryId:{} failed",
789 flowEntry.flowEntryId().toString());
790 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700791 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000792 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
793 flowEntry.flowEntryId().toString());
794 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800795 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700796 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800797
798 //
799 // Set the Flow Entry key:
800 // - flowEntry.flowEntryId()
801 //
802 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
803 flowEntryObj.setType("flow_entry");
804
805 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700806 // Set the Flow Entry Edges and attributes:
807 // - Switch edge
808 // - InPort edge
809 // - OutPort edge
810 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800811 // - flowEntry.flowEntryMatch()
812 // - flowEntry.flowEntryActions()
813 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800814 // - flowEntry.flowEntryUserState()
815 // - flowEntry.flowEntrySwitchState()
816 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700817 // - flowEntry.matchInPort()
818 // - flowEntry.matchEthernetFrameType()
819 // - flowEntry.matchSrcIPv4Net()
820 // - flowEntry.matchDstIPv4Net()
821 // - flowEntry.matchSrcMac()
822 // - flowEntry.matchDstMac()
823 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800824 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700825 ISwitchObject sw =
826 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800827 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700828 flowEntryObj.setSwitch(sw);
829 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700830 IPortObject inport =
831 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
832 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700833 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
834 flowEntryObj.setInPort(inport);
835 }
836 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
837 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
838 }
839 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
840 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
841 }
842 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
843 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
844 }
845 if (flowEntry.flowEntryMatch().matchSrcMac()) {
846 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
847 }
848 if (flowEntry.flowEntryMatch().matchDstMac()) {
849 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
850 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700851
852 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700853 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700854 IPortObject outport =
855 conn.utils().searchPort(conn,
856 flowEntry.dpid().toString(),
857 fa.actionOutput().port().value());
858 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
859 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700860 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700861 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800862 // TODO: Hacks with hard-coded state names!
863 if (found)
864 flowEntryObj.setUserState("FE_USER_MODIFY");
865 else
866 flowEntryObj.setUserState("FE_USER_ADD");
867 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
868 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700869 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800870 //
871
872 // Flow Entries edges:
873 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700874 // NextFE (TODO)
875 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800876 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700877 flowEntryObj.setFlow(flowObj);
878 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800879 }
880 conn.endTx(Transaction.COMMIT);
881
882 //
883 // TODO: We need a proper Flow ID allocation mechanism.
884 //
885 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700886
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800887 return true;
888 }
889
890 /**
891 * Delete a previously added flow.
892 *
893 * @param flowId the Flow ID of the flow to delete.
894 * @return true on success, otherwise false.
895 */
896 @Override
897 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700898 if (flowId.value() == measurementFlowId) {
899 modifiedMeasurementFlowTime = System.nanoTime();
900 }
901
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800902 IFlowPath flowObj = null;
903 //
904 // We just mark the entries for deletion,
905 // and let the switches remove each individual entry after
906 // it has been removed from the switches.
907 //
908 try {
909 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
910 != null) {
911 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
912 flowId.toString());
913 } else {
914 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
915 flowId.toString());
916 }
917 } catch (Exception e) {
918 // TODO: handle exceptions
919 conn.endTx(Transaction.ROLLBACK);
920 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
921 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700922 if (flowObj == null) {
923 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800924 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700925 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800926
927 //
928 // Find and mark for deletion all Flow Entries
929 //
930 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
931 boolean empty = true; // TODO: an ugly hack
932 for (IFlowEntry flowEntryObj : flowEntries) {
933 empty = false;
934 // flowObj.removeFlowEntry(flowEntryObj);
935 // conn.utils().removeFlowEntry(conn, flowEntryObj);
936 flowEntryObj.setUserState("FE_USER_DELETE");
937 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
938 }
939 // Remove from the database empty flows
940 if (empty)
941 conn.utils().removeFlowPath(conn, flowObj);
942 conn.endTx(Transaction.COMMIT);
943
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800944 return true;
945 }
946
947 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700948 * Clear the state for a previously added flow.
949 *
950 * @param flowId the Flow ID of the flow to clear.
951 * @return true on success, otherwise false.
952 */
953 @Override
954 public boolean clearFlow(FlowId flowId) {
955 IFlowPath flowObj = null;
956 try {
957 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
958 != null) {
959 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
960 flowId.toString());
961 } else {
962 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
963 flowId.toString());
964 }
965 } catch (Exception e) {
966 // TODO: handle exceptions
967 conn.endTx(Transaction.ROLLBACK);
968 log.error(":clearFlow FlowId:{} failed", flowId.toString());
969 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700970 if (flowObj == null) {
971 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700972 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700973 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700974
975 //
976 // Remove all Flow Entries
977 //
978 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
979 for (IFlowEntry flowEntryObj : flowEntries) {
980 flowObj.removeFlowEntry(flowEntryObj);
981 conn.utils().removeFlowEntry(conn, flowEntryObj);
982 }
983 // Remove the Flow itself
984 conn.utils().removeFlowPath(conn, flowObj);
985 conn.endTx(Transaction.COMMIT);
986
987 return true;
988 }
989
990 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800991 * Get a previously added flow.
992 *
993 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800994 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800995 */
996 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800997 public FlowPath getFlow(FlowId flowId) {
998 IFlowPath flowObj = null;
999 try {
1000 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
1001 != null) {
1002 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1003 flowId.toString());
1004 } else {
1005 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1006 flowId.toString());
1007 }
1008 } catch (Exception e) {
1009 // TODO: handle exceptions
1010 conn.endTx(Transaction.ROLLBACK);
1011 log.error(":getFlow FlowId:{} failed", flowId.toString());
1012 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001013 if (flowObj == null) {
1014 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001015 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001016 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001017
1018 //
1019 // Extract the Flow state
1020 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001021 FlowPath flowPath = extractFlowPath(flowObj);
1022 conn.endTx(Transaction.COMMIT);
1023
1024 return flowPath;
1025 }
1026
1027 /**
1028 * Get all previously added flows by a specific installer for a given
1029 * data path endpoints.
1030 *
1031 * @param installerId the Caller ID of the installer of the flow to get.
1032 * @param dataPathEndpoints the data path endpoints of the flow to get.
1033 * @return the Flow Paths if found, otherwise null.
1034 */
1035 @Override
1036 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1037 DataPathEndpoints dataPathEndpoints) {
1038 //
1039 // TODO: The implementation below is not optimal:
1040 // We fetch all flows, and then return only the subset that match
1041 // the query conditions.
1042 // We should use the appropriate Titan/Gremlin query to filter-out
1043 // the flows as appropriate.
1044 //
1045 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001046 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001047
1048 if (allFlows == null) {
1049 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001050 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001051 }
1052
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001053 for (FlowPath flow : allFlows) {
1054 //
1055 // TODO: String-based comparison is sub-optimal.
1056 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001057 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001058 //
1059 if (! flow.installerId().toString().equals(installerId.toString()))
1060 continue;
1061 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1062 continue;
1063 }
1064 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1065 continue;
1066 }
1067 flowPaths.add(flow);
1068 }
1069
1070 if (flowPaths.isEmpty()) {
1071 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001072 } else {
1073 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1074 }
1075
1076 return flowPaths;
1077 }
1078
1079 /**
1080 * Get all installed flows by all installers for given data path endpoints.
1081 *
1082 * @param dataPathEndpoints the data path endpoints of the flows to get.
1083 * @return the Flow Paths if found, otherwise null.
1084 */
1085 @Override
1086 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1087 //
1088 // TODO: The implementation below is not optimal:
1089 // We fetch all flows, and then return only the subset that match
1090 // the query conditions.
1091 // We should use the appropriate Titan/Gremlin query to filter-out
1092 // the flows as appropriate.
1093 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001094 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1095 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001096
1097 if (allFlows == null) {
1098 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001099 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001100 }
1101
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001102 for (FlowPath flow : allFlows) {
1103 //
1104 // TODO: String-based comparison is sub-optimal.
1105 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001106 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001107 //
1108 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1109 continue;
1110 }
1111 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1112 continue;
1113 }
1114 flowPaths.add(flow);
1115 }
1116
1117 if (flowPaths.isEmpty()) {
1118 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001119 } else {
1120 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1121 }
1122
1123 return flowPaths;
1124 }
1125
1126 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001127 * Get summary of all installed flows by all installers in a given range
1128 *
1129 * @param flowId the data path endpoints of the flows to get.
1130 * @param maxFlows: the maximum number of flows to be returned
1131 * @return the Flow Paths if found, otherwise null.
1132 */
1133 @Override
1134 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1135 //
1136 // TODO: The implementation below is not optimal:
1137 // We fetch all flows, and then return only the subset that match
1138 // the query conditions.
1139 // We should use the appropriate Titan/Gremlin query to filter-out
1140 // the flows as appropriate.
1141 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001142 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1143
1144 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001145
1146 if (allFlows == null) {
1147 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001148 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001149 }
1150
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001151 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001152
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001153 for (FlowPath flow : allFlows) {
1154
1155 // start from desired flowId
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -07001156 //if (flow.flowId().value() < flowId.value()) {
1157 // continue;
1158 //}
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001159
1160 // Summarize by making null flow entry fields that are not relevant to report
1161 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1162 flowEntry.setFlowEntryActions(null);
1163 flowEntry.setFlowEntryMatch(null);
1164 }
1165
1166 flowPaths.add(flow);
1167 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1168 break;
1169 }
1170 }
1171
1172 if (flowPaths.isEmpty()) {
1173 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001174 } else {
1175 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1176 }
1177
1178 return flowPaths;
1179 }
1180
1181 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001182 * Get all installed flows by all installers.
1183 *
1184 * @return the Flow Paths if found, otherwise null.
1185 */
1186 @Override
1187 public ArrayList<FlowPath> getAllFlows() {
1188 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001189 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001190
1191 try {
1192 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1193 log.debug("Get all FlowPaths: found FlowPaths");
1194 } else {
1195 log.debug("Get all FlowPaths: no FlowPaths found");
1196 }
1197 } catch (Exception e) {
1198 // TODO: handle exceptions
1199 conn.endTx(Transaction.ROLLBACK);
1200 log.error(":getAllFlowPaths failed");
1201 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001202 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1203 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001204 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001205 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001206
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001207 for (IFlowPath flowObj : flowPathsObj) {
1208 //
1209 // Extract the Flow state
1210 //
1211 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001212 if (flowPath != null)
1213 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001214 }
1215
1216 conn.endTx(Transaction.COMMIT);
1217
1218 return flowPaths;
1219 }
1220
1221 /**
1222 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1223 *
1224 * @param flowObj the object to extract the Flow Path State from.
1225 * @return the extracted Flow Path State.
1226 */
1227 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001228 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001229
1230 //
1231 // Extract the Flow state
1232 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001233 String flowIdStr = flowObj.getFlowId();
1234 String installerIdStr = flowObj.getInstallerId();
1235 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001236 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001237 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001238 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001239
1240 if ((flowIdStr == null) ||
1241 (installerIdStr == null) ||
1242 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001243 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001244 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001245 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001246 // TODO: A work-around, becauuse of some bogus database objects
1247 return null;
1248 }
1249
1250 flowPath.setFlowId(new FlowId(flowIdStr));
1251 flowPath.setInstallerId(new CallerId(installerIdStr));
1252 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001253 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001254 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001255 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001256
1257 //
1258 // Extract all Flow Entries
1259 //
1260 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1261 for (IFlowEntry flowEntryObj : flowEntries) {
1262 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001263 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1264 String switchDpidStr = flowEntryObj.getSwitchDpid();
1265 String userState = flowEntryObj.getUserState();
1266 String switchState = flowEntryObj.getSwitchState();
1267
1268 if ((flowEntryIdStr == null) ||
1269 (switchDpidStr == null) ||
1270 (userState == null) ||
1271 (switchState == null)) {
1272 // TODO: A work-around, becauuse of some bogus database objects
1273 continue;
1274 }
1275 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1276 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001277
1278 //
1279 // Extract the match conditions
1280 //
1281 FlowEntryMatch match = new FlowEntryMatch();
1282 Short matchInPort = flowEntryObj.getMatchInPort();
1283 if (matchInPort != null)
1284 match.enableInPort(new Port(matchInPort));
1285 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1286 if (matchEthernetFrameType != null)
1287 match.enableEthernetFrameType(matchEthernetFrameType);
1288 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1289 if (matchSrcIPv4Net != null)
1290 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1291 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1292 if (matchDstIPv4Net != null)
1293 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1294 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1295 if (matchSrcMac != null)
1296 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1297 String matchDstMac = flowEntryObj.getMatchDstMac();
1298 if (matchDstMac != null)
1299 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1300 flowEntry.setFlowEntryMatch(match);
1301
1302 //
1303 // Extract the actions
1304 //
1305 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1306 Short actionOutputPort = flowEntryObj.getActionOutput();
1307 if (actionOutputPort != null) {
1308 FlowEntryAction action = new FlowEntryAction();
1309 action.setActionOutput(new Port(actionOutputPort));
1310 actions.add(action);
1311 }
1312 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001313 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001314 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1315 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001316 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001317 // and FlowEntryErrorState.
1318 //
1319 flowPath.dataPath().flowEntries().add(flowEntry);
1320 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001321
1322 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001323 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001324
1325 /**
1326 * Add and maintain a shortest-path flow.
1327 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001328 * NOTE: The Flow Path argument does NOT contain all flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001329 * Instead, it contains a single dummy flow entry that is used to
1330 * store the matching condition(s).
1331 * That entry is replaced by the appropriate entries from the
1332 * internally performed shortest-path computation.
1333 *
1334 * @param flowPath the Flow Path with the endpoints and the match
1335 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001336 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001337 */
1338 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001339 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001340 String dataPathSummaryStr = null;
1341
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001342 //
1343 // Do the shortest path computation
1344 //
1345 DataPath dataPath =
1346 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1347 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001348 if (dataPath == null) {
1349 // We need the DataPath to populate the Network MAP
1350 dataPath = new DataPath();
1351 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1352 dataPath.setDstPort(flowPath.dataPath().dstPort());
1353 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001354
1355 FlowEntryMatch userFlowEntryMatch = null;
1356 if (! flowPath.dataPath().flowEntries().isEmpty()) {
1357 userFlowEntryMatch = flowPath.dataPath().flowEntries().get(0).flowEntryMatch();
1358 }
1359
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001360 // Compute the Data Path summary
1361 dataPathSummaryStr = dataPath.dataPathSummary();
1362
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001363 //
1364 // Set the incoming port matching and the outgoing port output
1365 // actions for each flow entry.
1366 //
1367 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1368 // Set the incoming port matching
1369 FlowEntryMatch flowEntryMatch = null;
1370 if (userFlowEntryMatch != null)
1371 flowEntryMatch = new FlowEntryMatch(userFlowEntryMatch);
1372 else
1373 flowEntryMatch = new FlowEntryMatch();
1374 flowEntry.setFlowEntryMatch(flowEntryMatch);
1375 flowEntryMatch.enableInPort(flowEntry.inPort());
1376
1377 // Set the outgoing port output action
1378 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1379 if (flowEntryActions == null) {
1380 flowEntryActions = new ArrayList<FlowEntryAction>();
1381 flowEntry.setFlowEntryActions(flowEntryActions);
1382 }
1383 FlowEntryAction flowEntryAction = new FlowEntryAction();
1384 flowEntryAction.setActionOutput(flowEntry.outPort());
1385 flowEntryActions.add(flowEntryAction);
1386 }
1387
1388 //
1389 // Prepare the computed Flow Path
1390 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001391 FlowPath computedFlowPath = new FlowPath();
1392 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1393 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1394 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001395
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001396 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001397 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001398 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001399
1400 // TODO: Mark the flow for maintenance purpose
1401
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001402 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001403 }
1404
1405 /**
1406 * Create a Flow from port to port.
1407 *
1408 * TODO: We don't need it for now.
1409 *
1410 * @param src_port the source port.
1411 * @param dest_port the destination port.
1412 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001413 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001414 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1415 // TODO: We don't need it for now.
1416 }
1417
1418 /**
1419 * Get all Flows matching a source and a destination port.
1420 *
1421 * TODO: Pankaj might be implementing it later.
1422 *
1423 * @param src_port the source port to match.
1424 * @param dest_port the destination port to match.
1425 * @return all flows matching the source and the destination port.
1426 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001427 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001428 public Iterable<FlowPath> getFlows(IPortObject src_port,
1429 IPortObject dest_port) {
1430 // TODO: Pankaj might be implementing it later.
1431 return null;
1432 }
1433
1434 /**
1435 * Get all Flows going out from a port.
1436 *
1437 * TODO: We need it now: Pankaj
1438 *
1439 * @param port the port to match.
1440 * @return the list of flows that are going out from the port.
1441 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001442 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001443 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001444 // TODO: We need it now: Pankaj
1445 return null;
1446 }
1447
1448 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001449 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001450 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001451 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001452 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001453 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001454 public void reconcileFlows(IPortObject portObject) {
1455 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1456 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001457
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001458 //
1459 // Collect all affected Flow IDs from the affected flow entries
1460 //
1461 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1462 for (IFlowEntry flowEntryObj: inFlowEntries) {
1463 IFlowPath flowObj = flowEntryObj.getFlow();
1464 if (flowObj != null)
1465 flowObjSet.add(flowObj);
1466 }
1467 for (IFlowEntry flowEntryObj: outFlowEntries) {
1468 IFlowPath flowObj = flowEntryObj.getFlow();
1469 if (flowObj != null)
1470 flowObjSet.add(flowObj);
1471 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001472
1473 // Reconcile the affected flows
1474 reconcileFlows(flowObjSet);
1475 }
1476
1477 /**
1478 * Reconcile all flows in a set.
1479 *
1480 * @param flowObjSet the set of flows that need to be reconciliated.
1481 */
1482 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1483 if (! flowObjSet.iterator().hasNext())
1484 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001485
1486 //
1487 // Remove the old Flow Entries, and add the new Flow Entries
1488 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001489
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001490 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001491 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001492 for (IFlowPath flowObj : flowObjSet) {
1493 FlowPath flowPath = extractFlowPath(flowObj);
1494 if (flowPath == null)
1495 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001496 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001497
1498 //
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001499 // Remove the Flow Entries from the Network MAP
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001500 //
1501 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001502 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001503 for (IFlowEntry flowEntryObj : flowEntries) {
1504 String dpidStr = flowEntryObj.getSwitchDpid();
1505 if (dpidStr == null)
1506 continue;
1507 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001508 /*
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001509 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1510 if (mySwitch == null)
1511 continue; // Ignore the entry: not my switch
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001512 */
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001513 deleteFlowEntries.add(flowEntryObj);
1514 }
1515 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001516 flowObj.removeFlowEntry(flowEntryObj);
1517 conn.utils().removeFlowEntry(conn, flowEntryObj);
1518 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001519 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001520
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001521 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001522 //
1523 // Delete the flow entries from the switches
1524 //
1525 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1526 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001527 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1528 if (mySwitch == null) {
1529 // Not my switch
1530 installRemoteFlowEntry(flowEntry);
1531 } else {
1532 installFlowEntry(mySwitch, flowEntry);
1533 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001534 }
1535
1536 //
1537 // Calculate the new shortest path and install it in the
1538 // Network MAP.
1539 //
1540 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1541 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001542 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001543 flowPath.dataPath().srcPort().toString(),
1544 flowPath.dataPath().dstPort().toString());
1545 continue;
1546 }
1547
1548 //
1549 // Add the flow entries to the switches
1550 //
1551 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1552 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001553 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1554 if (mySwitch == null) {
1555 // Not my switch
1556 installRemoteFlowEntry(flowEntry);
1557 continue;
1558 }
1559
1560 IFlowEntry flowEntryObj =
1561 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1562 if (flowEntryObj == null) {
1563 //
1564 // TODO: Remove the "new Object[] wrapper in the statement
1565 // below after the SLF4J logger is upgraded to
1566 // Version 1.7.5
1567 //
1568 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1569 new Object[] {
1570 flowEntry.dpid(),
1571 flowPath.dataPath().srcPort(),
1572 flowPath.dataPath().dstPort()
1573 });
1574 continue;
1575 }
1576 // Update the Flow Entry Switch State in the Network MAP
1577 if (installFlowEntry(mySwitch, flowEntry)) {
1578 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1579 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001580 }
1581 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001582 }
1583
1584 /**
1585 * Reconcile all flows between a source and a destination port.
1586 *
1587 * TODO: We don't need it for now.
1588 *
1589 * @param src_port the source port.
1590 * @param dest_port the destination port.
1591 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001592 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001593 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1594 // TODO: We don't need it for now.
1595 }
1596
1597 /**
1598 * Compute the shortest path between a source and a destination ports.
1599 *
1600 * @param src_port the source port.
1601 * @param dest_port the destination port.
1602 * @return the computed shortest path between the source and the
1603 * destination ports. The flow entries in the path itself would
1604 * contain the incoming port matching and the outgoing port output
1605 * actions set. However, the path itself will NOT have the Flow ID,
1606 * Installer ID, and any additional matching conditions for the
1607 * flow entries (e.g., source or destination MAC address, etc).
1608 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001609 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001610 public FlowPath computeFlowPath(IPortObject src_port,
1611 IPortObject dest_port) {
1612 //
1613 // Prepare the arguments
1614 //
1615 String dpidStr = src_port.getSwitch().getDPID();
1616 Dpid srcDpid = new Dpid(dpidStr);
1617 Port srcPort = new Port(src_port.getNumber());
1618
1619 dpidStr = dest_port.getSwitch().getDPID();
1620 Dpid dstDpid = new Dpid(dpidStr);
1621 Port dstPort = new Port(dest_port.getNumber());
1622
1623 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1624 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1625
1626 //
1627 // Do the shortest path computation
1628 //
1629 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1630 if (dataPath == null)
1631 return null;
1632
1633 //
1634 // Set the incoming port matching and the outgoing port output
1635 // actions for each flow entry.
1636 //
1637 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1638 // Set the incoming port matching
1639 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1640 if (flowEntryMatch == null) {
1641 flowEntryMatch = new FlowEntryMatch();
1642 flowEntry.setFlowEntryMatch(flowEntryMatch);
1643 }
1644 flowEntryMatch.enableInPort(flowEntry.inPort());
1645
1646 // Set the outgoing port output action
1647 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1648 if (flowEntryActions == null) {
1649 flowEntryActions = new ArrayList<FlowEntryAction>();
1650 flowEntry.setFlowEntryActions(flowEntryActions);
1651 }
1652 FlowEntryAction flowEntryAction = new FlowEntryAction();
1653 flowEntryAction.setActionOutput(flowEntry.outPort());
1654 flowEntryActions.add(flowEntryAction);
1655 }
1656
1657 //
1658 // Prepare the return result
1659 //
1660 FlowPath flowPath = new FlowPath();
1661 flowPath.setDataPath(dataPath);
1662
1663 return flowPath;
1664 }
1665
1666 /**
1667 * Get all Flow Entries of a Flow.
1668 *
1669 * @param flow the flow whose flow entries should be returned.
1670 * @return the flow entries of the flow.
1671 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001672 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001673 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1674 return flow.dataPath().flowEntries();
1675 }
1676
1677 /**
1678 * Install a Flow Entry on a switch.
1679 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001680 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001681 * @param flowEntry the flow entry to install.
1682 * @return true on success, otherwise false.
1683 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001684 @Override
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001685 public boolean installFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001686 //
1687 // Create the OpenFlow Flow Modification Entry to push
1688 //
1689 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1690 .getMessage(OFType.FLOW_MOD);
1691 long cookie = flowEntry.flowEntryId().value();
1692
1693 short flowModCommand = OFFlowMod.OFPFC_ADD;
1694 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1695 flowModCommand = OFFlowMod.OFPFC_ADD;
1696 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1697 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1698 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1699 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1700 } else {
1701 // Unknown user state. Ignore the entry
1702 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1703 flowEntry.flowEntryId().toString(),
1704 flowEntry.flowEntryUserState());
1705 return false;
1706 }
1707
1708 //
1709 // Fetch the match conditions
1710 //
1711 OFMatch match = new OFMatch();
1712 match.setWildcards(OFMatch.OFPFW_ALL);
1713 Port matchInPort = flowEntry.flowEntryMatch().inPort();
1714 if (matchInPort != null) {
1715 match.setInputPort(matchInPort.value());
1716 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1717 }
1718 Short matchEthernetFrameType =
1719 flowEntry.flowEntryMatch().ethernetFrameType();
1720 if (matchEthernetFrameType != null) {
1721 match.setDataLayerType(matchEthernetFrameType);
1722 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1723 }
1724 IPv4Net matchSrcIPv4Net = flowEntry.flowEntryMatch().srcIPv4Net();
1725 if (matchSrcIPv4Net != null) {
1726 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1727 }
1728 IPv4Net matchDstIPv4Net = flowEntry.flowEntryMatch().dstIPv4Net();
1729 if (matchDstIPv4Net != null) {
1730 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1731 }
1732 MACAddress matchSrcMac = flowEntry.flowEntryMatch().srcMac();
1733 if (matchSrcMac != null) {
1734 match.setDataLayerSource(matchSrcMac.toString());
1735 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1736 }
1737 MACAddress matchDstMac = flowEntry.flowEntryMatch().dstMac();
1738 if (matchDstMac != null) {
1739 match.setDataLayerDestination(matchDstMac.toString());
1740 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1741 }
1742
1743 //
1744 // Fetch the actions
1745 //
1746 // TODO: For now we support only the "OUTPUT" actions.
1747 //
1748 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1749 List<OFAction> actions = new ArrayList<OFAction>();
1750 ArrayList<FlowEntryAction> flowEntryActions =
1751 flowEntry.flowEntryActions();
1752 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1753 FlowEntryAction.ActionOutput actionOutput =
1754 flowEntryAction.actionOutput();
1755 if (actionOutput != null) {
1756 short actionOutputPort = actionOutput.port().value();
1757 OFActionOutput action = new OFActionOutput();
1758 // XXX: The max length is hard-coded for now
1759 action.setMaxLength((short)0xffff);
1760 action.setPort(actionOutputPort);
1761 actions.add(action);
1762 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1763 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1764 fm.setOutPort(actionOutputPort);
1765 }
1766 }
1767 }
1768
1769 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1770 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1771 .setPriority(PRIORITY_DEFAULT)
1772 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1773 .setCookie(cookie)
1774 .setCommand(flowModCommand)
1775 .setMatch(match)
1776 .setActions(actions)
1777 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1778
1779 //
1780 // TODO: Set the following flag
1781 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1782 // See method ForwardingBase::pushRoute()
1783 //
1784
1785 //
1786 // Write the message to the switch
1787 //
1788 try {
1789 messageDamper.write(mySwitch, fm, null);
1790 mySwitch.flush();
1791 } catch (IOException e) {
1792 log.error("Failure writing flow mod from network map", e);
1793 return false;
1794 }
1795 return true;
1796 }
1797
1798 /**
1799 * Remove a Flow Entry from a switch.
1800 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001801 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001802 * @param flowEntry the flow entry to remove.
1803 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001804 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001805 @Override
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001806 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001807 //
1808 // The installFlowEntry() method implements both installation
1809 // and removal of flow entries.
1810 //
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001811 return (installFlowEntry(mySwitch, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001812 }
1813
1814 /**
1815 * Install a Flow Entry on a remote controller.
1816 *
1817 * TODO: We need it now: Jono
1818 * - For now it will make a REST call to the remote controller.
1819 * - Internally, it needs to know the name of the remote controller.
1820 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001821 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001822 * @return true on success, otherwise false.
1823 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001824 @Override
1825 public boolean installRemoteFlowEntry(FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001826 // TODO: We need it now: Jono
1827 // - For now it will make a REST call to the remote controller.
1828 // - Internally, it needs to know the name of the remote controller.
1829 return true;
1830 }
1831
1832 /**
1833 * Remove a flow entry on a remote controller.
1834 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001835 * @param flowEntry the flow entry to remove.
1836 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001837 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001838 @Override
1839 public boolean removeRemoteFlowEntry(FlowEntry flowEntry) {
1840 //
1841 // The installRemoteFlowEntry() method implements both installation
1842 // and removal of flow entries.
1843 //
1844 return (installRemoteFlowEntry(flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001845 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001846}