blob: 2e3f02e252b572f6f1df9b9d4eed79696499f4af [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;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07008import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00009import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080011import java.util.Map;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070012import java.util.TreeMap;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070013import java.util.Collections;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070014import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070016import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070019import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080020import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080021
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080022import net.floodlightcontroller.core.IFloodlightProviderService;
23import net.floodlightcontroller.core.INetMapStorage;
24import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
25import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070026import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070027import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070028import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080029import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080030import net.floodlightcontroller.core.module.FloodlightModuleContext;
31import net.floodlightcontroller.core.module.FloodlightModuleException;
32import net.floodlightcontroller.core.module.IFloodlightModule;
33import net.floodlightcontroller.core.module.IFloodlightService;
34import net.floodlightcontroller.flowcache.IFlowService;
35import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
36import net.floodlightcontroller.restserver.IRestApiService;
37import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080038import net.floodlightcontroller.util.DataPath;
39import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080040import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070042import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070044import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080045import net.floodlightcontroller.util.FlowEntrySwitchState;
46import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080047import net.floodlightcontroller.util.FlowId;
48import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070049import net.floodlightcontroller.util.IPv4Net;
50import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080051import net.floodlightcontroller.util.OFMessageDamper;
52import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070053import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070054import net.onrc.onos.flow.IFlowManager;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080055import net.onrc.onos.util.GraphDBConnection;
56import net.onrc.onos.util.GraphDBConnection.Transaction;
57
58import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
60import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070061import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080062import org.openflow.protocol.OFType;
63import org.openflow.protocol.action.OFAction;
64import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080065
66import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070069public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070
71 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080072
73 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080074 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070075 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070076 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080077
78 protected OFMessageDamper messageDamper;
79
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070080 //
81 // TODO: Values copied from elsewhere (class LearningSwitch).
82 // The local copy should go away!
83 //
84 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
85 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
86 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
87 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
88 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080089
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070090 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070091 private static long measurementFlowId = 100000;
92 private static String measurementFlowIdStr = "0x186a0"; // 100000
93 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070094
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080095 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080096 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
97
98 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070099 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800100 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700101 private final ScheduledExecutorService measureMapReaderScheduler =
102 Executors.newScheduledThreadPool(1);
103 private final ScheduledExecutorService mapReaderScheduler =
104 Executors.newScheduledThreadPool(1);
105
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700106 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
107 private ThreadPoolExecutor shortestPathExecutor =
108 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
109
110 class ShortestPathTask implements Runnable {
111 private int hint;
112 private ITopoRouteService topoRouteService;
113 private ArrayList<DataPath> dpList;
114
115 public ShortestPathTask(int hint,
116 ITopoRouteService topoRouteService,
117 ArrayList<DataPath> dpList) {
118 this.hint = hint;
119 this.topoRouteService = topoRouteService;
120 this.dpList = dpList;
121 }
122
123 @Override
124 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700125 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700126 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
127 log.debug(logMsg);
128 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700129 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700130 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700131 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700132 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700133 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700134 long estimatedTime = System.nanoTime() - startTime;
135 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
136 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
137 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700138 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700139 }
140 }
141
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700142 final Runnable measureShortestPath = new Runnable() {
143 public void run() {
144 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
145 if (floodlightProvider == null) {
146 log.debug("FloodlightProvider service not found!");
147 return;
148 }
149
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700150 if (topoRouteService == null) {
151 log.debug("Topology Route Service not found");
152 return;
153 }
154
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700155 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
156 if (leftoverQueueSize > 0) {
157 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
158 log.debug(logMsg);
159 return;
160 }
161 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
162
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700163 //
164 // Recompute the Shortest Paths for all Flows
165 //
166 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700167 int hint = 0;
168 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700169 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700170
171 topoRouteService.prepareShortestPathTopo();
172
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700173 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
174 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700175 FlowId flowId = new FlowId(flowPathObj.getFlowId());
176
177 // log.debug("Found Path {}", flowId.toString());
178 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
179 Port srcPort = new Port(flowPathObj.getSrcPort());
180 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
181 Port dstPort = new Port(flowPathObj.getDstPort());
182 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
183 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700184
185 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700186 DataPath dp = new DataPath();
187 dp.setSrcPort(srcSwitchPort);
188 dp.setDstPort(dstSwitchPort);
189 dpList.add(dp);
190 if ((dpList.size() % 10) == 0) {
191 shortestPathExecutor.execute(
192 new ShortestPathTask(hint, topoRouteService,
193 dpList));
194 dpList = new ArrayList<DataPath>();
195 hint++;
196 }
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700197 */
198
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700199 DataPath dataPath =
200 topoRouteService.getTopoShortestPath(srcSwitchPort,
201 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700202 counter++;
203 }
204 if (dpList.size() > 0) {
205 shortestPathExecutor.execute(
206 new ShortestPathTask(hint, topoRouteService,
207 dpList));
208 }
209
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700210 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700211 // Wait for all tasks to finish
212 try {
213 while (shortestPathExecutor.getQueue().size() > 0) {
214 Thread.sleep(100);
215 }
216 } catch (InterruptedException ex) {
217 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700218 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700219 */
220
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700221 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700222 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700223
224 long estimatedTime = System.nanoTime() - startTime;
225 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
226 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
227 log.debug(logMsg);
228 }
229 };
230
231 final Runnable measureMapReader = new Runnable() {
232 public void run() {
233 if (floodlightProvider == null) {
234 log.debug("FloodlightProvider service not found!");
235 return;
236 }
237
238 //
239 // Fetch all Flow Entries
240 //
241 int counter = 0;
242 long startTime = System.nanoTime();
243 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
244 for (IFlowEntry flowEntryObj : allFlowEntries) {
245 counter++;
246 FlowEntryId flowEntryId =
247 new FlowEntryId(flowEntryObj.getFlowEntryId());
248 String userState = flowEntryObj.getUserState();
249 String switchState = flowEntryObj.getSwitchState();
250 }
251 conn.endTx(Transaction.COMMIT);
252
253 long estimatedTime = System.nanoTime() - startTime;
254 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
255 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
256 log.debug(logMsg);
257 }
258 };
259
260 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800261 public void run() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800262 if (floodlightProvider == null) {
263 log.debug("FloodlightProvider service not found!");
264 return;
265 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000266 Map<Long, IOFSwitch> mySwitches =
267 floodlightProvider.getSwitches();
268 Map<Long, IFlowEntry> myFlowEntries =
269 new TreeMap<Long, IFlowEntry>();
270 LinkedList<IFlowEntry> deleteFlowEntries =
271 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700272
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700273
274 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700275 // Fetch all Flow Entries and select only my Flow Entries
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000276 // that need to be undated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700277 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000278 Iterable<IFlowEntry> allFlowEntries =
279 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700280 for (IFlowEntry flowEntryObj : allFlowEntries) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000281 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700282 String userState = flowEntryObj.getUserState();
283 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000284 String dpidStr = flowEntryObj.getSwitchDpid();
285 if ((flowEntryIdStr == null) ||
286 (userState == null) ||
287 (switchState == null) ||
288 (dpidStr == null)) {
289 log.debug("IGNORING Flow Entry entry with null fields");
290 continue;
291 }
292 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
293 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800294
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000295 /*
296 log.debug("Found Flow Entry Id = {} {}",
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700297 flowEntryId.toString(),
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000298 "DPID = " + dpid.toString() +
299 " User State: " + userState +
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700300 " Switch State: " + switchState);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000301 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800302
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000303 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
304 continue; // Ignore the entry: nothing to do
305
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800306 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000307 if (mySwitch == null)
308 continue; // Ignore the entry: not my switch
309
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700310 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
311 }
312
313 //
314 // Process my Flow Entries
315 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700316 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700317 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
318 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700319 // Code for measurement purpose
320 {
321 IFlowPath flowObj =
322 conn.utils().getFlowPathByFlowEntry(conn,
323 flowEntryObj);
324 if ((flowObj != null) &&
325 flowObj.getFlowId().equals(measurementFlowIdStr)) {
326 processed_measurement_flow = true;
327 }
328 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700329
330 //
331 // TODO: Eliminate the re-fetching of flowEntryId,
332 // userState, switchState, and dpid from the flowEntryObj.
333 //
334 FlowEntryId flowEntryId =
335 new FlowEntryId(flowEntryObj.getFlowEntryId());
336 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
337 String userState = flowEntryObj.getUserState();
338 String switchState = flowEntryObj.getSwitchState();
339 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000340 if (mySwitch == null)
341 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800342
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700343 // TODO: PAVPAVPAV: FROM HERE...
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800344 //
345 // Create the Open Flow Flow Modification Entry to push
346 //
347 OFFlowMod fm =
348 (OFFlowMod) floodlightProvider.getOFMessageFactory()
349 .getMessage(OFType.FLOW_MOD);
350 long cookie = flowEntryId.value();
351
352 short flowModCommand = OFFlowMod.OFPFC_ADD;
353 if (userState.equals("FE_USER_ADD")) {
354 flowModCommand = OFFlowMod.OFPFC_ADD;
355 } else if (userState.equals("FE_USER_MODIFY")) {
356 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
357 } else if (userState.equals("FE_USER_DELETE")) {
358 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
359 } else {
360 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700361 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
362 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800363 continue;
364 }
365
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700366 //
367 // Fetch the match conditions
368 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800369 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700370 match.setWildcards(OFMatch.OFPFW_ALL);
371 Short matchInPort = flowEntryObj.getMatchInPort();
372 if (matchInPort != null) {
373 match.setInputPort(matchInPort);
374 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
375 }
376 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
377 if (matchEthernetFrameType != null) {
378 match.setDataLayerType(matchEthernetFrameType);
379 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
380 }
381 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
382 if (matchSrcIPv4Net != null) {
383 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
384 }
385 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
386 if (matchDstIPv4Net != null) {
387 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
388 }
389 String matchSrcMac = flowEntryObj.getMatchSrcMac();
390 if (matchSrcMac != null) {
391 match.setDataLayerSource(matchSrcMac);
392 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
393 }
394 String matchDstMac = flowEntryObj.getMatchDstMac();
395 if (matchDstMac != null) {
396 match.setDataLayerDestination(matchDstMac);
397 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
398 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700399
400 //
401 // Fetch the actions
402 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800403 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700404 Short actionOutputPort = flowEntryObj.getActionOutput();
405 if (actionOutputPort != null) {
406 OFActionOutput action = new OFActionOutput();
407 // XXX: The max length is hard-coded for now
408 action.setMaxLength((short)0xffff);
409 action.setPort(actionOutputPort);
410 actions.add(action);
411 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800412
413 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
414 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700415 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800416 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
417 .setCookie(cookie)
418 .setCommand(flowModCommand)
419 .setMatch(match)
420 .setActions(actions)
421 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700422 fm.setOutPort(OFPort.OFPP_NONE.getValue());
423 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
424 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
425 if (actionOutputPort != null)
426 fm.setOutPort(actionOutputPort);
427 }
428
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800429 //
430 // TODO: Set the following flag
431 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
432 // See method ForwardingBase::pushRoute()
433 //
434 try {
435 messageDamper.write(mySwitch, fm, null);
436 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000437 //
438 // TODO: We should use the OpenFlow Barrier mechanism
439 // to check for errors, and update the SwitchState
440 // for a flow entry after the Barrier message is
441 // is received.
442 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800443 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
444 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000445 // An entry that needs to be deleted.
446 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800447 }
448 } catch (IOException e) {
449 log.error("Failure writing flow mod from network map", e);
450 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700451 // TODO: XXX: PAVPAVPAV: TO HERE.
452 // TODO: XXX: PAVPAVPAV: Update the flowEntryObj
453 // to "FE_SWITCH_UPDATED" in the new (refactored) code.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800454 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000455
456 //
457 // Delete all entries marked for deletion
458 //
459 // TODO: We should use the OpenFlow Barrier mechanism
460 // to check for errors, and delete the Flow Entries after the
461 // Barrier message is received.
462 //
463 while (! deleteFlowEntries.isEmpty()) {
464 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
465 IFlowPath flowObj =
466 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
467 if (flowObj == null) {
468 log.debug("Did not find FlowPath to be deleted");
469 continue;
470 }
471 flowObj.removeFlowEntry(flowEntryObj);
472 conn.utils().removeFlowEntry(conn, flowEntryObj);
473
474 // Test whether the last flow entry
475 Iterable<IFlowEntry> tmpflowEntries =
476 flowObj.getFlowEntries();
477 boolean found = false;
478 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
479 found = true;
480 break;
481 }
482 if (! found) {
483 // Remove the Flow Path as well
484 conn.utils().removeFlowPath(conn, flowObj);
485 }
486 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700487
488
489 //
490 // Fetch and recompute the Shortest Path for those
491 // Flow Paths this controller is responsible for.
492 //
493
494 /*
495 * TODO: For now, the computation of the reconciliation is
496 * commented-out.
497 */
498 /*
499 topoRouteService.prepareShortestPathTopo();
500 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
501 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
502 for (IFlowPath flowPathObj : allFlowPaths) {
503 if (flowPathObj == null)
504 continue;
505 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
506 if (dataPathSummaryStr == null)
507 continue; // Could be invalid entry?
508 if (dataPathSummaryStr.isEmpty())
509 continue; // No need to maintain this flow
510
511 // Fetch the fields needed to recompute the shortest path
512 String flowIdStr = flowPathObj.getFlowId();
513 String srcDpidStr = flowPathObj.getSrcSwitch();
514 Short srcPortShort = flowPathObj.getSrcPort();
515 String dstDpidStr = flowPathObj.getDstSwitch();
516 Short dstPortShort = flowPathObj.getDstPort();
517 if ((flowIdStr == null) ||
518 (srcDpidStr == null) ||
519 (srcPortShort == null) ||
520 (dstDpidStr == null) ||
521 (dstPortShort == null)) {
522 log.debug("IGNORING Flow Path entry with null fields");
523 continue;
524 }
525
526 FlowId flowId = new FlowId(flowIdStr);
527 Dpid srcDpid = new Dpid(srcDpidStr);
528 Port srcPort = new Port(srcPortShort);
529 Dpid dstDpid = new Dpid(dstDpidStr);
530 Port dstPort = new Port(dstPortShort);
531 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
532 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
533 DataPath dataPath =
534 topoRouteService.getTopoShortestPath(srcSwitchPort,
535 dstSwitchPort);
536 String newDataPathSummaryStr = dataPath.dataPathSummary();
537 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
538 continue; // Nothing changed
539
540 //
541 // Use the source DPID as a heuristic to decide
542 // which controller is responsible for maintaining the
543 // shortest path.
544 // NOTE: This heuristic is error-prone: if the switch
545 // goes away and no controller is responsible for that
546 // switch, then the original Flow Path is not cleaned-up
547 //
548 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
549 if (mySwitch == null)
550 continue; // Ignore: not my responsibility
551
552 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
553 flowId.toString());
554 flowObjSet.add(flowPathObj);
555 }
556 reconcileFlows(flowObjSet);
557 topoRouteService.dropShortestPathTopo();
558 */
559
560
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800561 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700562
563 if (processed_measurement_flow) {
564 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
565 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
566 (double)estimatedTime / 1000000000 + " sec";
567 log.debug(logMsg);
568 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800569 }
570 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700571
572 /*
573 final ScheduledFuture<?> measureShortestPathHandle =
574 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
575 */
576
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700577 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700578 final ScheduledFuture<?> measureMapReaderHandle =
579 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700580 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700581
582 final ScheduledFuture<?> mapReaderHandle =
583 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800584
585 @Override
586 public void init(String conf) {
587 conn = GraphDBConnection.getInstance(conf);
588 }
589
590 public void finalize() {
591 close();
592 }
593
594 @Override
595 public void close() {
596 conn.close();
597 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800598
599 @Override
600 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
601 Collection<Class<? extends IFloodlightService>> l =
602 new ArrayList<Class<? extends IFloodlightService>>();
603 l.add(IFlowService.class);
604 return l;
605 }
606
607 @Override
608 public Map<Class<? extends IFloodlightService>, IFloodlightService>
609 getServiceImpls() {
610 Map<Class<? extends IFloodlightService>,
611 IFloodlightService> m =
612 new HashMap<Class<? extends IFloodlightService>,
613 IFloodlightService>();
614 m.put(IFlowService.class, this);
615 return m;
616 }
617
618 @Override
619 public Collection<Class<? extends IFloodlightService>>
620 getModuleDependencies() {
621 Collection<Class<? extends IFloodlightService>> l =
622 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800623 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700624 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800625 l.add(IRestApiService.class);
626 return l;
627 }
628
629 @Override
630 public void init(FloodlightModuleContext context)
631 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700632 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800633 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700634 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800635 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800636 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
637 EnumSet.of(OFType.FLOW_MOD),
638 OFMESSAGE_DAMPER_TIMEOUT);
639 // TODO: An ugly hack!
640 String conf = "/tmp/cassandra.titan";
641 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800642 }
643
644 @Override
645 public void startUp(FloodlightModuleContext context) {
646 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700647
648 //
649 // Extract all flow entries and assign the next Flow Entry ID
650 // to be larger than the largest Flow Entry ID
651 //
652 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
653 for (IFlowEntry flowEntryObj : allFlowEntries) {
654 FlowEntryId flowEntryId =
655 new FlowEntryId(flowEntryObj.getFlowEntryId());
656 if (flowEntryId.value() >= nextFlowEntryId)
657 nextFlowEntryId = flowEntryId.value() + 1;
658 }
659 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800660 }
661
662 /**
663 * Add a flow.
664 *
665 * Internally, ONOS will automatically register the installer for
666 * receiving Flow Path Notifications for that path.
667 *
668 * @param flowPath the Flow Path to install.
669 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700670 * @param dataPathSummaryStr the data path summary string if the added
671 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800672 * @return true on success, otherwise false.
673 */
674 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700675 public boolean addFlow(FlowPath flowPath, FlowId flowId,
676 String dataPathSummaryStr) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700677 if (flowPath.flowId().value() == measurementFlowId) {
678 modifiedMeasurementFlowTime = System.nanoTime();
679 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800680
681 //
682 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700683 // Right now every new flow entry gets a new flow entry ID
684 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800685 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800686 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700687 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800688 flowEntry.setFlowEntryId(new FlowEntryId(id));
689 }
690
691 IFlowPath flowObj = null;
692 try {
693 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
694 != null) {
695 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
696 flowPath.flowId().toString());
697 } else {
698 flowObj = conn.utils().newFlowPath(conn);
699 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
700 flowPath.flowId().toString());
701 }
702 } catch (Exception e) {
703 // TODO: handle exceptions
704 conn.endTx(Transaction.ROLLBACK);
705 log.error(":addFlow FlowId:{} failed",
706 flowPath.flowId().toString());
707 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700708 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000709 log.error(":addFlow FlowId:{} failed: Flow object not created",
710 flowPath.flowId().toString());
711 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800712 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700713 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800714
715 //
716 // Set the Flow key:
717 // - flowId
718 //
719 flowObj.setFlowId(flowPath.flowId().toString());
720 flowObj.setType("flow");
721
722 //
723 // Set the Flow attributes:
724 // - flowPath.installerId()
725 // - flowPath.dataPath().srcPort()
726 // - flowPath.dataPath().dstPort()
727 //
728 flowObj.setInstallerId(flowPath.installerId().toString());
729 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
730 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
731 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
732 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
733
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700734 if (dataPathSummaryStr != null) {
735 flowObj.setDataPathSummary(dataPathSummaryStr);
736 } else {
737 flowObj.setDataPathSummary("");
738 }
739
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800740 // Flow edges:
741 // HeadFE
742
743
744 //
745 // Flow Entries:
746 // flowPath.dataPath().flowEntries()
747 //
748 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
749 IFlowEntry flowEntryObj = null;
750 boolean found = false;
751 try {
752 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
753 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
754 flowEntry.flowEntryId().toString());
755 found = true;
756 } else {
757 flowEntryObj = conn.utils().newFlowEntry(conn);
758 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
759 flowEntry.flowEntryId().toString());
760 }
761 } catch (Exception e) {
762 // TODO: handle exceptions
763 conn.endTx(Transaction.ROLLBACK);
764 log.error(":addFlow FlowEntryId:{} failed",
765 flowEntry.flowEntryId().toString());
766 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700767 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000768 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
769 flowEntry.flowEntryId().toString());
770 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800771 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700772 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800773
774 //
775 // Set the Flow Entry key:
776 // - flowEntry.flowEntryId()
777 //
778 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
779 flowEntryObj.setType("flow_entry");
780
781 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700782 // Set the Flow Entry Edges and attributes:
783 // - Switch edge
784 // - InPort edge
785 // - OutPort edge
786 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800787 // - flowEntry.flowEntryMatch()
788 // - flowEntry.flowEntryActions()
789 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800790 // - flowEntry.flowEntryUserState()
791 // - flowEntry.flowEntrySwitchState()
792 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700793 // - flowEntry.matchInPort()
794 // - flowEntry.matchEthernetFrameType()
795 // - flowEntry.matchSrcIPv4Net()
796 // - flowEntry.matchDstIPv4Net()
797 // - flowEntry.matchSrcMac()
798 // - flowEntry.matchDstMac()
799 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800800 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700801 ISwitchObject sw =
802 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800803 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700804 flowEntryObj.setSwitch(sw);
805 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700806 IPortObject inport =
807 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
808 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700809 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
810 flowEntryObj.setInPort(inport);
811 }
812 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
813 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
814 }
815 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
816 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
817 }
818 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
819 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
820 }
821 if (flowEntry.flowEntryMatch().matchSrcMac()) {
822 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
823 }
824 if (flowEntry.flowEntryMatch().matchDstMac()) {
825 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
826 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700827
828 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700829 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700830 IPortObject outport =
831 conn.utils().searchPort(conn,
832 flowEntry.dpid().toString(),
833 fa.actionOutput().port().value());
834 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
835 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700836 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700837 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800838 // TODO: Hacks with hard-coded state names!
839 if (found)
840 flowEntryObj.setUserState("FE_USER_MODIFY");
841 else
842 flowEntryObj.setUserState("FE_USER_ADD");
843 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
844 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700845 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800846 //
847
848 // Flow Entries edges:
849 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700850 // NextFE (TODO)
851 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800852 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700853 flowEntryObj.setFlow(flowObj);
854 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800855 }
856 conn.endTx(Transaction.COMMIT);
857
858 //
859 // TODO: We need a proper Flow ID allocation mechanism.
860 //
861 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700862
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800863 return true;
864 }
865
866 /**
867 * Delete a previously added flow.
868 *
869 * @param flowId the Flow ID of the flow to delete.
870 * @return true on success, otherwise false.
871 */
872 @Override
873 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700874 if (flowId.value() == measurementFlowId) {
875 modifiedMeasurementFlowTime = System.nanoTime();
876 }
877
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800878 IFlowPath flowObj = null;
879 //
880 // We just mark the entries for deletion,
881 // and let the switches remove each individual entry after
882 // it has been removed from the switches.
883 //
884 try {
885 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
886 != null) {
887 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
888 flowId.toString());
889 } else {
890 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
891 flowId.toString());
892 }
893 } catch (Exception e) {
894 // TODO: handle exceptions
895 conn.endTx(Transaction.ROLLBACK);
896 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
897 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700898 if (flowObj == null) {
899 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800900 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700901 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800902
903 //
904 // Find and mark for deletion all Flow Entries
905 //
906 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
907 boolean empty = true; // TODO: an ugly hack
908 for (IFlowEntry flowEntryObj : flowEntries) {
909 empty = false;
910 // flowObj.removeFlowEntry(flowEntryObj);
911 // conn.utils().removeFlowEntry(conn, flowEntryObj);
912 flowEntryObj.setUserState("FE_USER_DELETE");
913 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
914 }
915 // Remove from the database empty flows
916 if (empty)
917 conn.utils().removeFlowPath(conn, flowObj);
918 conn.endTx(Transaction.COMMIT);
919
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800920 return true;
921 }
922
923 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700924 * Clear the state for a previously added flow.
925 *
926 * @param flowId the Flow ID of the flow to clear.
927 * @return true on success, otherwise false.
928 */
929 @Override
930 public boolean clearFlow(FlowId flowId) {
931 IFlowPath flowObj = null;
932 try {
933 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
934 != null) {
935 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
936 flowId.toString());
937 } else {
938 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
939 flowId.toString());
940 }
941 } catch (Exception e) {
942 // TODO: handle exceptions
943 conn.endTx(Transaction.ROLLBACK);
944 log.error(":clearFlow FlowId:{} failed", flowId.toString());
945 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700946 if (flowObj == null) {
947 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700948 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700949 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700950
951 //
952 // Remove all Flow Entries
953 //
954 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
955 for (IFlowEntry flowEntryObj : flowEntries) {
956 flowObj.removeFlowEntry(flowEntryObj);
957 conn.utils().removeFlowEntry(conn, flowEntryObj);
958 }
959 // Remove the Flow itself
960 conn.utils().removeFlowPath(conn, flowObj);
961 conn.endTx(Transaction.COMMIT);
962
963 return true;
964 }
965
966 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800967 * Get a previously added flow.
968 *
969 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800970 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800971 */
972 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800973 public FlowPath getFlow(FlowId flowId) {
974 IFlowPath flowObj = null;
975 try {
976 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
977 != null) {
978 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
979 flowId.toString());
980 } else {
981 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
982 flowId.toString());
983 }
984 } catch (Exception e) {
985 // TODO: handle exceptions
986 conn.endTx(Transaction.ROLLBACK);
987 log.error(":getFlow FlowId:{} failed", flowId.toString());
988 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700989 if (flowObj == null) {
990 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800991 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700992 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800993
994 //
995 // Extract the Flow state
996 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800997 FlowPath flowPath = extractFlowPath(flowObj);
998 conn.endTx(Transaction.COMMIT);
999
1000 return flowPath;
1001 }
1002
1003 /**
1004 * Get all previously added flows by a specific installer for a given
1005 * data path endpoints.
1006 *
1007 * @param installerId the Caller ID of the installer of the flow to get.
1008 * @param dataPathEndpoints the data path endpoints of the flow to get.
1009 * @return the Flow Paths if found, otherwise null.
1010 */
1011 @Override
1012 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1013 DataPathEndpoints dataPathEndpoints) {
1014 //
1015 // TODO: The implementation below is not optimal:
1016 // We fetch all flows, and then return only the subset that match
1017 // the query conditions.
1018 // We should use the appropriate Titan/Gremlin query to filter-out
1019 // the flows as appropriate.
1020 //
1021 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001022 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001023
1024 if (allFlows == null) {
1025 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001026 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001027 }
1028
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001029 for (FlowPath flow : allFlows) {
1030 //
1031 // TODO: String-based comparison is sub-optimal.
1032 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001033 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001034 //
1035 if (! flow.installerId().toString().equals(installerId.toString()))
1036 continue;
1037 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1038 continue;
1039 }
1040 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1041 continue;
1042 }
1043 flowPaths.add(flow);
1044 }
1045
1046 if (flowPaths.isEmpty()) {
1047 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001048 } else {
1049 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1050 }
1051
1052 return flowPaths;
1053 }
1054
1055 /**
1056 * Get all installed flows by all installers for given data path endpoints.
1057 *
1058 * @param dataPathEndpoints the data path endpoints of the flows to get.
1059 * @return the Flow Paths if found, otherwise null.
1060 */
1061 @Override
1062 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1063 //
1064 // TODO: The implementation below is not optimal:
1065 // We fetch all flows, and then return only the subset that match
1066 // the query conditions.
1067 // We should use the appropriate Titan/Gremlin query to filter-out
1068 // the flows as appropriate.
1069 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001070 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1071 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001072
1073 if (allFlows == null) {
1074 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001075 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001076 }
1077
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001078 for (FlowPath flow : allFlows) {
1079 //
1080 // TODO: String-based comparison is sub-optimal.
1081 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001082 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001083 //
1084 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1085 continue;
1086 }
1087 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1088 continue;
1089 }
1090 flowPaths.add(flow);
1091 }
1092
1093 if (flowPaths.isEmpty()) {
1094 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001095 } else {
1096 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1097 }
1098
1099 return flowPaths;
1100 }
1101
1102 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001103 * Get summary of all installed flows by all installers in a given range
1104 *
1105 * @param flowId the data path endpoints of the flows to get.
1106 * @param maxFlows: the maximum number of flows to be returned
1107 * @return the Flow Paths if found, otherwise null.
1108 */
1109 @Override
1110 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1111 //
1112 // TODO: The implementation below is not optimal:
1113 // We fetch all flows, and then return only the subset that match
1114 // the query conditions.
1115 // We should use the appropriate Titan/Gremlin query to filter-out
1116 // the flows as appropriate.
1117 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001118 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1119
1120 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001121
1122 if (allFlows == null) {
1123 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001124 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001125 }
1126
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -07001127// Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001128
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001129 for (FlowPath flow : allFlows) {
1130
1131 // start from desired flowId
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -07001132 //if (flow.flowId().value() < flowId.value()) {
1133 // continue;
1134 //}
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001135
1136 // Summarize by making null flow entry fields that are not relevant to report
1137 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1138 flowEntry.setFlowEntryActions(null);
1139 flowEntry.setFlowEntryMatch(null);
1140 }
1141
1142 flowPaths.add(flow);
1143 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1144 break;
1145 }
1146 }
1147
1148 if (flowPaths.isEmpty()) {
1149 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001150 } else {
1151 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1152 }
1153
1154 return flowPaths;
1155 }
1156
1157 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001158 * Get all installed flows by all installers.
1159 *
1160 * @return the Flow Paths if found, otherwise null.
1161 */
1162 @Override
1163 public ArrayList<FlowPath> getAllFlows() {
1164 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001165 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001166
1167 try {
1168 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1169 log.debug("Get all FlowPaths: found FlowPaths");
1170 } else {
1171 log.debug("Get all FlowPaths: no FlowPaths found");
1172 }
1173 } catch (Exception e) {
1174 // TODO: handle exceptions
1175 conn.endTx(Transaction.ROLLBACK);
1176 log.error(":getAllFlowPaths failed");
1177 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001178 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1179 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001180 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001181 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001182
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001183 for (IFlowPath flowObj : flowPathsObj) {
1184 //
1185 // Extract the Flow state
1186 //
1187 FlowPath flowPath = extractFlowPath(flowObj);
1188 flowPaths.add(flowPath);
1189 }
1190
1191 conn.endTx(Transaction.COMMIT);
1192
1193 return flowPaths;
1194 }
1195
1196 /**
1197 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1198 *
1199 * @param flowObj the object to extract the Flow Path State from.
1200 * @return the extracted Flow Path State.
1201 */
1202 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001203 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001204
1205 //
1206 // Extract the Flow state
1207 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001208 String flowIdStr = flowObj.getFlowId();
1209 String installerIdStr = flowObj.getInstallerId();
1210 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001211 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001212 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001213 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001214
1215 if ((flowIdStr == null) ||
1216 (installerIdStr == null) ||
1217 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001218 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001219 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001220 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001221 // TODO: A work-around, becauuse of some bogus database objects
1222 return null;
1223 }
1224
1225 flowPath.setFlowId(new FlowId(flowIdStr));
1226 flowPath.setInstallerId(new CallerId(installerIdStr));
1227 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001228 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001229 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001230 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001231
1232 //
1233 // Extract all Flow Entries
1234 //
1235 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1236 for (IFlowEntry flowEntryObj : flowEntries) {
1237 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001238 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1239 String switchDpidStr = flowEntryObj.getSwitchDpid();
1240 String userState = flowEntryObj.getUserState();
1241 String switchState = flowEntryObj.getSwitchState();
1242
1243 if ((flowEntryIdStr == null) ||
1244 (switchDpidStr == null) ||
1245 (userState == null) ||
1246 (switchState == null)) {
1247 // TODO: A work-around, becauuse of some bogus database objects
1248 continue;
1249 }
1250 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1251 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001252
1253 //
1254 // Extract the match conditions
1255 //
1256 FlowEntryMatch match = new FlowEntryMatch();
1257 Short matchInPort = flowEntryObj.getMatchInPort();
1258 if (matchInPort != null)
1259 match.enableInPort(new Port(matchInPort));
1260 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1261 if (matchEthernetFrameType != null)
1262 match.enableEthernetFrameType(matchEthernetFrameType);
1263 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1264 if (matchSrcIPv4Net != null)
1265 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1266 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1267 if (matchDstIPv4Net != null)
1268 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1269 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1270 if (matchSrcMac != null)
1271 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1272 String matchDstMac = flowEntryObj.getMatchDstMac();
1273 if (matchDstMac != null)
1274 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1275 flowEntry.setFlowEntryMatch(match);
1276
1277 //
1278 // Extract the actions
1279 //
1280 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1281 Short actionOutputPort = flowEntryObj.getActionOutput();
1282 if (actionOutputPort != null) {
1283 FlowEntryAction action = new FlowEntryAction();
1284 action.setActionOutput(new Port(actionOutputPort));
1285 actions.add(action);
1286 }
1287 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001288 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001289 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1290 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001291 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001292 // and FlowEntryErrorState.
1293 //
1294 flowPath.dataPath().flowEntries().add(flowEntry);
1295 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001296
1297 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001298 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001299
1300 /**
1301 * Add and maintain a shortest-path flow.
1302 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001303 * NOTE: The Flow Path argument does NOT contain all flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001304 * Instead, it contains a single dummy flow entry that is used to
1305 * store the matching condition(s).
1306 * That entry is replaced by the appropriate entries from the
1307 * internally performed shortest-path computation.
1308 *
1309 * @param flowPath the Flow Path with the endpoints and the match
1310 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001311 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001312 */
1313 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001314 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001315 String dataPathSummaryStr = null;
1316
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001317 //
1318 // Do the shortest path computation
1319 //
1320 DataPath dataPath =
1321 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1322 flowPath.dataPath().dstPort());
1323 if (dataPath == null)
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001324 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001325
1326 FlowEntryMatch userFlowEntryMatch = null;
1327 if (! flowPath.dataPath().flowEntries().isEmpty()) {
1328 userFlowEntryMatch = flowPath.dataPath().flowEntries().get(0).flowEntryMatch();
1329 }
1330
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001331 // Compute the Data Path summary
1332 dataPathSummaryStr = dataPath.dataPathSummary();
1333
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001334 //
1335 // Set the incoming port matching and the outgoing port output
1336 // actions for each flow entry.
1337 //
1338 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1339 // Set the incoming port matching
1340 FlowEntryMatch flowEntryMatch = null;
1341 if (userFlowEntryMatch != null)
1342 flowEntryMatch = new FlowEntryMatch(userFlowEntryMatch);
1343 else
1344 flowEntryMatch = new FlowEntryMatch();
1345 flowEntry.setFlowEntryMatch(flowEntryMatch);
1346 flowEntryMatch.enableInPort(flowEntry.inPort());
1347
1348 // Set the outgoing port output action
1349 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1350 if (flowEntryActions == null) {
1351 flowEntryActions = new ArrayList<FlowEntryAction>();
1352 flowEntry.setFlowEntryActions(flowEntryActions);
1353 }
1354 FlowEntryAction flowEntryAction = new FlowEntryAction();
1355 flowEntryAction.setActionOutput(flowEntry.outPort());
1356 flowEntryActions.add(flowEntryAction);
1357 }
1358
1359 //
1360 // Prepare the computed Flow Path
1361 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001362 FlowPath computedFlowPath = new FlowPath();
1363 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1364 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1365 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001366
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001367 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001368 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001369 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001370
1371 // TODO: Mark the flow for maintenance purpose
1372
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001373 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001374 }
1375
1376 /**
1377 * Create a Flow from port to port.
1378 *
1379 * TODO: We don't need it for now.
1380 *
1381 * @param src_port the source port.
1382 * @param dest_port the destination port.
1383 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001384 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001385 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1386 // TODO: We don't need it for now.
1387 }
1388
1389 /**
1390 * Get all Flows matching a source and a destination port.
1391 *
1392 * TODO: Pankaj might be implementing it later.
1393 *
1394 * @param src_port the source port to match.
1395 * @param dest_port the destination port to match.
1396 * @return all flows matching the source and the destination port.
1397 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001398 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001399 public Iterable<FlowPath> getFlows(IPortObject src_port,
1400 IPortObject dest_port) {
1401 // TODO: Pankaj might be implementing it later.
1402 return null;
1403 }
1404
1405 /**
1406 * Get all Flows going out from a port.
1407 *
1408 * TODO: We need it now: Pankaj
1409 *
1410 * @param port the port to match.
1411 * @return the list of flows that are going out from the port.
1412 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001413 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001414 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001415 // TODO: We need it now: Pankaj
1416 return null;
1417 }
1418
1419 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001420 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001421 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001422 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001423 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001424 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001425 public void reconcileFlows(IPortObject portObject) {
1426 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1427 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001428
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001429 //
1430 // Collect all affected Flow IDs from the affected flow entries
1431 //
1432 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1433 for (IFlowEntry flowEntryObj: inFlowEntries) {
1434 IFlowPath flowObj = flowEntryObj.getFlow();
1435 if (flowObj != null)
1436 flowObjSet.add(flowObj);
1437 }
1438 for (IFlowEntry flowEntryObj: outFlowEntries) {
1439 IFlowPath flowObj = flowEntryObj.getFlow();
1440 if (flowObj != null)
1441 flowObjSet.add(flowObj);
1442 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001443
1444 // Reconcile the affected flows
1445 reconcileFlows(flowObjSet);
1446 }
1447
1448 /**
1449 * Reconcile all flows in a set.
1450 *
1451 * @param flowObjSet the set of flows that need to be reconciliated.
1452 */
1453 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1454 if (! flowObjSet.iterator().hasNext())
1455 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001456
1457 //
1458 // Remove the old Flow Entries, and add the new Flow Entries
1459 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001460
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001461 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001462 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001463 for (IFlowPath flowObj : flowObjSet) {
1464 FlowPath flowPath = extractFlowPath(flowObj);
1465 if (flowPath == null)
1466 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001467 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001468
1469 //
1470 // Remove my Flow Entries from the Network MAP
1471 //
1472 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001473 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001474 for (IFlowEntry flowEntryObj : flowEntries) {
1475 String dpidStr = flowEntryObj.getSwitchDpid();
1476 if (dpidStr == null)
1477 continue;
1478 Dpid dpid = new Dpid(dpidStr);
1479 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1480 if (mySwitch == null)
1481 continue; // Ignore the entry: not my switch
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001482 deleteFlowEntries.add(flowEntryObj);
1483 }
1484 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001485 flowObj.removeFlowEntry(flowEntryObj);
1486 conn.utils().removeFlowEntry(conn, flowEntryObj);
1487 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001488 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001489
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001490 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001491 //
1492 // Delete the flow entries from the switches
1493 //
1494 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1495 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001496 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1497 if (mySwitch == null) {
1498 // Not my switch
1499 installRemoteFlowEntry(flowEntry);
1500 } else {
1501 installFlowEntry(mySwitch, flowEntry);
1502 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001503 }
1504
1505 //
1506 // Calculate the new shortest path and install it in the
1507 // Network MAP.
1508 //
1509 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1510 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001511 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001512 flowPath.dataPath().srcPort().toString(),
1513 flowPath.dataPath().dstPort().toString());
1514 continue;
1515 }
1516
1517 //
1518 // Add the flow entries to the switches
1519 //
1520 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1521 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001522 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1523 if (mySwitch == null) {
1524 // Not my switch
1525 installRemoteFlowEntry(flowEntry);
1526 continue;
1527 }
1528
1529 IFlowEntry flowEntryObj =
1530 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1531 if (flowEntryObj == null) {
1532 //
1533 // TODO: Remove the "new Object[] wrapper in the statement
1534 // below after the SLF4J logger is upgraded to
1535 // Version 1.7.5
1536 //
1537 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1538 new Object[] {
1539 flowEntry.dpid(),
1540 flowPath.dataPath().srcPort(),
1541 flowPath.dataPath().dstPort()
1542 });
1543 continue;
1544 }
1545 // Update the Flow Entry Switch State in the Network MAP
1546 if (installFlowEntry(mySwitch, flowEntry)) {
1547 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1548 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001549 }
1550 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001551 }
1552
1553 /**
1554 * Reconcile all flows between a source and a destination port.
1555 *
1556 * TODO: We don't need it for now.
1557 *
1558 * @param src_port the source port.
1559 * @param dest_port the destination port.
1560 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001561 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001562 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1563 // TODO: We don't need it for now.
1564 }
1565
1566 /**
1567 * Compute the shortest path between a source and a destination ports.
1568 *
1569 * @param src_port the source port.
1570 * @param dest_port the destination port.
1571 * @return the computed shortest path between the source and the
1572 * destination ports. The flow entries in the path itself would
1573 * contain the incoming port matching and the outgoing port output
1574 * actions set. However, the path itself will NOT have the Flow ID,
1575 * Installer ID, and any additional matching conditions for the
1576 * flow entries (e.g., source or destination MAC address, etc).
1577 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001578 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001579 public FlowPath computeFlowPath(IPortObject src_port,
1580 IPortObject dest_port) {
1581 //
1582 // Prepare the arguments
1583 //
1584 String dpidStr = src_port.getSwitch().getDPID();
1585 Dpid srcDpid = new Dpid(dpidStr);
1586 Port srcPort = new Port(src_port.getNumber());
1587
1588 dpidStr = dest_port.getSwitch().getDPID();
1589 Dpid dstDpid = new Dpid(dpidStr);
1590 Port dstPort = new Port(dest_port.getNumber());
1591
1592 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1593 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1594
1595 //
1596 // Do the shortest path computation
1597 //
1598 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1599 if (dataPath == null)
1600 return null;
1601
1602 //
1603 // Set the incoming port matching and the outgoing port output
1604 // actions for each flow entry.
1605 //
1606 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1607 // Set the incoming port matching
1608 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1609 if (flowEntryMatch == null) {
1610 flowEntryMatch = new FlowEntryMatch();
1611 flowEntry.setFlowEntryMatch(flowEntryMatch);
1612 }
1613 flowEntryMatch.enableInPort(flowEntry.inPort());
1614
1615 // Set the outgoing port output action
1616 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1617 if (flowEntryActions == null) {
1618 flowEntryActions = new ArrayList<FlowEntryAction>();
1619 flowEntry.setFlowEntryActions(flowEntryActions);
1620 }
1621 FlowEntryAction flowEntryAction = new FlowEntryAction();
1622 flowEntryAction.setActionOutput(flowEntry.outPort());
1623 flowEntryActions.add(flowEntryAction);
1624 }
1625
1626 //
1627 // Prepare the return result
1628 //
1629 FlowPath flowPath = new FlowPath();
1630 flowPath.setDataPath(dataPath);
1631
1632 return flowPath;
1633 }
1634
1635 /**
1636 * Get all Flow Entries of a Flow.
1637 *
1638 * @param flow the flow whose flow entries should be returned.
1639 * @return the flow entries of the flow.
1640 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001641 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001642 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1643 return flow.dataPath().flowEntries();
1644 }
1645
1646 /**
1647 * Install a Flow Entry on a switch.
1648 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001649 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001650 * @param flowEntry the flow entry to install.
1651 * @return true on success, otherwise false.
1652 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001653 @Override
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001654 public boolean installFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001655 //
1656 // Create the OpenFlow Flow Modification Entry to push
1657 //
1658 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1659 .getMessage(OFType.FLOW_MOD);
1660 long cookie = flowEntry.flowEntryId().value();
1661
1662 short flowModCommand = OFFlowMod.OFPFC_ADD;
1663 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1664 flowModCommand = OFFlowMod.OFPFC_ADD;
1665 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1666 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1667 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1668 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1669 } else {
1670 // Unknown user state. Ignore the entry
1671 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1672 flowEntry.flowEntryId().toString(),
1673 flowEntry.flowEntryUserState());
1674 return false;
1675 }
1676
1677 //
1678 // Fetch the match conditions
1679 //
1680 OFMatch match = new OFMatch();
1681 match.setWildcards(OFMatch.OFPFW_ALL);
1682 Port matchInPort = flowEntry.flowEntryMatch().inPort();
1683 if (matchInPort != null) {
1684 match.setInputPort(matchInPort.value());
1685 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1686 }
1687 Short matchEthernetFrameType =
1688 flowEntry.flowEntryMatch().ethernetFrameType();
1689 if (matchEthernetFrameType != null) {
1690 match.setDataLayerType(matchEthernetFrameType);
1691 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1692 }
1693 IPv4Net matchSrcIPv4Net = flowEntry.flowEntryMatch().srcIPv4Net();
1694 if (matchSrcIPv4Net != null) {
1695 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1696 }
1697 IPv4Net matchDstIPv4Net = flowEntry.flowEntryMatch().dstIPv4Net();
1698 if (matchDstIPv4Net != null) {
1699 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1700 }
1701 MACAddress matchSrcMac = flowEntry.flowEntryMatch().srcMac();
1702 if (matchSrcMac != null) {
1703 match.setDataLayerSource(matchSrcMac.toString());
1704 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1705 }
1706 MACAddress matchDstMac = flowEntry.flowEntryMatch().dstMac();
1707 if (matchDstMac != null) {
1708 match.setDataLayerDestination(matchDstMac.toString());
1709 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1710 }
1711
1712 //
1713 // Fetch the actions
1714 //
1715 // TODO: For now we support only the "OUTPUT" actions.
1716 //
1717 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1718 List<OFAction> actions = new ArrayList<OFAction>();
1719 ArrayList<FlowEntryAction> flowEntryActions =
1720 flowEntry.flowEntryActions();
1721 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1722 FlowEntryAction.ActionOutput actionOutput =
1723 flowEntryAction.actionOutput();
1724 if (actionOutput != null) {
1725 short actionOutputPort = actionOutput.port().value();
1726 OFActionOutput action = new OFActionOutput();
1727 // XXX: The max length is hard-coded for now
1728 action.setMaxLength((short)0xffff);
1729 action.setPort(actionOutputPort);
1730 actions.add(action);
1731 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1732 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1733 fm.setOutPort(actionOutputPort);
1734 }
1735 }
1736 }
1737
1738 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1739 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1740 .setPriority(PRIORITY_DEFAULT)
1741 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1742 .setCookie(cookie)
1743 .setCommand(flowModCommand)
1744 .setMatch(match)
1745 .setActions(actions)
1746 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1747
1748 //
1749 // TODO: Set the following flag
1750 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1751 // See method ForwardingBase::pushRoute()
1752 //
1753
1754 //
1755 // Write the message to the switch
1756 //
1757 try {
1758 messageDamper.write(mySwitch, fm, null);
1759 mySwitch.flush();
1760 } catch (IOException e) {
1761 log.error("Failure writing flow mod from network map", e);
1762 return false;
1763 }
1764 return true;
1765 }
1766
1767 /**
1768 * Remove a Flow Entry from a switch.
1769 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001770 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001771 * @param flowEntry the flow entry to remove.
1772 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001773 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001774 @Override
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001775 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001776 //
1777 // The installFlowEntry() method implements both installation
1778 // and removal of flow entries.
1779 //
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001780 return (installFlowEntry(mySwitch, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001781 }
1782
1783 /**
1784 * Install a Flow Entry on a remote controller.
1785 *
1786 * TODO: We need it now: Jono
1787 * - For now it will make a REST call to the remote controller.
1788 * - Internally, it needs to know the name of the remote controller.
1789 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001790 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001791 * @return true on success, otherwise false.
1792 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001793 @Override
1794 public boolean installRemoteFlowEntry(FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001795 // TODO: We need it now: Jono
1796 // - For now it will make a REST call to the remote controller.
1797 // - Internally, it needs to know the name of the remote controller.
1798 return true;
1799 }
1800
1801 /**
1802 * Remove a flow entry on a remote controller.
1803 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001804 * @param flowEntry the flow entry to remove.
1805 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001806 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001807 @Override
1808 public boolean removeRemoteFlowEntry(FlowEntry flowEntry) {
1809 //
1810 // The installRemoteFlowEntry() method implements both installation
1811 // and removal of flow entries.
1812 //
1813 return (installRemoteFlowEntry(flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001814 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001815}